From 9dbd71c41fc6894f4d416ee3e37bf3a9ce23c102 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 30 May 2026 18:14:37 +0200 Subject: [PATCH 01/94] Squash everything because testbot wants me to rebase # Conflicts: # Server/src/main/core/game/world/map/Location.kt # Server/src/main/core/game/world/map/RegionManager.kt --- .gitlab-ci.yml | 2 +- Server/data/ObjectParser.xml | 27 - Server/data/botdata/botnames.txt | 2589 +------------ Server/data/configs/object_overrides.json | 165 + Server/pom.xml | 1 + .../activity/shootingstar/ShootingStar.kt | 10 +- .../shootingstar/ShootingStarPlugin.kt | 7 +- .../ame/events/evilchicken/EvilChickenNPC.kt | 19 +- .../global/ame/events/maze/MazeInterface.kt | 67 +- .../ame/events/rivertroll/RiverTrollRENPC.kt | 8 +- .../ame/events/rockgolem/RockGolemRENPC.kt | 8 +- .../global/ame/events/shade/ShadeRENPC.kt | 8 +- .../ame/events/treespirit/TreeSpiritRENPC.kt | 8 +- .../global/ame/events/zombie/ZombieRENPC.kt | 8 +- .../main/content/global/bots/Adventurer.kt | 5 +- .../content/global/bots/CannonballSmelter.kt | 4 +- .../main/content/global/bots/DoublingMoney.kt | 11 +- .../special/ChainhitSpecialHandler.java | 6 +- .../special/ChinchompaSwingHandler.java | 17 +- .../special/PowerstabSpecialHandler.java | 4 +- .../special/SpearWallSpecialHandler.java | 4 +- .../special/SweepSpecialHandler.java | 7 +- .../item/withitem/SoftclayPlugin.java | 100 +- .../item/withobject/WaterSourceListener.kt | 24 +- .../global/handlers/scenery/TableListener.kt | 2 +- .../agility/brimhaven/BrimhavenArena.java | 549 +-- .../skill/construction/BuildRoomDialogue.java | 2 +- .../skill/construction/BuildingUtils.java | 29 +- .../skill/construction/HouseManager.java | 44 +- .../skill/construction/HousingStyle.java | 96 +- .../global/skill/construction/Room.java | 56 +- .../skill/construction/RoomProperties.java | 2 +- .../decoration/StaircasePlugin.java | 78 +- .../npc/HouseServantDialogue.java | 2 +- .../crafting/spinning/SpinningPulse.java | 146 +- .../skill/firemaking/FireMakingPulse.java | 2 +- .../gather/woodcutting/WoodcuttingListener.kt | 12 +- .../woodcutting/WoodcuttingSkillPulse.java | 423 ++- .../skill/hunter/implings/ImplingData.kt | 2 +- .../global/skill/magic/lunar/HealSpell.java | 7 +- .../skill/magic/lunar/LunarListeners.kt | 24 +- .../skill/magic/lunar/StatBoostSpell.java | 21 +- .../skill/magic/lunar/StatRestoreSpell.java | 41 +- .../summoning/familiar/ForgeRegentNPC.java | 4 +- .../familiar/GiantChinchompaNPC.java | 2 +- .../skill/summoning/familiar/PyreLordNPC.java | 2 +- .../summoning/familiar/SmokeDevilNPC.java | 2 +- .../summoning/familiar/SpiritTzKihNPC.java | 2 +- .../summoning/pet/KittenInteractDialogue.java | 2 +- .../skill/thieving/StallThiefPulse.java | 10 +- .../barrows/BarrowsActivityPlugin.java | 80 +- .../minigame/mta/TelekineticGrabSpell.java | 41 +- .../minigame/pestcontrol/PCObjectHandler.java | 9 +- .../minigame/pestcontrol/PCPortalNPC.java | 13 +- .../PestControlActivityPlugin.java | 76 +- .../pestcontrol/PestControlSession.java | 38 +- .../minigame/pestcontrol/SquireDialogue.java | 2 +- .../minigame/pestcontrol/VoidSealPlugin.java | 4 +- .../minigame/pestcontrol/bots/CombatState.kt | 4 +- .../bots/CombatStateIntermediate.kt | 4 +- .../pestcontrol/monsters/PCRavagerNPC.java | 10 +- .../pestcontrol/monsters/PCSpinnerNPC.java | 5 +- .../pestcontrol/monsters/PCSplatterNPC.java | 12 +- .../minigame/puropuro/ImpDefenderBehavior.kt | 3 +- .../sorceress/SorceressElementalNPC.java | 17 +- .../minigame/vinesweeper/Vinesweeper.kt | 36 +- .../vinesweeper/VinesweeperDialogues.kt | 2 + .../burthorpe/handlers/BurthorpeTrainNPC.java | 4 +- .../handlers/wguild/dummy/DummyRoom.java | 10 +- .../falador/diary/FaladorAchievementDiary.kt | 6 +- .../falador/handlers/GiantMoleNPC.java | 1 + .../FortressGuardDialogue.java | 2 +- .../handlers/GoblinVillageNPC.java | 2 +- .../GoblinVillagePopulationListener.kt | 4 +- .../handlers/WineOfZamorakInteraction.kt | 2 +- .../dialogue/PetshopOwnerTaverly.java | 2 +- .../quest/witchshouse/NoraTHaggNPC.java | 210 +- .../witchshouse/WitchsExperimentNPC.java | 268 +- .../handlers/gwd/GWDGraardorSwingHandler.java | 4 +- .../handlers/gwd/GWDKreeArraSwingHandler.java | 4 +- .../handlers/gwd/GWDZilyanaSwingHandler.java | 4 +- .../trollheim/handlers/gwd/GodWarsNPC.java | 10 +- .../alkharid/handlers/AlKharidWarriorNPC.kt | 2 +- .../princealirescue/LadyKeliDialogue.java | 2 +- .../desert/bandits/handlers/BanditNPC.kt | 5 +- .../bedabin/handlers/BedabinPlugin.java | 2 +- .../desert/handlers/KalphiteQueenNPC.java | 7 +- .../handlers/KhardianInteractionPlugin.java | 2 +- .../quest/thetouristrap/AnaDialogue.java | 2 +- .../thetouristrap/DesertGuardDialogue.java | 5 +- .../thetouristrap/TouristTrapPlugin.java | 3298 ++++++++--------- .../diary/FremennikAchievementDiary.kt | 10 +- .../TFTInteractionListeners.kt | 23 +- .../waterbirth/handlers/DagannothKingNPC.java | 3 +- .../handlers/WaterBirthDungeonZone.java | 13 +- .../ardougne/dialogue/SilkMerchantPlugin.java | 2 +- .../quest/hazeelcult/AlomoneDialogue.kt | 10 +- .../mourners/MournerKidnapDialogue.kt | 4 +- .../feldip/quest/chompybird/BloatedToadNPC.kt | 2 +- .../quest/dwarfcannon/dmc/DMCHandler.java | 27 +- .../diary/SeersVillageAchievementDiary.kt | 8 +- .../seers/handlers/RangingGuildPlugin.java | 2326 ++++++------ .../karamja/diary/KaramjaAchievementDiary.kt | 4 +- .../handlers/TzhaarFightPitsPlugin.java | 31 +- .../draynor/dialogue/DraynorBankGuard.java | 5 +- .../draynor/handlers/DBRCutscenePlugin.java | 896 ----- .../draynor/handlers/DBRCutscenePlugin.kt | 564 +++ .../draynor/handlers/DraynorManorChairNPC.kt | 3 +- .../draynor/handlers/DraynorManorHouseZone.kt | 4 +- .../draynor/handlers/DraynorTreeNPC.java | 5 +- .../diary/LumbridgeAchivementDiary.kt | 16 +- .../varrock/diary/VarrockAchivementDiary.kt | 8 +- .../varrock/handlers/StrayDogNPC.java | 5 +- .../dragonslayer/DragonSlayerPlugin.java | 36 +- .../quest/familycrest/ChronozonCaveZone.kt | 2 +- .../shieldofarrav/ShieldArravPlugin.java | 2 +- .../rcguild/RuneCraftingGuildObjects.java | 44 - .../morytania/handlers/MortMyreGhastNPC.kt | 5 +- .../handlers/CorporealBeastNPC.java | 7 +- .../handlers/DarkEnergyCoreNPC.java | 6 +- .../handlers/WildernessObeliskPlugin.java | 14 +- .../handlers/revenants/RevenantNPC.java | 5 +- Server/src/main/core/ServerConstants.kt | 2 +- Server/src/main/core/api/ContentAPI.kt | 15 +- .../regionspec/contracts/FillChunkContract.kt | 9 +- .../core/game/activity/ActivityPlugin.java | 3 +- .../core/game/activity/CutscenePlugin.java | 9 +- Server/src/main/core/game/bots/AIPlayer.java | 13 +- Server/src/main/core/game/bots/PvMBots.java | 204 +- Server/src/main/core/game/bots/ScriptAPI.kt | 46 +- .../game/global/action/DoorActionHandler.java | 15 +- .../core/game/interaction/MovementPulse.java | 276 +- .../main/core/game/node/entity/Entity.java | 86 +- .../game/node/entity/combat/CombatPulse.kt | 3 +- .../node/entity/combat/CombatSwingHandler.kt | 2 - .../node/entity/combat/spell/CombatSpell.java | 37 +- .../game/node/entity/impl/ForceMovement.java | 44 +- .../game/node/entity/impl/WalkingQueue.java | 58 +- .../main/core/game/node/entity/npc/NPC.java | 62 +- .../entity/npc/agg/AggressiveBehavior.java | 3 +- .../node/entity/npc/drop/NPCDropTables.java | 7 +- .../core/game/node/entity/player/Player.java | 29 +- .../player/info/login/LoginConfiguration.java | 495 +-- .../entity/player/info/login/PlayerSaver.kt | 1 - .../node/entity/player/link/GlobalData.java | 22 - .../entity/player/link/PacketDispatch.java | 15 +- .../node/entity/player/link/emote/Emotes.java | 4 +- .../entity/player/link/prayer/Prayer.java | 9 +- .../core/game/node/entity/skill/Skills.java | 10 +- .../game/node/item/GroundItemManager.java | 20 +- .../game/node/scenery/SceneryBuilder.java | 45 +- .../rottenpotato/RottenPotatoExtraDialogue.kt | 4 +- .../command/sets/DevelopmentCommandSet.kt | 34 +- .../game/system/command/sets/FunCommandSet.kt | 8 +- .../system/command/sets/MiscCommandSet.kt | 2 +- .../system/command/sets/SpawnCommandSet.kt | 60 +- .../system/command/sets/TeleportCommandSet.kt | 63 - .../core/game/system/config/ConfigParser.kt | 10 +- .../system/config/ObjectOverrideParser.kt | 57 + .../core/game/world/map/BuildRegionChunk.java | 336 -- .../src/main/core/game/world/map/Location.kt | 17 +- .../src/main/core/game/world/map/Region.java | 325 +- .../main/core/game/world/map/RegionChunk.java | 602 ++- .../main/core/game/world/map/RegionManager.kt | 726 +--- .../main/core/game/world/map/RegionPlane.java | 444 --- .../main/core/game/world/map/Viewport.java | 155 - .../{RegionFlags.java => ChunkFlags.java} | 40 +- .../game/world/map/build/DynamicRegion.java | 169 +- .../game/world/map/build/LandscapeParser.java | 124 +- .../game/world/map/build/MapscapeParser.java | 66 +- .../core/game/world/map/zone/ZoneMonitor.java | 10 +- .../world/map/zone/impl/ModeratorZone.java | 12 +- .../map/zone/impl/MultiwayCombatZone.java | 31 +- .../game/world/objectparser/ObjectParser.java | 101 - .../core/game/world/repository/Repository.kt | 2 +- .../game/world/update/MapChunkRenderer.kt | 17 +- .../core/game/world/update/NPCRenderer.kt | 4 +- .../core/game/world/update/PlayerRenderer.kt | 5 +- .../game/world/update/flag/PlayerFlags.java | 5 +- .../randoms/SnowStormHolidayRandomNPC.kt | 2 +- .../main/core/net/packet/PacketProcessor.kt | 8 +- .../net/packet/out/BuildDynamicScene.java | 17 +- .../test/kotlin/RegionSpecificationTests.kt | 15 +- Server/src/test/kotlin/RegionTests.kt | 24 +- Server/src/test/kotlin/TestUtils.kt | 7 +- .../blastfurnace/BlastFurnaceAreaTests.kt | 2 +- .../src/test/kotlin/core/PathfinderTests.kt | 18 +- Server/worldprops/default.conf | 2 +- 188 files changed, 7097 insertions(+), 10946 deletions(-) delete mode 100644 Server/data/ObjectParser.xml create mode 100644 Server/data/configs/object_overrides.json delete mode 100644 Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.java create mode 100644 Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt delete mode 100644 Server/src/main/content/region/misthalin/wiztower/handlers/rcguild/RuneCraftingGuildObjects.java create mode 100644 Server/src/main/core/game/system/config/ObjectOverrideParser.kt delete mode 100644 Server/src/main/core/game/world/map/BuildRegionChunk.java delete mode 100644 Server/src/main/core/game/world/map/RegionPlane.java delete mode 100644 Server/src/main/core/game/world/map/Viewport.java rename Server/src/main/core/game/world/map/build/{RegionFlags.java => ChunkFlags.java} (92%) delete mode 100644 Server/src/main/core/game/world/objectparser/ObjectParser.java diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 03a4e5b25..8e7707361 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ variables: # This will suppress any download for dependencies and plugins or upload messages which would clutter the console log. # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work. - MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true -Xmx3g" + MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true -Xmx4g -Xms2g" # As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used # when running from the command line. MAVEN_CLI_OPTS: "--batch-mode --errors --fail-fast --show-version" diff --git a/Server/data/ObjectParser.xml b/Server/data/ObjectParser.xml deleted file mode 100644 index bfd1c5167..000000000 --- a/Server/data/ObjectParser.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Server/data/botdata/botnames.txt b/Server/data/botdata/botnames.txt index 22c5715a8..e16423b0c 100644 --- a/Server/data/botdata/botnames.txt +++ b/Server/data/botdata/botnames.txt @@ -1,43 +1,22 @@ --Kevo -0 S O -0 4 1 1 -0 4 7 -0 HBK 0 -0 Khan 0 -0 LM +Kevo 0 Quest Ptz 0 Undead 532 0 hits -0 s m a n -0-0000000000 -00 zarour 00 -000eggs -004 n 007 Double O 007Banshee 00eeeee58 00eeeeeHC 00oo00oo00z 010elpibexx0 -014ankh -01690 017Lucas 01Ares 01eon 01ogre -020893 024elyograG 02RS 02homestar -031 -0315 -0416347345 -054 -055027584 05miller5 05venom04 -06 59 -0600 06sz 07 Account 07 Adept @@ -50,11 +29,9 @@ 07 Officer 07 Rz 07 Sicario -07 T Bone 07 iron 07 kiero X 07 nice jake -070623 07Ashley 07Ben 07Geno @@ -66,18 +43,10 @@ 07Rockysbudy 07coco 07guthix07 -07wan -080 -0800 -0800952449 -0837 -09 -0920 09Ash 09Ashley 09Ato09 09Chris -09Dans 09Paul 09Reaper 09Rhys @@ -86,42 +55,29 @@ 09TroyScape 09milo456 09scaping -09wan -0BAMA 0Behind0You0 -0CdanC0 0G 0GCore 0Giesel42O -0IIll0llIIII -0JL 0Joker0 0KAT -0LKI 0MEGA PVM 0MG ST3PSIS -0MW2PVM 0Manbearpig0 -0MrJ 0PC 0Pwnseason 0S Iluvatar 0SFX 0Tempest0 -0WEK 0X010 0_BADASS_0 0anabanthis0 -0bD0G 0bankspace 0bby -0bby Man 0belix 0bscure0ne 0ctopus -0dds r u win 0desza -0dexy 0dyssey 0ff Task 0ffline @@ -137,8 +93,6 @@ 0im2old4this 0inke 0k -0l -0l m 0ld Mate 0leaguespace 0li @@ -162,11 +116,9 @@ 0neski 0netruememe 0niichan -0njon 0nlyClouds 0nmy 0ops -0oqs 0pSe 0pen 0pen Al @@ -177,13 +129,9 @@ 0rl 0rnstein 0rphaned -0samaBdabbin -0sc4r -0smasher0 0so 0ssimpwner 0syb -0t 0taku 0taylor 0verHyped @@ -204,35 +152,15 @@ 0xocube 0xp Fail 0xygen -1 -1 0 1 0 -1 1 4 -1 2 2 -1 337 -1 3s -1 4 11 -1 54 -1 9 7 -1 A M O R -1 A N D 1 1 Account -1 Corin 6 9 -1 DC -1 Flicki Boi 1 Free Ryde 1 Ham 1 K0 Is Back 1 Line 1 Lion Tell -1 P P 1 1 Percent -1 Waffle 1 and only -1 is ln of e -1 kc 1 pet -1 parhaista -1 s t Blood -1-800DILLDOE +1st Blood 1-GrayStone 10 Four 100 Duke @@ -241,57 +169,26 @@ 1000 Ways 10000Fists 1000PingOnly -100Cl 100Grabb -100g 100kyews 100m gp 100xcoin -101000101010 -1017Trev -101e 101evil101 101rootbeer -104512 -105 -107M -1085 -1099s -10Hz -10R80 -10b -10cc -10lachs 10mm mafia 10th Reaper 10v10 10v10v 10v10v10v 10x Brew -1101953119 -1111 -11111111111d 111fishkite1 112OceanAve -116 -116 123 -1183kenny -118s 11inchlimp -11l1 -12 -12 49 12 XP 12 hours -120u -1212ajs2 123 Zeus -123456205 123Four 123bear5 -123tseemijni -1272172 -1288 12bar 12bar_ty 12blackeagle @@ -299,24 +196,6 @@ 12earlycob 12in 12millionGP -12oss -12oz -12th -13 37 -13 Daas -1300 -130SS -130rk -1312AFCA -1313 -131kg -1337 af -1337Trevor -1350 -138hans -13D -13LACK0N3 -13O 13alerion 13ayek 13ehh @@ -328,98 +207,44 @@ 13purecs 13ruce 13th Witness -14 wides -1400 -14060M -144 -1441 -144forever -1453 FSM -149122089147 -14Fre-e -14GT -14Words 15 min Break 150 kilos 1520sedgwick 15b name -15mg -16 Fly Tell +16 FlyTell 16 Fps -1602 16bumpysnow -16lB -16le -17 76 -170 IQ -17222 -1780 -17Kc -17_FLHXS 17rune2277 18 Or Older 18 Points 18 girlll -18-06-2022 x -1800BetsOff -1802M -180555 -181 -1817 -1827 -1845 -184910381412 -187 -187 781 -1877 187PIGMORGUE 187er -1889 18cast1935 -18hr 18killz -18s 19 KAPLAN 05 -19088ml -1942 -1948 -199 -1992 -1994 -19O7 19edgebee 19puxx -1AB 1After909 1Alfa -1Ali1Plane -1BGP -1Bio 1Buck1Love -1C2R 1C3 W4RR10R 1CuteBot -1Fbs -1G1D 1GramIronMan 1Hit2Lum 1Hunnid -1I1I1IIll1l 1InchWalrus 1Iron Reborn 1Kyle 1Lank 1ManGangBang 1Mayze -1NANO -1NU 1Nikolai 1Nut Dude 1O1Barz 1Ogp 1P Game 1Parthannax2 -1RlE 1ST KC 1Shadow9Fist 1Shark @@ -431,7 +256,6 @@ 1TickShit 1Unforgiven8 1_BLEED_BLUE -1ars 1badprogram 1bankingnoob 1blackhawk17 @@ -450,8 +274,6 @@ 1imp1jar 1isa 1itemtbow -1jbone -1john 1k no zik 1kDuramax 1kMaster QXD @@ -469,11 +291,9 @@ 1nVaSioN 1ndy 1ne life -1nfiniti 1nsane str5 1nv1s 1nvercargill -1o 8 1ocation 1please 1powerhydra @@ -484,46 +304,31 @@ 1st ed mint 1st son 1stHCwasPKED -1stlrfan 1stnoob7 1t8w 1tapaturma 1tickspecwep 1trueMortyy 1ucif3ro -1v1d a sedan 1w1lll0se 1wayEscape -1wwdwd2e21ed 1yfe -1zet -2 0 1 4 2 1Savage -2 2 7 7 -2 2 8 9 -2 3 7 5 -2 9 2 Big tities -2 Brothers 2 Much Tuna -2 P A C 2 Rich 4 Dis 2 Silent 540 2 Smooth 2 ball cane 2 funny bro 2 grls 1 Jad -2 h p -2 in +2 hp 2 kups -2 lN 2 more min 20 20 vision 20 Agi irl 20 On Pump 3 -200 200 Cook -2000 2001Arwen 2006nope 2007scape @@ -536,94 +341,35 @@ 200mslay1day 2011Turmoil 2013 Rt -20130406655 -20136 2027Parzival -202o2 -204 Wootang 205alphago -208 -209th -20Four -20I0 -20JuanSavag3 -20ms -21 5 21 Average 21 Musketeer 21 Savage 2137 gp -215O -2173 -21JJ 21SavageX2C 21unit -22 69 -22 Geese -22 Gz -22 darnoc 22 -22 day fury -220mg -226559 -227 7 -2277 2277 Beast 2277 Soon TM 2277MaybeNvr -2277kg -22O5 -22X7 22btc 22harry 22mario 22whitewolf -23 x 3 232o2oo -234071973416 -23463564 -235iii6i666i -2376Total -2376ed -23847239571 -23CD -23I 23coalcare 24 Hour -24000 -241 -241196 -2424 -245 -247 365 -2488 -24YO -24l7 -24w -25 S 25simulator -26 th 260sheepdog -265344626546 -26ll98 26pandas 26th -27 5 -27 M -271MPN -27ml -2841280 28BagsOfSalt 28goldpieces -290x -29384652 -2996 29Pons30 29enchant821 29robdead 2B Nier 2Broke4Coke -2C-T-2 -2D E F2 2D pantsut 2Edgy4Meme 2Far @@ -634,21 +380,11 @@ 2Goblins1Jug 2Guys1Wyvern 2Guys1dds -2I40 2InchLift 2InchPnisher -2JZ GTE -2JZ Soup -2JZ-GTE Mk4 2Jerry 2Lit -2M0X1 -2MIN -2Men 2MinNoodles -2O xp -2O07 -2OO7 2QC 2Rare2Die 2Secs @@ -675,14 +411,12 @@ 2girls1Tbow 2girls1bed 2girls1troll -2girlz1jbird 2gurls1tick 2h ur azzzzz 2hopp 2hot2touch 2hot2touch2 2hs -2id 2kav 2late2team 2logx @@ -696,120 +430,61 @@ 2pacs 2plush 2sm0keyyyyyy -2steps -2th7 2tickin 2tti -2two77 -2uBz -2ual -2ugi 2woke -2x92is99 -2ze 2zick1zussy -3 Hit V -3 5 P -3 50 -3 77 3 Moons -3 S I X E S +3 SIXES 3 SwordStyle -3 T C -3 arcanes ty +3 arcanes 3 me0 3-age 30 yo b00mer 300m MPS -3019 -30FF 30SHOTFOCUS -30XY 30thNovember -30zl -311s -3155 -315lbs 315squatreps -3160 316Austin 32 kay -320m 33 Dust Cat -335K -33jf -33zero2 -3400 -341all -34241245321 -345138 -34HL6432G6L2 -34T -34rj394thgro -351329 35ankoumoon 35cm bicep 360 Labels 360backhand 365 day 369x -36ACT 36answersay -379 -37Kg -37kg -381N 38CoolestMan 38drivelift 39 PETS 3BigDoobie 3D AnimeTits 3D Dorito -3E8 -3G -3III -3L1QZaD 3LetterName 3Miller3 3TicYaMum 3TickEat 3Ticks 3WordName -3a B0ng -3aly -3amf 3arbeed 3ash 3awe -3b 3bay -3bobyshmurda -3d age boots -3d354 -3dderino 3erzerk 3h scimitar -3ibal0e9 3inchsoft -3ioc 3iron5u -3km 3lPatron 3lack 3litz 3lilbirbs -3lit3 3liteSupreme 3lven 3lyrie 3lys -3niZ -3nosedmonkey -3nps -3oh5 3pic 3ragesave 3rd Age Ryan -3rd Age THC 3rd Age Toes 3rd Age Wife 3rd Hunter @@ -819,38 +494,21 @@ 3rdAgeHunt 3rdAgeSlayer 3rdMistake -3sd -3sl +3d age boots 3stripe -3uck -3uzi -3verD3ad 3vil 3vil Giraffe 3vil Lawyer -3we 3x3i 3xDestroyer 3xtra-1arge 3yes -3zR -3zi 4 Bros Info 4 Man Nex 4 inch demon 4 inches now -40 IQ -400L -400s -403 b -40699 Crabs -40Atk -40ms -40oz -412087542131 413 JokeR 416MiIf Jade -41O 42 Mime 2462 42 Reasons 42 skankhunt @@ -868,27 +526,11 @@ 420licious 420michael13 420tarmslyng -42342343342 42Def -42O42O -42nd 432andone 43technetium -44 bot -4400 -44444444444 45 fail -4500c -4564 -457 45smith2345 -478k -47an -47th -48H -48hour -49 r -492117837813 49forcerage 4ALLYaYa03 4D Entity @@ -899,8 +541,6 @@ 4K MrKrabs 4KT Youngboy 4Kath -4L O K O -4LDO 4LeafCIover 4Lt Goon Bag 4MoistScoops @@ -915,15 +555,12 @@ 4are 4asphalt4 4biddin3 -4cof -4dan2 4dapigs 4dosemonster 4ever 4everdry 4got2pull0ut 4gottenvoid -4hQ 4hit pl0x 4holyhydra 4iend @@ -937,63 +574,32 @@ 4rKsTon3 4sen 4th lesson -4th8 -4the 4themininoob 4thunderbolt 4ur Elise -4werty4 -5 56 -5 Nine -5 Oh -5 mil -5 ms 5-Bet Fold 50 DKP Minus 500 BJ -5000men4 -505 50Dkp_Minus 50TintenUwMa 50bitsnka -510 51Highlander 51xp 528racklover -5304 530pm 53R10U5 53m0g 54 Slayer -548 -55mg -562 -5639 -56667 -56771910 -56O -570215 -5771 57tallfred 57wraith2076 -5876 -58th -59OG 5ADx 5Aces -5BY5 5G fries 5GCovidTower 5H4NKS 5IRLOIN -5Id3Track -5M3H -5M9SNH31KAOI -5NAX -5OP 5Orudis5 5UBLlME -5a9 5alood 5alve 5ammito @@ -1001,69 +607,28 @@ 5eekingdeath 5eizures 5g Internet -5gum 5harp5hoota -5hauny -5hayWh1te 5head 5inch Floppy -5is -5j5 5kc Zulrah -5l9 -5lNS 5lap 5nis 5parrow 5quid -5st -5t h 5th Blessing 5th hcim LUL -5trm -5wan 5wattia -5x3 -5xr2 -6 57 6 9buttholes 6 Donuts 6 Drive Fox -6 Foot 5 -6 I X GOD -6 M 6 Mil 6 Qp -600 Years -605 -60min is 1hr -617 -61V -6264 -629fm 62steeplist -6384 -647 -64DD -64th -6535 -6620 -666 317 -666 J -666 is leet -666Ds -666Duuvel666 666drkwizard 66Cute 66sick -675 -67M -67jj6j7 68 savage -6822ii 68pickleman -69 L OR D 69 -6942O 69KolaOlli73 69Skrrt420 69bbygurl @@ -1072,17 +637,10 @@ 6ESkarmory 6LACKY 6PaperJoint -6R6 6T9sofine -6TMG 6Tilbud -6UGG 6cansOfBeer 6cythe -6dr3w9 -6e -6enny -6ess 6et Schwifty 6h Logout 6in9 @@ -1090,72 +648,25 @@ 6ixty 6ixx 6jadkiller -6km 6lb brownie -6mat -6ong -6p8o6 6pathsofpein -6qp 6shooter 6uapo -6uh 6utt9lug -6y6y6y2 -7 7 MAFIA -7 Curry 7 DeadlySins -7 Fat Drake -7 Of Nine -7 Trouts -7 pets chimp -7 seconds -7042 70Point1 lol 70rangeboy -70to120 -710 710 710 -716 -718m -71rc -72005sc -73 and Kree -734590325839 -737 73Head 73HoundKey -73gp -742617OOOO27 74ChaosLTUU 75 IQ -76frozen44 -76ms -7738 777slayer777 -77Dunamis77 77Stingray -77ms -782 -784162 79giantfoot -7AYL0R -7D9 7Esconar7 7Ethereal -7F9 -7GB -7God -7H3 -7J4FXEL7YFW5 -7Lazy7 -7RAC -7T -7TF 7Vick 7Viggie -7ZP -7abibi -7amowdahli 7aq 7asty 7ate9 @@ -1165,20 +676,13 @@ 7ckng Mad 7claudia7 7crypto7 -7emo -7emp 7emptest 7fisherdog 7havage -7min -7mins -7mni -7om 7ourney 7out 7rad3 7raphouse -7rev 7ridley 7scaryfire 7th Chamber @@ -1186,104 +690,45 @@ 7uP joAo 7wizard10 7xshadowx7 -8 1 O -8 3B -8 Sue Build -8 alien 8 -8 bit bling -8 oh 8 8008tator 808Southside 80leavefox 82 Sue Say -8282 831pride -832arba -8485 -849 84Bandit -85 N -8502 -852K -858 -85U -85dakota85 -88 Odd Wand -8800 -8885 -88gg -89devoid1329 8ASS 8BootRaw6220 -8ElMandinga8 -8J8 -8O8O8O8O8O8O 8ass 8balknowsall 8balled 8eauty 8h of sleep 8ind -8l0wm3 -8lackMamba24 8loodrune 8lue Phat 8owser 8qxkf02v 8tail 8uD -8yrs -9 9 Problems -9 B 0 -9 DUIS -9 Tick Brain -9 mb +99 Problems 900mexp 901Grizzlies -90804 -9092514 90tegguy -91 91 Tin Idea 911_Nate -91414 91CAL 91flip 92 way there 920 Bdops -9227 -9297 -92t 92times2is99 -94 xp 94AR BTW 95EliasAw -95LH -95p7 96 WINDSTAR -9687 96fastfrog -97DEF 97ccman97 -97fsh -98 BEDARD -98 Civic -982 -98Bn 98max1 -99 Doobies -99 Grill -99 Grinding -99 Mage -99 Rats -99 StaKe LvL -99 Steeze -99 oz -99 rwt 991atatime -9991499 99BnkStnding -99Juuling 99Lives 99S2HP 99Scents @@ -1294,40 +739,24 @@ 99_Maxed 99bottin 99charming -99hh 99moretimes -99ox 99problems4 -99ss 99sweatlvl -99wc500m 9Bar 9Barr -9CX 9D9Skillzz 9Dimensional 9GAG Reflex -9JR 9KL00AZIIZ9K -9O 9 9PetsSoFar -9T3 9TY9_Sailing -9UNIT 9cansRavioli -9ieman 9inchStepBro -9mm ko 9mmlesah -9ne -9ond 9till5slave 9ussy 9yearoldpops A 2 The Aron -A 3 -A 45 -A 7 F O L D A Articuno A Bad IGN A Bad Meme @@ -1346,15 +775,12 @@ A Cityzen A Claptrap A Classy Boy A Crazy Cook -A Crisp Sock -A Curry A Cute Snail A Dreamer A Drunk Beer -A Du Ma A F K Scape A F KING -A F M Scape +A F Scape A Fat Deer A Fat Pike A Fat Swede @@ -1364,20 +790,10 @@ A Godsword A H Fire A Half Fool A Hofasho -A I D E N -A I I e n -A II D A Iron Yoshi -A J -A JJug A Jack O Lit A Jug A Kimura -A L 3 X -A L C A P WN -A L E K S -A L I S H A -A L T A Lava Lamp A LifeTime A Lilypad @@ -1407,8 +823,6 @@ A Pot Head A Psy A Quest God A Quickie -A R H -A R Z A Raccoon A Random 4nr A Real Bamf @@ -1437,64 +851,44 @@ A Wise Sloth A X Y S A Yang A Yep -A Zee -A Zeer A Zoo Keeper -A Zuk -A Zuzakini A aron A bit north A broke 126 A capybara A cclimation -A d e b y +A deby A dam A damm A dammmm -A e d o -A e s i r +A edo +A esir A f r a i d -A gg -A lba -A ll F A llan A llstar A ltar A m a nd a A n d re -A nz A rdy A rmin A rmoa A rrow A stoner guy -A to teh Jay -A ug A y s a A z k e n A z t e r A-Chronic A-F-Kaveman -A123 A13X -A15 A1KMAN A1nz00alGown A1rhook -A2 -A22Y A47 Soldier -A543 -A7MED -A84 -AAA GG AAAAAFK AAAAAddy AAIGHT AAsamba AB Dash -AB84 -ABEC ABG Huntr ABILITEETTI ABearCat @@ -1502,8 +896,6 @@ ABlazys97 ABlueShirt AC Dicing AC TEMP IQ -AC0T -ACDC ACatGirl uwu AColdBeer AComp @@ -1540,11 +932,8 @@ AFKspiracy AFTW AFX64 AFrickinLion -AGIT8 -AGP3 AGRONOMlST AGSpec -AGWA AGlassOfH2O AGorski AH Energy @@ -1556,7 +945,6 @@ AHarmlesKitn AHlager AHriMTaLeZ AI Fighter -AI0 AII 99 AIchemyz AIecko @@ -1566,26 +954,14 @@ AIixs AIlByMyself AIm23ARDesti AIways sm1le -AJ R -AJ Skills -AJ4J -AJTracey -AJ_24 -AJisHere93 -AJsk AK Alpha AK Sam -AK47 -AK4LF -AK5C AKI-47 AKK1E -AKM AKSpring AKinkyMonkey AL-Trojans AL3CX -AL7 ALBlNO ALEXppresso ALLCAPS @@ -1602,18 +978,14 @@ ALonelyKurt ALonelySpoon ALonelyTaco ALv3Magikarp -AMAWM AMC Millions -AMD352 AMDOSRSIRON2 AMGS65 AMRSY -AMST AN07HER AN0NYM0OOOUS AN1MAL1ST1SK ANDERDAPLUG -ANDR3 ANDREVVTATE ANDROlD 18 ANGL0 SAX0N @@ -1630,14 +1002,8 @@ AOT GOAT APC L000000L APTZ27 APrince -AQ COCUGU -AQMD -AQUAMARROCKZ -AR Brah AR Fifteen AR15ONA -AR1F -AR53 ARCANO RS ARCHER ARCHIT3CTS @@ -1670,7 +1036,6 @@ ATastyPastry ATurboVirgin AU6URY AUD1O -AURl AUSLANDER AUSTlN AUTOart @@ -1689,8 +1054,6 @@ AXL gun ROSE AYRI DMM AZER AZNPanda -A_G_4 -A_Wuh AaaBiiCee Aaalmost Aadalyn @@ -1712,35 +1075,12 @@ Aaron Btw Aaron Quiz Aaron Samuel Aaron11700 -AaronJMLP AaronPVM -Aarsworm -Aarti -Aary -Aaryn -AashUnce Aastradsen AatroxLife Aauburn AavikonGaara -Aayraz -AbInito -Abaay -Abacraumbii -Abaiz -Abaker -Abaqus Abariel -Abbas Elect -Abbey -Abbey Ruins -Abbo baker -Abbyscimmy -Abc easy as -Abdallah6 -Abdirahman -Abe lnnkon -Abe numse AbeTheHobo Abengers Abernasty @@ -1748,7 +1088,6 @@ AbiChillii Abide Abido Abigayyl -Abismaalinen Abito Abiuro Ablazin @@ -1796,11 +1135,6 @@ Abstractable AbsurdGreek Absurdly Gay Absynthial -Abu Chungus -Abu Salih -Abuk -Abulssoni -Abuv Abyission AbysmalGrind Abyss Laps @@ -1850,7 +1184,6 @@ Aces Aces x3 Acesuke Acesupersoak -Acetazolamid Acha9 Achaeos Ache @@ -1862,7 +1195,6 @@ Achilles Low Achilles XXI AchillesFist Acholight -Achuu11 Acid Acid Cat420 Acid Christ @@ -1877,9 +1209,7 @@ AcidHouse Acide Acidic Acidylia -Acir Ack Varmland -Acke AckeSSBM Ackman67 Acko @@ -2071,11 +1401,6 @@ Aeugh Aev Aeyriex Aezolix -Aff it -Affaires -Affan Khan -Affect -Affectie Affidra Affinivax Affirmed @@ -2101,26 +1426,6 @@ Afkin Afkoelen Afkstar Afkwarrio6 -Aflamed -Afnacho1 -Afonso -Afperser -Afrecan -AfricaSavior -Africagamer1 -AfricanMelon -Afrie -Afrikka -Afriquee -Afro -Afro Deagle -AfroFishh -AfroShay -Afrojofe -Afroman -Afromann -Afromouse87 -Afrothunder Aft3rmath After Dark After3Scoops @@ -2204,10 +1509,6 @@ Ahriah Ahrim Job420 Ahrou Ahvexx -Ai Haibara -Ai activated -Ai u -AiMienOortje AiNebesvaik AiXiao Aiai8 @@ -2255,11 +1556,6 @@ Airstone Airstrike Airstrikes Airwalk -Airwipp -Aishi owo -Aisyah -Aivery -Aiwe Aixaa Aixleft Aiyaaaa @@ -2267,21 +1563,6 @@ Aiyzer Aizor Aizzz Aj Blitz -Ajamian -Ajarn -Ajaxius -Ajdj -Ajeh -Ajeti -Ajikk -Ajinz -Ajt141 -Ajushox -Ajuus -Ajx -Ak 4854 -Ak5u -Aka God AkaSpecs Akadian Akagi @@ -2292,13 +1573,6 @@ AkaseAkari Akasha Akashy Akatsuki -Akaza -Akduman -Akeno -Akhasa -Akhavan -Akhotha -Akiha Akihiko Main Akilled Akimbo Gmaul @@ -2332,17 +1606,6 @@ Akustic Akvarij Akyba Akyle -Al Go Rhythm -Al e x x -Al ex G -Al-Kimiya -AlCaponee -AlFromOhio -AlIigator -AlMusallam95 -Alabandus -Alabarce -Aladfar Alak4zam Alakazoom Alakazzaror @@ -2371,9 +1634,6 @@ Albertttt AlbiBambi Albin0z Albinos10 -AlboBloodZ -Alboy -AlbusTheDood Albuun Alc1 Alcadeias @@ -2464,27 +1724,6 @@ Alexx2G Alexxandraa AlexxisTexas Alexzilla -Alf11 -AlfaAleksi -AlfaQ -Alfahane -Alfahanne -Alfication -Alfie 96 -Alfonga -Alfonso -AlfonsoKhan -AlfredTB -Alfrid -Alfuh -Algiebeer -Alharbi -Alhyrr -Ali Shuffle -AliThePvmer -Alibaba -Alicander -Alicc Alice Alice x AliceOMalice @@ -2498,7 +1737,6 @@ AlienVoucher Alienmage Aliens Aliii33 -Alijr AliksOh Alioman AlistarTb21 @@ -2628,21 +1866,10 @@ Alrite Alry Alsatian Alsatians -Also -Also Jack -Also Luci -Also Lucky -Also Nexxtar -Also Noexi -Also Schlak -Also kawkky -AlsoAlso AlsoRabbit Alst Alston Alt Ctrl -Alt G boys -Alt Juana Alt Redshok Alt prepot Alt3rbridg3 @@ -2698,12 +1925,6 @@ Alwin S Alxs Alyks Alysanne -Alyv -Alzad -Alzuraak -Alzz -Am eer -Am ity Am ln Danger AmCatWhatDo Ama zon @@ -2751,22 +1972,6 @@ Amend Amenity Ameno l Americlaps -AmiableDingo -Amibis -Amida -Amigeau -Amigo -Amigos -Amillie -Amin -Amir Psycho -Amis -Amitwin -Amityz -AmixBeast -Amjad -Amjar -Amka0s Amkings Amlodipinee Ammastian @@ -2852,8 +2057,6 @@ Ancientz pal Ancitif Ancona Ancow -And e -And r ew AndSo AndYetISmile Andardenn @@ -2870,7 +2073,6 @@ Andiamo98 Andipyrus Andirath Anditre -Andj Andoyen Andrade149 AndreasBL5 @@ -2957,15 +2159,6 @@ AngryNachos AngryPickle AngryScape AngryWizard -Angsti -AngusM -AnhTaDuong -Anhedoniaa -Anid -Anida Hanjab -Anidien -Anieli -Aniheyu Anim Anima Animal @@ -3131,15 +2324,7 @@ Anzie Anzied Anzu Anzypoo -AoA Jammer -AobaJohsai -Aog -Aoh -Aohc -Aohu Aoi Tetsu -Aokijahr -Aokijii AonEne Aonyx AoooA @@ -3150,16 +2335,11 @@ Aozaa Ap0logy Ap0phis Ap3x -Ap870 -ApRoMn -Apaat -Apaatje Apache Apache30 Aparlo ApartAbyss Apathetik -ApdoJ Apdomine Ape Cape Ape Dos Mil @@ -3169,7 +2349,6 @@ ApetimusPrym Apex Apex Pro Apex-scaper -ApexGT Apexflashy Apexist Apgujeong @@ -3495,14 +2674,6 @@ Arrowtower Ars Nova Arsaydar Arsenals -Arsene rar -Arsenic -ArsenicEyes -Arsenn -Arshal -Arsi -Arslen -Arson ArsonScape Arst Arstan Selmy @@ -3767,17 +2938,13 @@ Atvinnulaus Atylos Atza Au 0srs -Au 1 -Au Bar Au Barrett Au Joel Au Shooty -Au92 AuRoyce AuStarZ Aubrey Aubrey UIM -AubsG Auburn Lax Aubzzz Auclaw @@ -3800,8 +2967,6 @@ August AugustAmes Augustiner16 Augutis -Auhdy -Auja3 AuksoAlt Aulono Aumoki @@ -3828,7 +2993,6 @@ Aurtle AurumFoxfire Auryn Aus -Aus 2277 Aus Shizam AusBruto AusGram @@ -4005,9 +3169,6 @@ Ayenull Ayetg Ayfi Aylia -Aylward -Ayman -Ayo4Yayo AyoSteeze Ayoe Ayonikz @@ -4016,41 +3177,11 @@ Ayri Ayrton Aysuu Ayveros -Ayy Nakana -Ayy bae bae -Ayy q p -Ayyye -Ayyyon -Ayzo -Az PVM -Aza zel -Azad -Azad Kashmir -Azala -Azami -Azandari Azathor Azathoth26 Azathrir Azazel OSRS Azeenil -Azemu -Azerma -Azez -Azimut -Azimuthaal -Aziz -Aziz7 -Azkaton -Azken -Azkybot -Azlo -Azmataz -Aznbabe -Aznmixboy -Azom -AzorAhaiBTW -Azotize Azoxy Azpa AzraelReaper @@ -4082,69 +3213,8 @@ Azzanadraa Azzax Azzgarnia Azzz -B 0 B S -B 0 S S -B 0 U J E E -B 3R -B 58 -B A F F E Y -B A MF -B A U W S -B B Bouncy -B C 2 -B C M -B CA -B D Y -B E E G -B E R T A -B E R t I 3 -B ELA -B Gates -B Gonkeybron -B I G G L E -B I R T -B Ian -B J O R N -B L 4 N K -B L A D E Z -B L A N E -B L A Y E D -B L ANK -B L I X T -B Milesy -B Minor -B O G S -B O O T H -B O Y E A -B R A l N -B R II A N -B R l C E -B S -B SlDE -B T J -B Victor B -B W 1 -B W A K -B aylor -B aze -B ecky -B eeez -B iggles -B la z e -B las -B r a g g -B r eezy -B rads -B raes i -B ruised Lee -B u bs -B ug -B un -B utt -B w -B-0-SS-M-A-N -B-Dollaz -B-Lal +B0BS +B0SS B00 KAW KEY B00Lici0us B00MERAT3R @@ -4187,14 +3257,7 @@ B1gTTgothGF B1gd0wg B1ink B1mboBambi -B1zrme -B2AD -B2F -B2J3 B2bZeroSpecs -B2rad -B3A5T -B3CK B3NJAMOON B3NT D0ver B3TTERLUCK @@ -4202,15 +3265,6 @@ B3Y0ND B3njamima B3njamin B3nny Blanco -B46 -B4RR -B4S -B4llista -B6a -B6i -B70 -B747B -B8 H8ER BACKURBOI BACONisgd4me BADASS @@ -4229,17 +3283,12 @@ BASEDQwert BATATUNGA BATH0RY BAYLlFE -BBBBBONKA -BBGL -BBK BBKwenie BBL RIZZY BBQs BBW Pizza BBarnzeyy BBeepLettuce -BBoys Father -BCBDestroyer BCC YT BCDOJRP BCK CigButts @@ -4255,7 +3304,6 @@ BEEA BEG0N BEG0NE BEINGMAXDSUX -BELSJ BEMBOU BEST BET5 @@ -4271,7 +3319,6 @@ BIGD05 BIGDROPHUNTR BIGFERGLOAD BIGHEADSMASH -BIGJP BIGMINK BIGSITUATI0N BIKlIllIlIIE @@ -4279,14 +3326,11 @@ BILR0Y BIOATED BIRD SHlT BIRP -BIRWAAA BIS Monster BIaded BIadet BIapa BIood Prince -BJ Applegate -BJ M BJPlaysRS BKBB BKK @@ -4298,7 +3342,6 @@ BLACK DOG NI BLASE BLGesus BLICKYSTIFFI -BLOBi WRX BLOOD BLUEPIZZAMAN BLXCKPINK @@ -4308,10 +3351,6 @@ BMEUR BMooldijk BMrgn BO0MERSO0NER -BOA Liger -BOBGIGALUCKY -BOBYAHMDGECI -BOER KAMIEL BOGOBoneless BOL0CKS BOLSOONARO @@ -4329,11 +3368,8 @@ BOlNEXTDOOR BPNS Hawk BPTheIronOne BPrimitive -BR0 BRO BR00KES BR0CE -BR0ER -BR0THERS BR3AKABLE BRA71L BRACULA @@ -4345,7 +3381,6 @@ BRUTAL BRabbit25 BRlOCHE BSB Howie -BSNR BST Steve BSickler BSven-B @@ -4356,13 +3391,9 @@ BTW Beirre BTW idgaf BTW vs RNG BTWSaberlion -BTWsanta BU1MER -BUHLL -BUILD BUILD PONYS BULLlSH -BUNDHA BUNStheGOD BUR13D AL1VE BURYT0MORROW @@ -4371,33 +3402,11 @@ BUTTB0NERED BUTTCOlN BV Martyr BWheatZ -BYEq -BYOBOOZE114 -Ba1i -Ba5b0y -Ba6y -Ba77erY -Baa m -Baaaats -Baal157 -BaalZvuv Baals Baalthas Baamf Baami Baandos -Baarb Lahey -Baas -Baba -Baba Booey9 -Baba Borgar -BabaLovesKos -BabaSlaaf -BabaSleep -BabaTarzan -Babafasa -Babayaga-9 -Babayaga2121 Baberrandrid Babica Mraz Babiez @@ -4519,26 +3528,11 @@ Baekah Bag it Bag of Yay BagFryLife -Bagadigi -Bagan -Bageera -BagelSpanker -Bagels -Baggyshaw -Baghdad -Baginga -Bagis Bagokk Bags Bags n Beer Bagsnacks Bagz -BahRitTanEe4 -BahamutLimit -Bahn -Bahnzeen -Bahp -Bai Ningyang Baib Bail Jait Baileys @@ -4551,22 +3545,6 @@ BainoLad Bainz Bairac Baites -Baja Baja -Bajan -Bajart -Bajcolado -Bajela -Bajere -Bajhole -Bajista -Bajji -Bajkami -Bajsanus -Baju -Bak cornet -BakIron -Baka Mop -Baka Prase BakaOsaka BakaPho Bakazuro @@ -4604,12 +3582,7 @@ BalazinGIM Balboa Park Balbuli Bald -Bald Arab -Bald Male -Bald Shupa -Bald Sicknez Bald To Bold -Bald Wookiee Bald at 29 BaldKnees BaldMansKenn @@ -4646,36 +3619,23 @@ Balob Balontra Balou Balrogs Hell -Balthazar BL -Baltimohr -Baltimore MD Baltoth -Baltramiejus Baltzerboii Balu Balu Titan Baluk Bam Achilles Bam Grizz -Bambi0326 BambiSlayer Bamboo Bamboo James BambooPandas Bambuliuss Bamf -BamfJoe -Bamfbeav -Bamiman -Bamse -Bamztile -Banan Banefish Banerz Banio Bank Stander -Bankaiz -Banki 1 1 Banzu Bape BapeNation @@ -6146,7 +5106,6 @@ Bmoot BmwNerd BnB Bnaar -Bo Ed Bo Selecta Bo0nies BoBgss126 @@ -6171,29 +5130,15 @@ Bob44th BobBojangles BobCatMilk BobGuenille -BobNegao BobRossDied BobTheDaddy BobaNeZmogus Bobakadush BobbaStanley Bobbanxd -Bobbiie -Bobby -Bobby Brawl -Bobby JoJo -Bobby Lash7 -BobbyBigLips -BobbyBonk -BobbyShurda -BobbySmooth -Bobbyccf Bobbydrake09 -Bobbysweggg BobbyyHill -Bobi Bobicles2 -Bobidabob Bobite92 Bobo Bagins Bobrobber @@ -6604,22 +5549,16 @@ Boze Worm Boze mol BozeOog Bozut -Br ay -Br ibb -Br yan Br00dje Br0ox Br0wnSpit Br3ws Br4dders -Br4w Br5andon BraBraBrad Braaamps Brabbss Brad -Brad RS -Brad T King Brad017 BradIsAChad BradIsChad @@ -6680,7 +5619,6 @@ Brando23x Brandog Brandon Brandon 126 -Brandon TJ Brandon9250 BrandonLarge Brandonp32 @@ -6718,7 +5656,6 @@ Brazeheart Brazzerker Brb Delivery Brblol -Brdy Breaches Bread Bread Again @@ -8231,9 +7168,7 @@ Cewl Cewl Hwip Cexilius Ceyyl -Cf b4 Cfretz244 -Ch i Ch i c k en Ch ief Ch00bies @@ -10096,11 +9031,6 @@ Cvanz Cvbgn Cvrkster Cvrsn -Cw90 -Cwab -Cwazza -Cweavy -Cwer Cwick Cwioktopus Cxffee @@ -10111,7 +9041,6 @@ Cyal8rnub Cyan Cyan Ablaze Cyasoon -Cybb Cyber Mind Cyber n Bug Cyber172 @@ -10180,78 +9109,6 @@ Czechmate Czha Czivend123 Czk -D A I J I N -D A L M -D A M 0 -D A M I A N -D A M N L0L -D A N G I T -D A N N Yy -D A T H I T -D B A -D B Z pker -D Blo -D Clawz -D Darkblader -D Derbles -D Dragon124 -D Duberstein -D E C O -D E F Q 0 N -D E F Q O N -D E R P -D E V I N -D F U Q -D I Q -D I R T Y Ko -D J Diddles -D Long -D M T Elves -D O D -D O M M E L -D R 6 K E -D R l Z Z T -D Rack4 -D S A V -D Squarius -D U R K -D Wilson -D Wreck -D a mo -D a r t s -D a rk -D a u t o -D a v i d -D amz -D arking -D arkoz -D as -D ashing -D avey -D axe -D db -D ebol -D ecimate -D eej -D eek -D eep -D eez -D en -D enial -D entist -D i l a n -D i x o n -D i zz y -D iesel -D iizzy -D imi -D imitri -D onda -D onger -D oo l ey -D op e -D utchgr -D-D-A D00DLES D00dey9 D0CTOR @@ -10301,16 +9158,9 @@ D4nnyy D4rels D4rk D4rth -D7NNY -D9 -D9R DA ODB KIDZ DA0IST DA3N33RY -DA4N -DAD563884271 -DADDYS IR0N -DAHDB DARCHANG3L DARGON DASH @@ -10318,14 +9168,10 @@ DAWGPOUND DArtspret DBA Paulo DBKangaroo -DBO90 DBOL TRICEPS DBUZZ DC Flubber -DC-8-51 DCreek -DD 214 -DD G DD2I4 DDAlt DDSurWrists @@ -10341,17 +9187,12 @@ DESPA SIITTO DESPAlRGE DESTYLAT DFez -DG 00 DGAF DH Marker -DH btw DHIBZ DHSC4EVER DHally -DHlN DHoShow -DIDZZ -DIETDRDIET DINGO SCUM DIORITIC DIORITlC @@ -10380,19 +9221,9 @@ DJMileyCyrus DJMuscleBram DJOFULLIN DJSeinfeld -DKHo -DKJN -DMM 2 07 -DMM Gp Swap -DMM Ryu -DMT Dad -DMT Satan -DMTDAN -DMTe DMagnum 10 DMessengerS DN Atro -DN20 DNFL DNLD DO0FY @@ -10405,12 +9236,10 @@ DONJOHNNNY DOOMBRlNGER DOOMSlayer DOSNE -DP776 DPRNS DPS Disciple DPvM DPvM Jordan -DQ9 DR PAAAK DR VABA DRAEG0 @@ -10453,9 +9282,6 @@ Da Nils Da Puppy13 Da Sniper007 Da T Virus -Da d dy -Da t -Da then bh Da1ton DaBears DaBoz @@ -10519,9 +9345,6 @@ Dachowski Dackel Dackenerino Dacune -Dad Goals -Dad Sean -DadBurrys DadGoingMad DadLeft DadRanarrWay @@ -10529,8 +9352,6 @@ DadamoSte Dadbackward Dadbackwards Dadbod4lyfe -Daddaforce -Daddy Daddy Bundy Daddy Chaman Daddy Chubs @@ -10562,7 +9383,6 @@ Dadfield Dadi415 Dadorii Dadosaur -Dads Dadukez DadurQa Dadyankee3 @@ -10610,8 +9430,6 @@ Dahlareen Dahls Dahlson Dahmonkey -Dahrmata -Dahrr Dahumbug Daijoukay Daiju Spede @@ -10778,15 +9596,11 @@ Daniella DanielleOfc Danielmcken1 Daniels -Danielwat -Daniiieell -Danijenn1211 Danilin Danimal DanisH96 DanishAdonis DanishGoat -Danje Dank Dank Chef Dank Exp @@ -11070,14 +9884,6 @@ DavidPH Davidisiscoo Davidopathy Davis751 -Davlan -Davo -Davord -Davoron -Davros70 -Davshing -Davu -Dawaj Lama Dawg Dynasty Dawkins Dawn @@ -11120,13 +9926,7 @@ Daze DazedDave DazednConfsd Dazzler95 -Dazzz -Dbeatz -Dbewt -Dbmx -Dboot Dbricke -Dbz Pride Dc B L I N D Dc Hakkarn Dc IronMan @@ -11139,8 +9939,6 @@ Dday6Jun1944 Ddestroyer56 Ddos Dds4theko -Ddsing -Ddsme De Algerijn De Baardman De Eryngy @@ -11158,7 +9956,6 @@ De Redacteur De Sam Matie De monic De stoutsten -De us De1icioso DeAndre DeDawgTubb @@ -11170,7 +9967,6 @@ DeHijskraan DeIronMan DeIronedMan DeKawika -DeLL DeLooter DeLouuu DePope @@ -16770,20 +15566,15 @@ Fyrox Fyszz Fyzio Fziaa -G G 0 A T G A F F E R G Alfansos G Ape -G B S G Check G Fruit G GAMER GIRL G I M Danny G Iron Adam -G L E N -G L H F -G M B G Man9822 G Mauls G O O D @@ -16791,36 +15582,21 @@ G O O S E Y G R E E N G R I L L O G Terminator -G X F C G Zus G a r t y G a t t s u -G ante -G dot C G e n g a r -G eeb -G i j s G i l b o -G iG G imme -G iooo G l R L G laze -G no Z -G o G G u -G o h o -G o th i X G oldd G oldeen G oofy -G ozz G rafix G ronimo27 G root -G shi G u a m s -G unitt -G-F-M G-IronKuv G-Thug Nasty G-knowww @@ -17064,15 +15840,8 @@ GTRKingZilla GUBIDUBII GUCCI SENPAI GUCCl -GUJ0 GUNMAN683 -GURRD GUUMBY -GVSU -GYDtown -GZA -GZX -Ga l Ga7ba Gaara Gaara Sand @@ -17270,7 +16039,6 @@ Gastje888 Gastronaught Gate Gateofdoom -Gath Gato GatoNaranja Gator @@ -17297,9 +16065,7 @@ Gavy Gawd Bodi Gawk5000 Gawkes -Gawkss Gawt -Gawz Gay 4 Guthix Gay Bear Gay Bear Cub @@ -17557,23 +16323,11 @@ Geuld Gew Gewoon Gezang -Gf g Gf4tiuser GfRsIGotAGf -Gfi -Gh3t0 T4nk3r -Ghafir -Ghaipol -Ghandizy -Ghandy -Gharron -Ghckkrchkrer -Ghda -Gheed Ghentiana Gherkins Ghetto -Ghhjgwsr Ghidorah Ghillie Suit Ghilly @@ -17793,10 +16547,6 @@ Gixerikan Gizmoed Gizmoo247 Gizzy-71 -Gj nice -Gjerloew -Gjonunaki -Gktr Gl Bob Gl Im Dandy Gl Im Tom @@ -18905,36 +17655,6 @@ Gytisr9 Gyts Gyym Gz Parsec -GzBs -H 0 U N D -H 2R -H A D O -H A I D E S -H A M M E H -H A R L S -H A T -H A X 3 D -H D M P -H E A L E R -H E J S A N -H O L M E -H Q Killer -H S 7 -H U L K K -H U N A J A -H a t y -H a w n y -H abs -H alo -H ch -H e c t o r -H i n e s -H l E U -H obbs -H owl -H rekDoer -H uff -H-tsi H0B0 H0DEX H0LINESS @@ -18942,8 +17662,6 @@ H0NA H0PES H0RSEFIGHTER H0RY -H0j -H0j00 H0lyPorkyPig H0me H0nestyBe @@ -20120,7 +18838,7 @@ Hislordship HisokaX4 Hispeeed Hissi-Timo -Hit U +Hit U Hit By Car Hit Points Hit The Guam @@ -20153,7 +18871,6 @@ Hldz Hlep Hlnub Hm -Hmg Hawj Str Hmm Fr Bruh HmmKoekjes Hmmer @@ -20297,8 +19014,6 @@ Hompski Hon Honaz Honchcrow -Honda Coupes -HondaXJ20 Honden Hondo Ohnaka Hondsvot @@ -20800,9 +19515,7 @@ Hyun Hyxbe Hyze Hyzers -I M I Skilz I -I ADK I I AM DROID I Am Arun I Am Calysto @@ -20817,7 +19530,6 @@ I Am Vexed I Am Vono I Am Xyience I Am Yesac -I B Z I Barak I I Be Vibing I Be Yankin @@ -20860,12 +19572,9 @@ I Heal DHers I Herb Store I Hunt Pets I Hustle Man -I I ODIN I I I JANGLER I I Judgee Yu -I Ko U Lol 1 I L0ve Lolis -I LOTR I I LV PEACH X I Lezima I I Liam I @@ -20882,8 +19591,6 @@ I Luci I Luhhya I Luv tSwift I M A P nuss -I M Ket -I M S N Y I M The Weed I Maxed OSRS I May Be @@ -20894,10 +19601,7 @@ I Need 1M I Need Succ I Need aBeer I Novato I -I Nz I -I OX I Owning -I P0 I P0KY I I Parry I I Peter I @@ -20906,10 +19610,6 @@ I Plank Lots I Play Aegis I Pod335 I Pri -I Q T -I R N B R U -I R O N 99 -I RC I ReAPeR I I Roll Need I Ron Man @@ -20981,7 +19681,6 @@ I sak I smell zaza I so pale I squared R -I t I s I tbag cows I used to Rc I van @@ -20989,11 +19688,6 @@ I vinrox I w4ste xp I wana dew u I want wings -I-IEEBO -I-Iulk -I00OOOOOO00I -I2P -I2m I2ocky I2ossiiii I3ET @@ -21004,9 +19698,7 @@ I3ox I3rucex I3ubbles I3ulow -I7I I7iablo -IA IAM HARDWELL IAMBillNye IAMDouble_C @@ -21035,10 +19727,7 @@ IBloodwing IBuyGF5GP IBuyPowers IBuyShungite -IC 3 -IC XC NI KA ICE GIANTT -ICNK ICantFit ICauseRage ICrazyCamelI @@ -21050,12 +19739,6 @@ IDiabloI IDustie IEATEDYU IFALL3NI -IFIFIFFIFIF -IFIFIFIFFIFI -IFIFIFlFIFIF -IFRC -IFRS -IFRS 9 IFartOnBaby IFernedYou IFistBonk @@ -21074,31 +19757,19 @@ IHuntKoalas II Fabi II II Gots Piie II Mossy II -II TurMz -II0III -II0v0II IICyRaNoKII III SLAYR -III jin III -IIIBCIII IIIGavinIII IIIel0n IIIusionist -IIKOO -IIPAC IIPrincesaII II_Blanx_II IIamaman IIflemishII -IIlIIAS -IIlIIoIIlII -IIllIll -IIlllllIIlIl IIndy IIrisviel IIsaac IIx Link xII -IJzer Bal IJzermeneer IK Pegasi IKotol @@ -21188,9 +19859,7 @@ IMAEATURASSS IMAFKNNONCE2 IMGOKU1 IMHankey -IMHky IMJeffG -IMMezzo IMNagrom IMPERlO IMPlayerjohn @@ -21264,18 +19933,11 @@ ITIajestic ITIallen ITIasKilleR ITIassacre -ITIatty -ITIerica -ITIiko -ITIoj -ITIoosh -ITIr ITSPYRO ITV X IThe Beatles ITrimGlories ITurtlekunI -IUR IUntradeable IV Luke IV skin @@ -21296,8 +19958,6 @@ IVIush IVIxtthew IVOXYGEN IW Lytheria -IW4M -IWGP I_Eat_Ass04 I_Inity I_Noodz_I @@ -21494,8 +20154,6 @@ IkkleHorvick Il Il MrBorn lI IlIBooieIlI -IlIIIIlIIIlI -IlIIlIllIlII IlINard0IlI IlRisklIlIlI Ileeze @@ -21569,12 +20227,10 @@ Im Hawkward Im Hersh Im Huck Im Hunta -Im Hussain Im Iron Im Iron WTF Im Jags Im Jokers -Im Jovian Im Just Ken Im Krazy Im Kyle Btw @@ -21715,7 +20371,6 @@ ImVanilla ImWargasm ImWilbur ImYourDadBTW -ImZe ImZorp Im_Stone126 Ima Guy @@ -21792,8 +20447,6 @@ Improv Improved Impulsive Au Impurest678 -Imql -Imre Imsain Imsokwtie Imstratss @@ -22026,7 +20679,6 @@ Ionia Iono Iou689 Iowa146 -IowaCJ Ioyal Ioyins IpeeInTheSea @@ -22044,9 +20696,6 @@ Ir0nMammoth Ir0nMish Ir0nPuma Ir0nRagnarok -IrDA -Iralimir -Irha Irid Irie IrieLuDa @@ -22919,95 +21568,6 @@ Izvorul Izzy IzzyBigBoy Izzyboy300 -J 0 S H Y -J 0 S H l -J 4 6 -J 4 K E -J 6 -J A B S -J A I D A N -J A M A L -J A N K I -J A U N U S -J A W D -J Breezi -J C Trousers -J D -J D Ballew -J Dahmer -J E E V E 5 -J E T -J F -J Fred Run -J I M M -J I MM Y -J Kole -J Kribzz -J L A -J MF B -J Neat -J O E G -J O L T I K -J O T A -J O3Y -J R O C -J R V -J Rat Cow -J S 2 M -J S Z M -J Saints -J Suave -J U S T A S -J U Z -J a c k a l -J a c k son -J a c k y -J a mie -J a n i -J ackal -J al -J ameper -J anii -J appie -J asnah -J ason -J asyra -J ayson -J bellfortt -J bird shady -J e sse -J eff -J effy -J ensen -J esse -J essica -J imme -J imy -J imz -J ipr -J lMM Y -J o b e -J o e -J o ey -J o f -J o s h y -J oep -J ohannes -J ointz -J oke R -J or G -J oshh -J oshhh -J osie -J u wu -J ung -J unko -J utch -J uun -J uwu -J x B -J yy -J-2tha-R-O-C J-Man 93 J-Turn J-Yeezy @@ -23034,22 +21594,7 @@ J0seph J0shh J1MB0H J1NBE -J1ub -J2TR J2caine45 -J2ck -J328 -J3Ciron -J3JU -J3S5E -J3rkkuHD -J41AL -J45e0wns -J4QS -J4S -J4gga -J4my -J95 JAABASNABBA JACK3DJOHNNY JACKYOUNG93 @@ -23061,79 +21606,30 @@ JAVON 9-INCH JAYJ51 JAYR0CKBABY JAlDYN -JB 2K -JB87 JBGard JBrody JBuck057 JBux -JC-1989 -JCS07 -JCole -JCon -JCutler -JD MD -JD4 -JDBass -JDEP -JDFlaSh -JDJM -JDez -JDlion -JDredd66 -JDuck -JE B JEEZE JENNY JENNY DEATH JERN SVIN TO JETSNBEERS JF Kennedy -JFB -JFCK JFK gone AFK JFKautopilot -JFL JField JFrog JFryGuy JGIRONTG -JGIV -JGlen97 -JH3305 -JH91xx -JHINitalia -JIGGYWIGGY -JIIVEE94 -JJ-M -JJ23 -JJAAKKO -JJBW -JJPowers -JJROCKETS -JJRicky -JJS BBQ -JJSM_Dulker -JJchris66 -JJoe -JJumalwelho JK Rowling -JKMi -JKTimbo -JKUR ON 40S -JKeM -JKingJ777 JKrollin JKuyaa -JLG JLowe JLsone -JMI NG JMTaipei JMack JMiddd -JOBBO -JOCKO00O0O0O JOE EROTIC JOKER 709 JON3ZYY94 @@ -23149,9 +21645,6 @@ JPantless JPatness JPence JPountney -JPudz -JR05E -JR0D JRBeast JRC Crypto JROGU @@ -23167,32 +21660,12 @@ JSilvester08 JSlice94 JSplash JStepho -JT5 -JTAG -JTCS -JTI ain -JTIAIC -JTM33 -JTscape -JUGIB -JUIBE JUICEWRLD9 9 JULlAN JUST JUST A HlPPO JUST Nikk JUSTICE -JWRLD -JXJ -JZB -JZX1O0 -Ja k ey -Ja m e s -Ja mes A -Ja se -Ja sn -JaBouris -JaDig JaStraater Ja_Fireking Jaaaakkoooo @@ -23300,32 +21773,11 @@ JadsVag Jaecob JaegerBoom Jaeson -Jafacakeman -Jafanto -JafarTooHigh -Jaffa Jake -Jaffar -Jaffywaffy -Jafsx -Jagdpanther JagerBombski JagerIron Jagermeister Jagged Jaggen -Jaghatai K -Jagoodiii -Jah toch -JahIthBer -Jahaerhys -Jahaok -Jaharred -Jahbby -JahgexPlzzz -Jahmay -Jahmerica -Jahngles -JaiSiaRamJai Jaiden184 Jailbreak455 Jaime 427 @@ -23354,13 +21806,6 @@ Jakey Jakey C Jakeyosaurus Jakeyz -Jaknop -Jakrem -Jakrojan -Jakuli226 -Jal-Nib-Jmal -JalNib -Jalduii Jaleesa Jales Jalim Rabei @@ -23394,24 +21839,17 @@ James Kelp James Poncho James PvE James Rolfe -James c James osrs James1087 -James2709 -James9 -James945848 -James9520 JamesBondss JamesCUFC JamesDaWizar JamesHaliday -JamesJ2019 JamesLango JamesMaynard JamesNI JamesPratt94 JamesShotGG -James_22 Jamesay Jamesbombom Jamesrb1 @@ -23440,9 +21878,6 @@ Jamosbondos Jamppa Jampy Jampyre -Jamuli -Jamurazi -Jamwa Jamyroo531 Jamzylockz Jamzz @@ -23479,21 +21914,6 @@ Janne JannpajII JanoPotato Jansky -Jansz101 -Jante -Jantex -JantheBear -Jaooa -Japanese -Japhur -Japiohh -Japles1 -Japoolie -Jappieee -Jappieness -Jappo -Jaqen -Jaqquu Jar Of Pets Jar Uh Dirt Jar of Pukes @@ -23622,47 +22042,8 @@ Jayster Jaytea Jayteaf Jaytee1262 -Jaywub -Jayy -Jayy Slays -Jayy x -Jayzar -Jaz Coleman -Jazo -Jazpurs -Jazz -JazzFlap -JazzMaster09 -Jazzeh -Jazzjr89 -Jazzly -Jazzy -JazzyFlips -Jb Godranger -Jba123 -Jbevzzz -Jblieves88 -Jbob72 -Jbt -Jbvff -Jc_TheCops -Jcb4646 -Jcdelavici -Jchn -Jcmalone23 -Jcolts20 -Jcourt1 -Jdaws -Jdidy -Jdoggy2018 -Jdp3 -Je nny -Je pppe -JeBoyHiddema JeIlo JeIly Man -JeJoat -JeK0 Jean Jean belette Jean man @@ -23739,7 +22120,6 @@ Jelen Jelenner Jelior Jella -Jelle Jelle Bouma Jellie40 Jellisme_99 @@ -23755,12 +22135,9 @@ JellyBeanRs JellyGenix Jellydonuts Jellyfishes -Jelziin -Jelzini Jemades Jemelope Jemile -Jen na Jen0va JenaTulwarts Jenessa @@ -23826,128 +22203,6 @@ Jerry Maine JerryChinger JerryMina Jerryy -Jers -Jers Knot -Jersh -Jershawerr -Jersion -Jertz -Jeru -Jerunox -Jerusalenm -Jerziii -Jerzy -Jes2x -Jeseeka -Jesh g -Jesh-mar -JeshusChrist -Jesiah -Jesk -Jesliq -Jesper Bratt -Jesper135 -Jesperyo -Jess -Jesse -Jesse Top -Jesseq -Jessica -Jessie -Jessie Jones -Jesspresso -Jessy -JessyTrip -JessycaOSRS -Jester Head -Jesterbubba -Jesus -Jesus I love -Jesus MPhys -Jesus Saved -JesusComing -JesusRedeems -Jet Jaguar8D -Jet3010 -JetFlame -Jeththe -Jetlag -Jetma -Jetridder11 -Jetski -Jetsmoke -Jettiesimp -Jettrider -Jeugd -Jev21 -Jevel -JewFroBro -Jewbaaca -Jewbakah -Jewbang -JewishRob -Jewy -Jexlad -Jexlo -Jeyos -Jeyzuz -Jezeus -Jezkoz -Jezuux -JezzaripHD -Jezzie -Jezzx -Jf-n03 -Jfleeze -Jfrith -Jfuzzy -Jglove -Jgus88 -Jgy1889 -Jhackal -Jhb -Jhebs -Jhny -Jhonlovin -Jhoocy -Jhoocy Moot -JhormanCovid -JhosS -Jhow -Ji bs -Ji m m -Jia Lissa -Jian -Jiara -Jibajaba -Jibberflexed -Jibbllyy -JibinSui -Jibneh -JibrilMaster -Jiffee -Jig Bugs -Jiga Chad -Jiggalagg -JiggerJoe -Jiggity -Jigglyboy -Jigglywoo -Jiggypufff -Jignite -Jigoogly -Jih -Jihe -Jihne -JiiU -Jiiko -Jiim Lahey -Jiiraiiya -JikdarShark -Jikkurr -Jiklim -Jill Hyde -Jille Man Jim Jim Sauce Jim Shorts @@ -24006,9 +22261,7 @@ Jims Ironing Jimsterjim Jimver Jin Oh -Jin R n G JinDoritos -JinJ0 nJuice Jinb JingleBiloba Jingy @@ -24046,22 +22299,12 @@ Jixr Jixx0x Jiyool Jizt -Jj Dynomite -Jj Jerk2 -Jjar127 -Jjjjjj210 -Jjozzie Jk Esq Jkdogg Jkhby Jkl Kalja Jkolrur Jkrexx -Jku45 -Jl-SOO -JlGA -JlLLY -JlMMB0 JlZZB0SS Jlarge Jlova @@ -24081,27 +22324,9 @@ Jmz Jnas JnrSeneca Jnsthenx -Jnup -Jnwp -Jo Pain -Jo de Coeckh -Jo h 2 -Jo iron -Jo rd an -Jo shua -Jo we -Jo0l -Jo3 H -Jo3p -Jo5p -Jo6p -Jo711 JoE ShMoee JoEiSaFiShEr -JoJi -JoJo JoJo Skriver -JoJo79 JoJoJoUrBoat JoKerRtheGOD JoMoe @@ -24156,7 +22381,6 @@ Joee P Joeholding Joekle Joel -Joel 9444 Joel In Pain Joel Lobster JoelBtw @@ -24246,16 +22470,6 @@ Johnsters4 Johny Johny Aus JohnyLocoo -Johnyy -Johuab -Johzyn -Joizz -Jojis -Jojj -Jojkan -Jojo Rabbit -Jojora -Jojy Jok Jokar Joke @@ -24432,46 +22646,6 @@ Josh x Josh013 Josh2Godly JoshD -JoshDagainz -JoshGymnast -JoshMarksman -JoshYewAhh -Joshalog -Joshan -Joshery -Joshh -Joshhhh -Joshii -Joshimitzu -Joshism -Joshjoshin -Joshmaster31 -Joshpaul -Joshua -Joshuaaaah -JoshyCii -Josiah Higha -Josiahs -Josoust -Joss -Josse -Jostavo -Josti O_o -Jostle -Josue -Josukes -Josylvio -Jota_420 -Jote -Jothha -Jotjemenotje -Jotq -Jottini -Jotunheimar -Jotwe -Joueur4376 -Joulaha -Jovial Jovilius JovyGaming Jowah @@ -24491,21 +22665,9 @@ Jpan1 Jpellican Jpq Jqwss -Jr Metro -Jr Muffin -Jr Stigel -Jr2k13 -Jrabbat -Jrby -Jrdn Jreppks Jrey Jroanirr -Jrodjok -Jrogo -JsJays -JsN4 -Jsag Jsi7111 Jsnn Jsony @@ -24595,18 +22757,6 @@ JuicyTigr JuicyWetNut Juicy_Newfie JuiicyAF -Juikki -Juint -Juipp_Iron -Juisy -Juk e -JukeLess -Jukebot -Juked -JukeduM -Juko -Juktes -Jul es Jules Julesbak Julia @@ -24764,100 +22914,9 @@ Juun Solo Juuna Juunaz2chips Juustis -Juuzo -Juvi -Juvian -Juzzy -Jvzy -Jwad -Jwcsg -Jwd -Jwett -Jwu -JxJxV -JxcelD -Jxck -Jxcx -Jxdidiah -Jxdooo -Jxhnn -Jxke -Jxmeson -Jxnas -Jxni -Jxstxn -Jxxst -JxyStorm -Jy -Jybais -Jyeronese -Jygers -Jyhlln -Jyhy -Jype -Jyppedi1992 -Jysk -Jyura -Jyy -Jyypy -JyzzBrah -Jz -Jzbeta -K 1 L L A -K 1 P -K AMI -K B D autism -K E K E B -K E L A -K E T CHUM -K E V 0_O -K Hades -K K Boef -K NW -K O L L I -K O M P I S -K OOOOOOOOOO -K P N -K P Sweet -K Smalls -K W -K W A L A -K Y Y -K a l e w i -K a z a -K aarel -K ayyla -K eller -K elvin -K en -K etaminer -K ev -K iNG IRON -K idd -K ilo -K im -K l 9 -K l N G S -K nauss -K nut -K o j o -K o o s a -K ohen -K orruptt -K ree -K rs -K t r n e -K una -K ushi -K uz -K voth e -K y u m a -K yogre -K-Diddy K-epan K-market K0 -K0 4 K00LBR33ZE K0F K0L0S @@ -24873,7 +22932,6 @@ K0rnuit K0tleciokas K0veras K0zor -K19 K1ERZ K1LLY K1ddl3 @@ -24883,8 +22941,6 @@ K1ngo K1ngshredder K1r1t0123 K2 Jung -K32 -K38 K3KSE K3U S2 K3azkoks @@ -24892,26 +22948,18 @@ K3fka K3kt K3mi K3nn3d -K44K -K4IF20 K8iee -K99 2 -K9Father K9lenny K9rk -KA97 KABBABEAST KAKAGUATE0 KAKERANDELIN KAL-JML KAMlX KAT alyzt -KB1988 KBARAKAT KBX0 KC Chiefz -KC M0 -KC8 KCRB KChiefn KDOG1419 @@ -24938,7 +22986,6 @@ KGP KGee KGoldy KHADER -KIIIIIIIIIIH KILLER COMBO KILO KIMB0 @@ -26887,58 +24934,6 @@ KyuubiKurama Kywt Kyykin Kzyl -L 0 S T Y -L 3 G 4 C Y -L 67 -L A R A M S -L Ben -L CBO -L D A -L E G E N D -L E G O -L E L O -L E P I -L F C -L FC -L Hus -L I N U X -L I V M -L OAFS -L S Q -L U I G -L U U K E -L X R D S -L achie -L aika -L aka -L ama -L ang -L apras -L atias -L aw Rune -L aze -L e an -L eafErikson -L egs -L ek -L emaster -L ev -L i m a a -L iamm -L iar -L ilo -L inox -L ions -L o w g -L ockdown -L ofty -L osi -L paradoxum -L u m i -L u mi -L u x -L ucas -L unatic L00000 L00M L00OL0OO00OL @@ -27026,8 +25021,6 @@ LIMEWORLD LIQUICITY LITEIT LITHITS -LJ 8 -LJAP LJPalmer LKIT LL Trigger @@ -27056,10 +25049,7 @@ LOSTinGAMES LOUlSlANA LOWIQXD LP Smokie -LRG -LRGD LRichyy -LS1 LS3D LSD-25 LSDDS @@ -29076,81 +27066,6 @@ Lyyli PL Lyzu Lzin Lzs -M A G 3 -M 1 KE -M 3 3 P -M 4 T R I X -M 8 A 1 -M A D O X -M A D Storm -M A T E J -M A X O U T -M A X PAYNE -M B Z -M E H I S -M E L D O -M E T R O -M E X I -M I K B A R -M I T H O X -M I U -M I Z Z O U -M INDGAME -M Itty -M K J -M O B I L 3 -M O C 0 -M O C H -M O ID O K -M R NaCl -M Super Buu -M T C -M U D K l P -M X G P -M a V 3 Rick -M a d Shrumn -M a k a i -M age -M aikel -M ak0 -M ammoth -M ana -M ankDemes -M anu -M aples -M arcel -M arquim -M artin -M ask -M athis -M axou -M azzz -M c -M elz -M enzy -M ga -M gh -M i t c h y -M i y a -M ikasa -M ike -M imik -M int -M itchel -M ittens -M l Q Q -M merz poL9 -M o C e -M o r t e n -M oist -M onkfish -M orytania -M the Maxed -M ugger -M ulas -M urphy 2 -M usashi -M-theory M00CHIE M00SE M00SE M01 @@ -29271,55 +27186,38 @@ MCHammered MCKenny91 MCSIZZLE MCmattt -MD7 -MD96 MDE Presents MDPS -MDaher MDucks MEAT G0D MEAT HEAD36 MEGATRON -MEK4KK4KK4KK MELAN00MA MELT METM0NKEY METR0lD METS0 MEV4NS -MF DC MF MORTEN MF SofaKing MF TEE -MFE MFKU MFLI MFSTEVE -MG5 MGFS MGKRevs MGM WAY MGreengrass MH Therapist -MHA C -MHBC -MHS MIDAs MILFmauler MILSHAKE -MINH MISOGl MISSYGAMlNG MIST MITCHY MIX0R -MJ23 -MJKaboose2 -MJT MK-HARDSTYLE -MK6R -MKAM -MLB MLTEEZY MLaidman MMMahogany @@ -29332,10 +27230,6 @@ MOMHUNTER666 MON5TER MOODSWlNGS MOOSEM3AT -MOTM -MP17 -MP9 -MPB MR JOHN WlCK MR LETHAL2u MR REET @@ -29347,7 +27241,6 @@ MRC Tugboat MRGAMEZ MRHD MRLARGE -MRM MRPlZZAPRIZE MRWHlTE MR_MAITO @@ -29355,18 +27248,12 @@ MSPaint64 MSceneFF MSpacePotato MStarkz -MTBMB -MTPETE -MTV CRlBS -MTXP MUISSS911 MULHERndaEXP MUMM0 MURMELl MUSK MUSK0KA -MUSUMUMM -MUZAMMIL MV Flow MV Welshy MVIII @@ -29375,7 +27262,6 @@ MVP HERO MVP Mahomes MVRDA MVTIASD -MWwarzone MY L U N A MYRSKYVIITTA MYTHICROYXLE @@ -29383,7 +27269,6 @@ M_Sariol Ma Band Ma Dood Ma Titi -Ma t t h e w Ma5onx Ma7e MaCoMb @@ -31670,26 +29555,6 @@ MoetIkLopen Mofaer45 MoffelRS Mofleminator -Mofo Lt -Mofo Shadow -MofoMo92 -Mofoe -Mog Time xD -Mogcow -Moggok -Mogtime -Moh -Mohahm -Mohamedss -Mohanad -Mohannah -Moheed -Mohh -Mohib -Mohlo -Mohnday -Mohphy -Moiqol Moist Moist Dreamz Moist Holy @@ -31702,8 +29567,6 @@ MoistWreck Moistium Mojimot0 Mojito -Mojo Fiki -Mojojojo171 Moju Moju GG Mojurico @@ -32488,7 +30351,6 @@ MrsSocorelis Mrslipkn0t Mrwaffleses Ms Goblin -Ms K Ms Lizziard Ms Trap Ms Zik @@ -32529,47 +30391,6 @@ Muckball Muco Mud Cricket Mud Temple -Mud9 -MudCatBigDog -Mudda Focha -Muddas Main -Muddy patch -Mudguard -Mudkins -Mudkip -Mudmur -Mueezy -MuerteBella -Mues -Mufasa -Mufasa IXI -MufffinKing -Mufficer -MuffinActual -Muffinkyutie -Muffins -Muffinyatta -Mufz -Mugarooni -Mugen -Mugge -Muggerman3 -Muggled -Muggles -Muggtjuven -Mugrub -Mugy -Mugzy -Muhaji -Muhamed -Muhfn -Muhkea -Mui Gokuu -Muilpeer -Muki -Mukkaram7861 -Mukkey -Muktheduck MulasRevenge Mulberry Mtn Muleleaveox @@ -32720,8 +30541,6 @@ Muziek Smurf Muzket Muzz Muzzle -Mv P -MvP ov RnG Mvk Mvko Mvp Scrub @@ -32851,51 +30670,16 @@ Mythrin III Myto Myuf Myuk -Mywa -Myz Myzi Mzaa Mziy -Mzr Mztar -N 10 -N 55 -N A l N E R -N E L L -N E N E N Gallagher -N I GH T96 -N I N O X -N I S H -N ICK Y -N O B S Y -N U B U -N W M -N a t t z -N ang -N anko -N arb -N dejay p -N e a k i le -N e i l -N e0 -N iall -N ibbler -N ightgleam -N l C K O -N l E V E -N o m a d -N occo -N oggin -N u d -N uggies -N-J-R N0 H34RT N0 Invictus N0 pid N00biistyl N00bslayer27 -N04me N0B4Marri4g3 N0Ballz N0ID @@ -32912,26 +30696,12 @@ N0t Maxed N0t special N0tliketh1s N0ul -N1 CK N17 Jake -N1C3 N1NJASK1LLZZ N1ckai N1cwho N1nja N1njaCat -N3XX -N3p -N3se -N3x -N4L -N4ruto -N4styNat3 -N7N -N8vy -N9NE420 -N9T7 -N9U NABEEL RJ NAGAKAMAL NANORA @@ -32940,14 +30710,6 @@ NASDBOY NASSERN NASTY NAVl -NB8K 2K13 -NBA -NBA NewMain -NBA Youngb0i -NC90 -NCG -NCG 2 -NCPS NEBR0SKY NECR0DANCER NEEDAMETHYST @@ -32964,14 +30726,9 @@ NEXFARMER NEYOVIC NFed NHL Blues -NHrn NIIXIIK NINJABLEV1NS NINJATMNT -NITR00 -NJC20 -NJWW -NKJ NL Chronos NL Gilbert NLDeluXe @@ -32995,32 +30752,15 @@ NOTaPancake NOmki NPC Healer NPC Icedrake -NPYJ -NRA -NSFL -NSHN NST Praise NT FiSHvv -NT Y NTBeerBandit NTMR RADIO NUEL NULLI NULLlN KUPPl NUTSHOT -NVQ -NWHL -NWI 219 RAT -NY -NY C -NY G -NY x LEGiiT -NZ Dave -NZL -N_MB N_other_day -Na Mn Or I -NaCl NaCl Sprite NaCl is salt NaQ @@ -33045,15 +30785,6 @@ Nacho Alt Nacho2030 NachoByte NachoDragon -NachoPapi -Nacht -Nachtkastje -NachuiTuda -Nadaa -Nadeo -Nader -Nadsage -Nadund Naethera Naftininkas Naga @@ -33110,26 +30841,12 @@ Namine Silke Namir Nammer Namuko -Nana -Nana Steel -Nanado -Nanciscor Nancyy Nander Nandos Nandos Man NangMan Nangdalorian -Nanimavi -Naniva -Nannertee -Nanno -Nannu Baba -NannyCam69 -Nanoh -Nanoman360 -Nanonymouse -Nanook IV Nanoray Nanotech Nans @@ -33179,38 +30896,6 @@ Naru808 Naruto Narval Narvalow -Narwallus -Narwhal1731 -Narx4 -Nas is like -Nasa -Nasaman -Nascar -Naseeph -Nashh -Nashluffy -Nashonic -Nashy -Naskarsdad -Nasko 07 -Nasper -Nasrullah -Nasseee -Nassim -Nast -Nastacov -Nastie -Nastik -Nasty -Nasty107red7 -NastyAss -NastyCasual -NastyDonger -NastyGarbage -NastyGeUsers -NastyV6 -Nasuuu -Nat Scheetje Natalie Natby Nate @@ -33479,8 +31164,6 @@ Nerf Bowfa Nerf Coffee Nerf Th1s NerfMePlz -NerfTG -Nergegante Nergg Nerio x Nerithma @@ -35685,24 +33368,15 @@ Ozzy Hobbit Ozzykye Ozzys Ozzzyy -P 0 W N E D -P 0 E F -P 0 R G I E -P A M K A -P A P Z -P A R N Y P DIRTY SODA P EDRAO P Eng -P I T P K P O L I S H P O T A T O P O V I P Purts P R O X -P R S -P V M Lew P W A Y P Y R O P a n x o @@ -35764,7 +33438,6 @@ P4sk P5ythix P6D P7DRO -P9 PA N I C PACK WATCH PACKETLOSS @@ -36344,11 +34017,7 @@ Pb and Jd Pbby Pbkillua PbyOne -PdaddyReborn PdfPKerNoGF -PdiddyReborn -Pe en -Pe t er Pe1ipp3r Peabody PeacandLove @@ -38185,12 +35854,6 @@ Pyzdalupi PzK Pzju PzzaPredator -Q 1 -Q K M Nophis -Q Proserpina -Q S L -Q cs -Q l ii Ma X Q of Spade Q uincy Q-Dance Jr @@ -49584,7 +47247,6 @@ USirHaveLost USirHaveWon UTT UWCB -UWF UWUSTELIJA UZY VS JAD Ualt @@ -49597,7 +47259,6 @@ Uber Yeats Uberamazing Ubersmind Ubicorn -Ubu Uccino Uchiwa Uchr @@ -49619,7 +47280,6 @@ Uh-0h Uhbove UhhhBoneless Uhhhh Wut -Uhm Uhscended Uidi One Uim Beyonce @@ -49679,7 +47339,6 @@ Umiland Ummfufu Ummz Un Dutchable -Un M-U-T-3-D Un puma Un-Expected UnDutchable @@ -54506,7 +52165,6 @@ apou appelkneuz applee aqp frog -aqqqqqqqqqqq aquafx araenel13 aratsanus @@ -54515,20 +52173,7 @@ archyiop arcvnaxiii arcwriter ard lad 06 -ardazz ardy guardy -arengs -arevles -arexmeister -arfih -argilah -ari abdul -ari shaffir -ariman22 -arkoudaphile -armadyyyyldo -armyofkids -arnr arocardo arookie arouze @@ -54559,7 +52204,6 @@ asian asianbunnyx asibioass asidb -asm asmoooo ason jones aspiraring1 @@ -54571,9 +52215,6 @@ assbergerler assdrag asseaterbtw assoffire -astgferallah -asuhcuh -at0 atob7 atoma619 attaaM @@ -54582,7 +52223,6 @@ auditore28 audrey audrey horne auma -aus j osh aussieyobbo aut AT5 aut1st1c @@ -54623,22 +52263,6 @@ azilim aziz8mohd azj azura -b a g -b a l r a j -b b o x x -b eeg -b enjy -b ezos -b i g s t -b kuz -b l u rr -b oe -b on ass -b oo n -b ooth -b u l -b ulba -b-ray29 b00ty b00tyw1zard b0btehcool @@ -54950,10 +52574,6 @@ bisse bitten by bitter bitter fruit -bj0rne -bjassen -bjpc -bjuti bkguytd6 bl00d twinz bl00dShaman @@ -55026,23 +52646,10 @@ blutorch blvckstvrr blynaas bman5 -bmeow -bnff bnndt bnqy -bo bby -bo nk bo2Lawrence bo3rke -bo4r -bob bob bob -bobby ross -bobby45153 -bobbyb727 -bobbyitsme -bobbyjoe -bobbytronx -bober vvittu bobfish66 bobness bobondowski @@ -55124,10 +52731,8 @@ boycie420 boydi boydt boyuniverse -boz pwr boze bozo -bp9 br0wnardRS braap poster bradrian @@ -55263,18 +52868,6 @@ byEmilsson byll byrny bzerk -c a b l a y -c bro -c greyson -c h u c kles -c hainz -c j t -c m l -c o 1 a -c onorr -c rompt -c ubic -c xx zz c c-ross93 c00lbeer c0vid @@ -59902,14 +57495,7 @@ mlong06 mmaxie mmigo mmmkay02 -mmmmmmmmhmm -mmmmmmnmmnm -mmmuurrddaaa -mndo mniml -mno -mnt -mo an mobile moer mogwire @@ -60014,13 +57600,6 @@ mstr nay nay mtash96 mthic muchderanged -mucserup -mudbitedlite -mufassa -muffing -muggfac -mugii -muh muh sheen muhName muhnamezjeff @@ -60075,12 +57654,6 @@ myrtlecat mys_try mystic myturngranny -mzsc -n a g a -n k h -n o m i s -n oge -n os n00b tax n00btube n00dIe @@ -60091,14 +57664,7 @@ n0rthmemphis n1ch0las n1ghtmares n3cromans3r -n4ts -n8m -n8n nSubordinate -nVox -nYer -n_koo -na cba naamarihomo naapurintati nabritches @@ -60383,17 +57949,10 @@ nymue nysyGG nzskater o Buffy o -o Galaxy -o Jay o -o NEK o o Pug o o SiLeNce o o Steven o o c c u l t -o chem -o n e i n v -o tp -o tu o0 Rang0r 0o o00dan00o o0Ganktank0o @@ -60656,9 +58215,6 @@ oxyy oysni tu ozos ozztrevor -p hd -p n g -p x v x m p000r p0ge p0tat0_baked @@ -60730,7 +58286,6 @@ pazmar pb tiramisu pbagel pbj eater -pbjt pcce pd3 pdi @@ -61057,9 +58612,6 @@ pzqlpwbma q Aleks q Nossie p q b0nkerz q -q f z -q l l u -q sl q-Mini-p q0k q9q9q @@ -61117,15 +58669,6 @@ qwruqwpourqr qy qz qzxz -r a i n i n -r a i q -r d x -r eflex -r ehab -r i ley -r n g o d -r o c h i -r pt r u a pussy r0adh0g r0jasss @@ -62393,12 +59936,6 @@ syytu szer szeth17 sztuk -t iel -t imbo -t r a m -t rio -t u k e -t ux t-Wrench t-painn t0_valhalla @@ -62657,11 +60194,7 @@ tjd1233 tjomka tksnevrlucky tmahones -tmeer -tmeer 18 -tmjdx tmued -to dd to0Oldf0r1t to_o toad @@ -62729,7 +60262,6 @@ toxiclun toxicsaitama toy Owner tozmic -tq tr0nberg tr0nd tra1nwr3ck13 @@ -62993,12 +60525,6 @@ uz x uzei uzis akimbo uzui -v Simba v -v olksu -v oltage -v tsng -v uka -v yp v-yordan0702 v0i kehveli v0mbat @@ -63172,10 +60698,6 @@ vw vzi vzkg w Danko -w e b r l -w en -w ert -w vy w00_88 w00d pecker w00tgh0st @@ -63330,7 +60852,6 @@ whyamisofat whynotp2p whyuboolyme whyzerkbro -wi f wibeton widefang wiegehtsmir @@ -63375,12 +60896,10 @@ wiw wizard129 wizardyoda7 wizkid499 -wjsn wkurtin wlkerTXrangr wndow wndy -wngo woah wocket wodg @@ -63431,17 +60950,10 @@ wutzgood wutzit wwTakun wweadge2 -www -wwwMusic-Map -wyat wyattearp99 wyked wytch wyverns4days -wzav423 -wzrdddddyo -wzrds -wzs x 0lev x x ABBlE x Argonath x @@ -63482,10 +60994,7 @@ x iyad x x lollage x x mk ultra x preska x -x r x warri0r121 -x zi -x zn x073x x0Mag x0Tub @@ -63594,15 +61103,6 @@ xHugsi xHussla xI3reeze xIron Senpai -xJeb -xJiren -xJlN -xJolt -xJord -xJordd -xJulia -xJuve -xKAJJEx xKadi xKdpunx xKing @@ -63822,7 +61322,6 @@ xtyrantix xvn xvrph xvza -xwl xwuwesxdrf xx darkminer xxDerp @@ -63843,8 +61342,6 @@ xzb xzizzil xzn 2 xzwu -y om -y w y0y0keepitup y37ir y8s1 @@ -63869,10 +61366,6 @@ yapgragim yasuo god69 yayasquirrel ydoc -ye idc -ye ki M -ye p to -yea im jebus yeahboi9992 yeahsmitty yeahyoink @@ -63897,9 +61390,7 @@ ykO Ops ykeL yleisradio ylliB -ym y ymca4life -yna yo eight yo itz ep yobacha @@ -63914,32 +61405,6 @@ yooyeet yorkietootz yorue you died123 -you r a qt -youb1n -youneedcope -young meows -young vibby -youngbriks -youngmachine -youngtrop21 -youngwings -youpougou -your -your thrall -youralterego -youssef -yowasupppbra -yoyoma361 -yp -ypoodle -ypool4 -ypools -yragbackward -yrhs -yribbles -ytsud mi -ytuiop -yugiiii yuh huh yum yummybolete @@ -63960,13 +61425,6 @@ yyknaH J yyttam yyzanadu94 yzyzyzy -z 5 x -z Animal z -z Rhodes -z Shane -z a p s -z iQ -z man827 z0nk z0rrda z0up @@ -63999,10 +61457,6 @@ zSlay zSpaceRaptor zSwanny zTitan -zWxLF -za2 -za33erklan -zaaza zacharial zachhy zachte @@ -64029,7 +61483,6 @@ zazyga zbra zclx zcollins -zdi zdin zdya ze4l @@ -64091,10 +61544,6 @@ zionari zippp zirreael ziurbtw -ziuys -ziyi_wangler -zjh -zjind zlayaa zlink10 zlliM @@ -64124,7 +61573,6 @@ zruG zrzwns ztaM ztkfps -zu b zubor1 zuenzima zujal @@ -64139,8 +61587,6 @@ zummorak zurcc zurlond zuuryy -zw -zwah zwint zwolle zwqpDEOXl23 @@ -64152,9 +61598,6 @@ zykez zymaa zymz zysuna -zzad -zzai zzben zzero -zzigma -zzzJonno +zzigma \ No newline at end of file diff --git a/Server/data/configs/object_overrides.json b/Server/data/configs/object_overrides.json new file mode 100644 index 000000000..c00cbf672 --- /dev/null +++ b/Server/data/configs/object_overrides.json @@ -0,0 +1,165 @@ +[ + { + "mode": "add", + "id": "1814", + "location": "3090, 3475, 0", + "type": "4", + "direction": "nw" + }, + { + "mode": "add", + "id": "2646", + "location": "2445, 3413, 0", + "direction": "nw" + }, + { + "mode": "add", + "id": "2646", + "location": "2447, 3414, 0", + "direction": "e" + }, + { + "mode": "add", + "id": "2646", + "location": "2447, 3421, 0", + "direction": "nw" + }, + { + "comment": "Prison Pete Random", + "mode": "add", + "id": "36788", + "location": "2094, 4465, 0", + "type": "10", + "direction": "e" + }, + { + "comment": "Green Portal", + "mode": "remove", + "id": "11371", + "location": "2085, 4457, 0" + }, + { + "comment": "Lever", + "mode": "remove", + "id": "10817", + "location": "2083, 4460, 0" + }, + { + "comment": "Lever", + "mode": "add", + "id": "26191", + "location": "2083, 4460, 0", + "type": "10", + "direction": "e" + }, + { + "comment": "Window", + "mode": "add", + "id": "26184", + "location": "2084, 4459, 0", + "type": "0", + "direction": "n" + }, + { + "comment": "Door", + "mode": "add", + "id": "26186", + "location": "2085, 4459, 0", + "type": "0", + "direction": "n" + }, + { + "comment": "Door", + "mode": "add", + "id": "26188", + "location": "2086, 4459, 0", + "type": "0", + "direction": "n" + }, + { + "comment": "Window", + "mode": "add", + "id": "26184", + "location": "2087, 4459, 0", + "type": "0", + "direction": "n" + }, + { + "mode": "remove", + "id": "37670", + "location": "3292, 3299, 0" + }, + { + "mode": "add", + "id": "37304", + "location": "3292, 3299, 0" + }, + { + "mode": "add", + "id": "20987", + "location": "3821, 2996, 0" + }, + { + "mode": "remove", + "id": "356", + "location": "2804, 3428, 0" + }, + { + "mode": "add", + "id": "356", + "location": "2804, 3428, 0" + }, + { + "mode": "remove", + "id": "20228", + "location": "2537, 3573, 0" + }, + { + "mode": "add", + "id": "27663", + "location": "2537, 3573, 0", + "direction": "w" + }, + { + "mode": "add", + "id": "39237", + "location": "2957, 3266, 0", + "direction": "n" + }, + { + "mode": "add", + "id": "39245", + "location": "2956, 3270, 0", + "direction": "se" + }, + { + "mode": "add", + "id": "39242", + "location": "2955, 3273, 0", + "direction": "w" + }, + { + "mode": "add", + "id": "39241", + "location": "2955, 3274, 0" + }, + { + "mode": "add", + "id": "20987", + "location": "2821, 2996, 0", + "direction": "s" + }, + { + "mode": "add", + "id": "21301", + "location": "2662, 3162, 0", + "direction": "e" + }, + { + "mode": "add", + "id": "4176", + "location": "2629, 3661, 2", + "type": "4", + "direction": "e" + } +] diff --git a/Server/pom.xml b/Server/pom.xml index 5c93c44d2..ffc43d1c8 100644 --- a/Server/pom.xml +++ b/Server/pom.xml @@ -252,6 +252,7 @@ false false + -Xmx4g -Xms2g 2.22.0 diff --git a/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt b/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt index 074ab27a6..6a7b8802a 100644 --- a/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt +++ b/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt @@ -99,12 +99,18 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando return ShootingStarType.values()[level.ordinal - 1] } + /** + * Clears the current star object or sprite + */ + fun clear() { + SceneryBuilder.remove(starObject) + clearSprite() + } + /** * Fires the shooting star (spawns a new one). Only used when spawning new shooting stars, not for downgrading existing ones. */ fun fire() { - SceneryBuilder.remove(starObject) - clearSprite() SceneryBuilder.add(starObject) if(!isSpawned) { (0..2).forEach { diff --git a/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt b/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt index 7368b7689..0c938aec5 100644 --- a/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt +++ b/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt @@ -17,6 +17,7 @@ import core.game.world.GameWorld import core.tools.Log import core.tools.secondsToTicks import content.data.Quests +import core.game.node.scenery.SceneryBuilder class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Commands, StartupListener { override fun login(player: Player) { @@ -46,6 +47,7 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com // Check if it's time to fire a new one if (star.ticks >= tickDelay && !star.spriteSpawned) { + star.clear() star.rebuildVars() star.fire() } @@ -133,11 +135,12 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com } override fun defineCommands() { - define("tostar", Privilege.ADMIN, description = "Teleports you adjacent to the currently active star.") { player, _ -> - teleport(player, star.starObject.location.transform(1,1,0)) + define("tostar", Privilege.ADMIN, description = "Teleports you inside the currently active star.") { player, _ -> + teleport(player, star.starObject.location.transform(0, 0, 0)) } define("submit", Privilege.ADMIN, description = "Rebuilds and fires the shooting star event immediately.") { _, _ -> + star.clear() star.rebuildVars() star.fire() } diff --git a/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt b/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt index 5b065f567..c945d2f6e 100644 --- a/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt +++ b/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt @@ -8,12 +8,15 @@ import core.game.node.item.Item import core.tools.RandomFunction import org.rs09.consts.Items import content.global.ame.RandomEventNPC +import core.api.sendMessage import core.api.utils.WeightBasedTable +import core.game.world.map.MapDistance val ids = (2463..2468).toList() 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!") + var sentMessage = false override fun talkTo(npc: NPC) {} override fun init() { @@ -31,13 +34,17 @@ class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventN } override fun tick() { - if(!player.location.withinDistance(this.location,8)){ - this.terminate() - } - if(getWorldTicks() % 10 == 0){ - sendChat(phrases.random().replace("@name",player.username.capitalize())) + if (!sentMessage) { + if (!player.location.withinDistance(this.location, 8)) { + // https://www.youtube.com/watch?v=v9p_I_Tq3JE + sendMessage(player, "The Evil Chicken realises you're out of range and vanishes.") + sentMessage = true + terminate() + } + if (getWorldTicks() % 10 == 0) { + sendChat(phrases.random().replace("@name", player.username.capitalize())) + } } super.tick() - if(!player.viewport.currentPlane.npcs.contains(this)) this.clear() } } diff --git a/Server/src/main/content/global/ame/events/maze/MazeInterface.kt b/Server/src/main/content/global/ame/events/maze/MazeInterface.kt index c3c1ab7f4..5376e870c 100644 --- a/Server/src/main/content/global/ame/events/maze/MazeInterface.kt +++ b/Server/src/main/content/global/ame/events/maze/MazeInterface.kt @@ -15,6 +15,7 @@ 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.RegionManager import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneRestriction import core.game.world.update.flag.context.Graphics @@ -109,73 +110,17 @@ class MazeInterface : InteractionListener, EventHook, MapArea { 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 -> + lock(player, 3) + animate(player, 536) + replaceScenery(node.asScenery(), Scenery.CHEST_3636, 3) if (getAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) > 0 && getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0) < 10) { - 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){ + 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!") @@ -187,7 +132,7 @@ class MazeInterface : InteractionListener, EventHook, MapArea { 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)) + setAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, getAttribute(player, MAZE_ATTRIBUTE_CHESTS_OPEN, 0) + 1) } else { sendMessage(player,"You find nothing of interest.") } diff --git a/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt b/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt index dff28d7e9..50888b63e 100644 --- a/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt +++ b/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt @@ -3,7 +3,9 @@ package content.global.ame.events.rivertroll import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC +import core.api.getWorldTicks import core.api.utils.WeightBasedTable +import core.game.world.map.MapDistance val ids = (391..396).toList() @@ -21,10 +23,12 @@ class RiverTrollRENPC(override var loot: WeightBasedTable? = null) : RandomEvent super.finalizeDeath(killer) } override fun tick() { - if(!player.location.withinDistance(this.location,8)){ + if (!player.location.withinDistance(this.location, 8)) { this.terminate() } super.tick() - if(!player.viewport.currentPlane.npcs.contains(this)) this.clear() + if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { + this.clear() + } } } \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt b/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt index eb3399657..68bd92beb 100644 --- a/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt +++ b/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt @@ -3,7 +3,9 @@ package content.global.ame.events.rockgolem import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC +import core.api.getWorldTicks import core.api.utils.WeightBasedTable +import core.game.world.map.MapDistance val ids = (413..418).toList() @@ -21,10 +23,12 @@ class RockGolemRENPC(override var loot: WeightBasedTable? = null) : RandomEventN super.finalizeDeath(killer) } override fun tick() { - if(!player.location.withinDistance(this.location,8)){ + if (!player.location.withinDistance(this.location, 8)) { this.terminate() } super.tick() - if(!player.viewport.currentPlane.npcs.contains(this)) this.clear() + if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { + this.clear() + } } } \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt b/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt index 60a0f57ae..14bcdd609 100644 --- a/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt +++ b/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt @@ -3,7 +3,9 @@ package content.global.ame.events.shade import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC +import core.api.getWorldTicks import core.api.utils.WeightBasedTable +import core.game.world.map.MapDistance class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){ val ids = (425..430).toList() @@ -20,10 +22,12 @@ class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(4 super.finalizeDeath(killer) } override fun tick() { - if(!player.location.withinDistance(this.location,8)){ + if (!player.location.withinDistance(this.location, 8)) { this.terminate() } super.tick() - if(!player.viewport.currentPlane.npcs.contains(this)) this.clear() + if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { + this.clear() + } } } diff --git a/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt b/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt index 3b0033972..0bba8e2b5 100644 --- a/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt +++ b/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt @@ -3,7 +3,9 @@ package content.global.ame.events.treespirit import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC +import core.api.getWorldTicks import core.api.utils.WeightBasedTable +import core.game.world.map.MapDistance val ids = (438..443).toList() @@ -21,10 +23,12 @@ class TreeSpiritRENPC(override var loot: WeightBasedTable? = null) : RandomEvent super.finalizeDeath(killer) } override fun tick() { - if(!player.location.withinDistance(this.location,8)){ + if (!player.location.withinDistance(this.location, 8)) { this.terminate() } super.tick() - if(!player.viewport.currentPlane.npcs.contains(this)) this.clear() + if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { + this.clear() + } } } \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt b/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt index 6b43d54b4..ebe4465bc 100644 --- a/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt +++ b/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt @@ -3,7 +3,9 @@ package content.global.ame.events.zombie import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC +import core.api.getWorldTicks import core.api.utils.WeightBasedTable +import core.game.world.map.MapDistance class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(419){ val ids = (419..424).toList() @@ -20,10 +22,12 @@ class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC( super.finalizeDeath(killer) } override fun tick() { - if(!player.location.withinDistance(this.location,8)){ + if (!player.location.withinDistance(this.location, 8)) { this.terminate() } super.tick() - if(!player.viewport.currentPlane.npcs.contains(this)) this.clear() + if (!player.location.withinDistance(this.location, MapDistance.RENDERING.distance)) { + this.clear() + } } } diff --git a/Server/src/main/content/global/bots/Adventurer.kt b/Server/src/main/content/global/bots/Adventurer.kt index 916503945..62464bbf2 100644 --- a/Server/src/main/content/global/bots/Adventurer.kt +++ b/Server/src/main/content/global/bots/Adventurer.kt @@ -21,6 +21,7 @@ import core.game.bots.CombatBotAssembler import core.game.bots.Script import core.game.interaction.IntType import core.game.interaction.InteractionListeners +import core.game.world.repository.Repository import core.tools.Log import java.io.File import java.io.FileReader @@ -114,7 +115,7 @@ class Adventurer(val style: CombatStyle): Script() { } private fun otherPlayersNearby(): Boolean { - val localPlayers = RegionManager.getLocalPlayers(bot) + val localPlayers = RegionManager.getLocalPlayers(bot.location) val otherPlayers = localPlayers.filter { it.name != bot.name } return otherPlayers.isNotEmpty() } @@ -503,7 +504,7 @@ class Adventurer(val style: CombatStyle): Script() { dateCode == 404 -> lineAlt = dialogue.getLines("easter").rand() } - var localPlayers = RegionManager.getLocalPlayers(bot) + val localPlayers = RegionManager.getLocalPlayers(bot.location) if (localPlayers.isNotEmpty()) { val localPlayer = localPlayers .filter { it.name != bot.name } diff --git a/Server/src/main/content/global/bots/CannonballSmelter.kt b/Server/src/main/content/global/bots/CannonballSmelter.kt index 8ac77f7e1..bc921111b 100644 --- a/Server/src/main/content/global/bots/CannonballSmelter.kt +++ b/Server/src/main/content/global/bots/CannonballSmelter.kt @@ -58,7 +58,7 @@ class CannonballSmelter : Script() { } else if(!coalMine.insideBorder(bot)){ scriptAPI.walkTo(coalMine.randomLoc) } else { - val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node?.id!!).reward == Items.COAL_453 }) + val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.COAL_453 }) if(rock != null) { scriptAPI.interact(bot, rock, "mine") } else { @@ -75,7 +75,7 @@ class CannonballSmelter : Script() { var loc = ironMine.randomLoc scriptAPI.walkTo(loc) } else { - val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node?.id!!).reward == Items.IRON_ORE_440 }) + val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.IRON_ORE_440 }) //rock?.let { InteractionListeners.run(rock.id, IntType.SCENERY,"mine",bot,rock) } if(rock != null) { scriptAPI.interact(bot, rock, "mine") diff --git a/Server/src/main/content/global/bots/DoublingMoney.kt b/Server/src/main/content/global/bots/DoublingMoney.kt index 785fd8690..8840191eb 100644 --- a/Server/src/main/content/global/bots/DoublingMoney.kt +++ b/Server/src/main/content/global/bots/DoublingMoney.kt @@ -22,6 +22,7 @@ import core.game.bots.Script import core.game.interaction.IntType import core.game.interaction.InteractionListeners import core.game.world.ImmerseWorld +import core.game.world.repository.Repository import java.io.File import java.io.FileReader import java.util.Random @@ -262,10 +263,12 @@ class DoublingMoney : Script() { minDist = min(minDist, loc.getDistance(bot.location)) } if (minDist > 1) return 2 - RegionManager.forId(bot.location.regionId).planes[bot.location.z].players.forEach { - if (AIRepository.PulseRepository[it?.username?.lowercase()]?.botScript is DoublingMoney - && it != bot - && it.location.getDistance(bot.location) <= 1) { + val region = RegionManager.forId(bot.location.regionId) + val players = region.assemblePlayerList(bot.location.z) + for (player in players) { + if (AIRepository.PulseRepository[player.username.lowercase()]?.botScript is DoublingMoney + && player != bot + && player.location.getDistance(bot.location) <= 1) { return 2 } } diff --git a/Server/src/main/content/global/handlers/item/equipment/special/ChainhitSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/ChainhitSpecialHandler.java index b3e276dcd..08b180396 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/ChainhitSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/ChainhitSpecialHandler.java @@ -79,7 +79,7 @@ public final class ChainhitSpecialHandler extends RangeSwingHandler implements P if (!((Player) entity).getSettings().drainSpecial(SPECIAL_ENERGY)) { return -1; } - state.setStyle(CombatStyle.RANGE); + state.setStyle(CombatStyle.RANGE); if (victim instanceof NPC) { NPC npc = victim.asNpc(); if (npc.getId() == 2440) { @@ -186,9 +186,9 @@ public final class ChainhitSpecialHandler extends RangeSwingHandler implements P if (list == null) { int distance = 5; if (victim instanceof NPC) { - e.setAttribute("chain-hit_v", list = RegionManager.getLocalNpcs(e, distance)); + e.setAttribute("chain-hit_v", list = RegionManager.getLocalNPCs(e.getLocation(), distance)); } else { - e.setAttribute("chain-hit_v", list = RegionManager.getLocalPlayers(e, distance)); + e.setAttribute("chain-hit_v", list = RegionManager.getLocalPlayers(e.getLocation(), distance)); } list.remove(e); list.remove(victim); diff --git a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java index a0801835e..0523f8753 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java @@ -13,7 +13,6 @@ import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; -import java.util.ArrayList; import java.util.List; /** @@ -56,14 +55,18 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { return -1; } - // ! Initial capacity of 14, but has dynamic size? i.e. we are not restricting to a max of 14 targets hit here now - List targetCandidates = new ArrayList<>(14); - targetCandidates.addAll(RegionManager.getSurroundingNPCs(victim, 14, entity)); - targetCandidates.addAll(RegionManager.getSurroundingPlayers(victim, 14, entity)); + // https://oldschool.runescape.wiki/w/Chinchompa - shit source but it's better than what was here before + @SuppressWarnings("rawtypes") List targetCandidates; + if (victim instanceof Player) { + targetCandidates = RegionManager.getSurroundingPlayers(victim, 9); + } else { + targetCandidates = RegionManager.getSurroundingNPCs(victim, 11); + } BattleState[] targets = new BattleState[targetCandidates.size()]; int count = 0; - for (Entity e : targetCandidates) { - if (canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { + for (Object o : targetCandidates) { + Entity e = (Entity) o; + if (e != entity && canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { BattleState s = targets[count++] = new BattleState(entity, e); s.setStyle(CombatStyle.RANGE); int hit = 0; diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index ba3ff8ed0..0b09a3c2c 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -76,12 +76,12 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements return super.swing(entity, victim, state); } @SuppressWarnings("rawtypes") - List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9, entity) : RegionManager.getSurroundingPlayers(entity, 9, entity); + List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Object o : list) { Entity e = (Entity) o; - if (CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { + if (e != entity && CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { BattleState s = targets[count++] = new BattleState(entity, e); int hit = 0; if (isAccurateImpact(entity, e)) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java index 2595b0479..4ae69ddc2 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java @@ -77,12 +77,12 @@ public final class SpearWallSpecialHandler extends MeleeSwingHandler implements return super.swing(entity, victim, state); } @SuppressWarnings("rawtypes") - List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9, entity) : RegionManager.getSurroundingPlayers(entity, 9, entity); + List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Object o : list) { Entity e = (Entity) o; - if (CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { + if (e != entity && CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { BattleState s = targets[count++] = new BattleState(entity, e); int hit = 0; hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index 6c4b9cedc..c51e3532e 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -2,7 +2,9 @@ package content.global.handlers.item.equipment.special; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import core.game.world.repository.Repository; import core.plugin.Initializable; import content.global.skill.summoning.familiar.Familiar; import core.game.node.entity.Entity; @@ -98,7 +100,10 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); - for (Entity n : victim instanceof NPC ? RegionManager.getSurroundingNPCs(victim, 9, entity, victim) : RegionManager.getSurroundingPlayers(victim, 9, entity, victim)) { + for (Entity n : victim instanceof NPC ? RegionManager.getSurroundingNPCs(victim, 9) : RegionManager.getSurroundingPlayers(victim, 9)) { + if (n == entity) { + continue; + } if (n instanceof Familiar) { continue; } diff --git a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java index 37ff46584..fc63daa34 100644 --- a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java +++ b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java @@ -21,47 +21,47 @@ import java.util.Objects; @Initializable public final class SoftclayPlugin extends UseWithHandler { - /** - * Represents the clay item. - */ - private static final Item CLAY = new Item(Items.CLAY_434); + /** + * Represents the clay item. + */ + private static final Item CLAY = new Item(Items.CLAY_434); - /** - * Represents the soft clay item. - */ - private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); + /** + * Represents the soft clay item. + */ + private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); - /** - * Represents the bowl of water item. - */ - private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); + /** + * Represents the bowl of water item. + */ + private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); - /** - * Represents the empty bowl item. - */ - private static final Item BOWL = new Item(Items.BOWL_1923); + /** + * Represents the empty bowl item. + */ + private static final Item BOWL = new Item(Items.BOWL_1923); - /** - * Represents the empty bucket item. - */ - private static final Item BUCKET = new Item(Items.BUCKET_1925); + /** + * Represents the empty bucket item. + */ + private static final Item BUCKET = new Item(Items.BUCKET_1925); /** * Represents the bucket of water item. */ private static final Item BUCKET_OF_WATER = new Item(Items.BUCKET_OF_WATER_1929); - /** - * Represents the jug item. - */ - private static final Item JUG = new Item(Items.JUG_1935); + /** + * Represents the jug item. + */ + private static final Item JUG = new Item(Items.JUG_1935); /** * Represents the jug of water item. */ private static final Item JUG_OF_WATER = new Item(Items.JUG_OF_WATER_1937); - /** + /** * Constructs a new {@code SoftclayPlugin} {@code Object}. */ public SoftclayPlugin() { @@ -70,7 +70,7 @@ public final class SoftclayPlugin extends UseWithHandler { @Override public Plugin newInstance(Object arg) throws Throwable { - addHandler(1921, ITEM_TYPE, this); + addHandler(1921, ITEM_TYPE, this); addHandler(1929, ITEM_TYPE, this); addHandler(1937, ITEM_TYPE, this); return this; @@ -115,33 +115,33 @@ public final class SoftclayPlugin extends UseWithHandler { * @return {@code True} if so. */ private boolean create(final Player player, NodeUsageEvent event) { - Item removeItem = null; - Item returnItem = null; - if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { - removeItem = BUCKET_OF_WATER; - returnItem = BUCKET; - } - if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { - removeItem = BOWL_OF_WATER; - returnItem = BOWL; - } - if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { - removeItem = JUG_OF_WATER; - returnItem = JUG; - } + Item removeItem = null; + Item returnItem = null; + if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { + removeItem = BUCKET_OF_WATER; + returnItem = BUCKET; + } + if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { + removeItem = BOWL_OF_WATER; + returnItem = BOWL; + } + if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { + removeItem = JUG_OF_WATER; + returnItem = JUG; + } if (player.getInventory().containsItem(CLAY) && player.getInventory().containsItem(Objects.requireNonNull(removeItem))) { - player.getInventory().remove(removeItem); - player.getInventory().remove(CLAY); - player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); - player.getInventory().add(SOFT_CLAY); - player.getInventory().add(returnItem); - if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getViewport().getRegion().getId() == 12341) { - player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); - } + player.getInventory().remove(removeItem); + player.getInventory().remove(CLAY); + player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); + player.getInventory().add(SOFT_CLAY); + player.getInventory().add(returnItem); + if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { + player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); + } return true; } else { - return false; - } + return false; + } } } diff --git a/Server/src/main/content/global/handlers/item/withobject/WaterSourceListener.kt b/Server/src/main/content/global/handlers/item/withobject/WaterSourceListener.kt index 75652b75d..dfa302014 100644 --- a/Server/src/main/content/global/handlers/item/withobject/WaterSourceListener.kt +++ b/Server/src/main/content/global/handlers/item/withobject/WaterSourceListener.kt @@ -15,30 +15,19 @@ import org.rs09.consts.Sounds * @author Ceikry */ class WaterSourceListener : InteractionListener { - // NOTE '9695' should be removed from the array below once the sink object can be used directly, this is a temporary - // solution. - // this is ugly! - private val waterSources = intArrayOf(21355, 16302, 6827, 11661, 24160, 34577, 15936, 15937, 15938, 23920, 35469, 24265, 153, 879, 880, 2864, 6232, 10436, 10437, 10827, 11007, 11759, 21764, 22973, 24161, 24214, 24265, 28662, 30223, 30820, 34579, 36781, 873, 874, 4063, 6151, 8699, 9143, 9684, 9695, 10175, 12279, 12974, 13563, 13564, 14868, 14917, 14918, 15678, 16704, 16705, 20358, 22715, 24112, 24314, 25729, 25929, 26966, 29105, 33458, 34082, 34411, 34496, 34547, 34566, 35762, 36971, 37154, 37155, 878, 884, 3264, 3305, 3359, 4004, 4005, 6097, 6249, 6549, 8747, 8927, 11793, 12201, 12897, 24166, 26945, 31359, 32023, 32024, 34576, 35671, 40063, 13561, 13563, 13559, 12089) + private val waterSources = intArrayOf(21355, 16302, 6827, 11661, 24160, 34577, 15936, 15937, 15938, 23920, 35469, 24265, 153, 879, 880, 2864, 6232, 10436, 10437, 10827, 11007, 11759, 21764, 22973, 24161, 24214, 24265, 28662, 30223, 30820, 34579, 36781, 873, 874, 4063, 6151, 8699, 9143, 9684, 10175, 12279, 12974, 13563, 13564, 14868, 14917, 14918, 15678, 16704, 16705, 20358, 22715, 24112, 24314, 25729, 25929, 26966, 29105, 33458, 34082, 34411, 34496, 34547, 34566, 35762, 36971, 37154, 37155, 878, 884, 3264, 3305, 3359, 4004, 4005, 6097, 6249, 6549, 8747, 8927, 11793, 12201, 12897, 24166, 26945, 31359, 32023, 32024, 34576, 35671, 40063, 13561, 13563, 13559, 12089) private val nonWellableMsg = "If I drop my @ down there, I don't think I'm likely to get it back." private val animation = Animation(832) - override fun defineListeners() - { + override fun defineListeners() { onUseWith(IntType.SCENERY, WaterVessel.getInputs(), *waterSources){ player, used, with -> val vessel = WaterVessel.forId(used.id) ?: return@onUseWith false - if(with.name.contains("well", ignoreCase = true) && !vessel.wellable) { sendMessage(player, formatMsgText(used.name, nonWellableMsg)) return@onUseWith true } - - if(with.id == 9695 && player.location.regionId != 11571) - { - return@onUseWith false - } - //ugly achievement code, achievement system sux if(vessel == WaterVessel.BUCKET && with.id == 11661) { @@ -67,15 +56,6 @@ class WaterSourceListener : InteractionListener { return@onUseWith true } - - // This is needed to make the crafting guild sink work, but technically it's wrong as it is the noticeboard and - // not the sink being used. This is a temporary solution until the sink object can be used directly. - setDest(IntType.SCENERY, intArrayOf(9695), "use") { player, node -> - if (player.location.regionId == 11571){ - return@setDest Location.create(2934, 3280, 0) - } - return@setDest node.location - } } private fun formatMsgText(name: String, template: String): String diff --git a/Server/src/main/content/global/handlers/scenery/TableListener.kt b/Server/src/main/content/global/handlers/scenery/TableListener.kt index c35ebd27b..c89c6262b 100644 --- a/Server/src/main/content/global/handlers/scenery/TableListener.kt +++ b/Server/src/main/content/global/handlers/scenery/TableListener.kt @@ -413,7 +413,7 @@ class TableListener : InteractionListener { } val droppedItem = used.dropItem if (droppedItem.id == Items.COINS_995) playAudio(player, DROP_COINS_SOUND) else playAudio(player, DROP_ITEM_SOUND) - GroundItemManager.create(droppedItem, Location(nearestX, nearestY), player) + GroundItemManager.create(droppedItem, Location(nearestX, nearestY, player.location.z), player) setAttribute(player, "droppedItem:${droppedItem.id}", getWorldTicks() + 2) PlayerParser.save(player) diff --git a/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java b/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java index 13a6a4ad6..c046d73f7 100644 --- a/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java +++ b/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java @@ -19,6 +19,7 @@ import core.game.world.GameWorld; import core.game.world.map.*; import core.game.world.map.zone.MapZone; import core.game.world.map.zone.ZoneBuilder; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; import core.plugin.Plugin; @@ -37,300 +38,302 @@ import static core.api.ContentAPIKt.*; @Initializable public final class BrimhavenArena extends MapZone implements Plugin { - /** - * The location based traps. - */ - private static final Map LOCATION_TRAPS = new HashMap<>(); + /** + * The location based traps. + */ + private static final Map LOCATION_TRAPS = new HashMap<>(); - /** - * The overlay component. - */ - private static final Component OVERLAY = new Component(5); + /** + * The overlay component. + */ + private static final Component OVERLAY = new Component(5); - /** - * The ticket dispenser locations. - */ - private static final Location[] DISPENSERS = new Location[24]; + /** + * The ticket dispenser locations. + */ + private static final Location[] DISPENSERS = new Location[24]; - /** - * The agility ticket reward item. - */ - private static final Item TICKET = new Item(2996); + /** + * The agility ticket reward item. + */ + private static final Item TICKET = new Item(2996); - /** - * If the saw blade is currently active. - */ - public static boolean sawBladeActive; + /** + * If the saw blade is currently active. + */ + public static boolean sawBladeActive; - /** - * Constructs a new {@code BrimhavenArena} {@code Object}. - */ - public BrimhavenArena() { - super("Brimhaven agility arena", true); - } + /** + * Constructs a new {@code BrimhavenArena} {@code Object}. + */ + public BrimhavenArena() { + super("Brimhaven agility arena", true); + } - /** - * Sets the current ticket dispenser target. - * - * @param player The player. - */ - private void setDispenser(Player player) { - if (!player.getAttribute("brim-tagged", false)) { - player.setAttribute("brim-tagcount", 0); - } - player.setAttribute("brim-tagged", false); - setVarp(player, 309, 0); - int index = RandomFunction.randomize(DISPENSERS.length); - if (index == player.getAttribute("brim-tag", -1)) { - index = (index + 1) % DISPENSERS.length; - } - int iconSlot = player.getAttribute("brim-icon", -1); - if (iconSlot > -1) { - HintIconManager.removeHintIcon(player, iconSlot); - } - player.setAttribute("brim-tag", index); - player.setAttribute("brim-icon", HintIconManager.registerHeightHintIcon(player, DISPENSERS[index], 50)); - } + /** + * Sets the current ticket dispenser target. + * + * @param player The player. + */ + private void setDispenser(Player player) { + if (!player.getAttribute("brim-tagged", false)) { + player.setAttribute("brim-tagcount", 0); + } + player.setAttribute("brim-tagged", false); + setVarp(player, 309, 0); + int index = RandomFunction.randomize(DISPENSERS.length); + if (index == player.getAttribute("brim-tag", -1)) { + index = (index + 1) % DISPENSERS.length; + } + int iconSlot = player.getAttribute("brim-icon", -1); + if (iconSlot > -1) { + HintIconManager.removeHintIcon(player, iconSlot); + } + player.setAttribute("brim-tag", index); + player.setAttribute("brim-icon", HintIconManager.registerHeightHintIcon(player, DISPENSERS[index], 50)); + } - @Override - public boolean enter(Entity entity) { - if (entity instanceof Player) { - Player player = (Player) entity; - player.getInterfaceManager().openOverlay(OVERLAY); - setDispenser(player); - } - return super.enter(entity); - } + @Override + public boolean enter(Entity entity) { + if (entity instanceof Player) { + Player player = (Player) entity; + player.getInterfaceManager().openOverlay(OVERLAY); + setDispenser(player); + } + return super.enter(entity); + } - @Override - public boolean leave(Entity entity, boolean logout) { - if (entity instanceof Player && !logout) { - Player player = (Player) entity; - player.getInterfaceManager().closeOverlay(); - player.removeAttribute("brim-tag"); - player.removeAttribute("brim-tagcount"); - int iconSlot = player.getAttribute("brim-icon", -1); - if (iconSlot > -1) { - HintIconManager.removeHintIcon(player, iconSlot); - player.removeAttribute("brim-icon"); - } - } - return super.enter(entity); - } + @Override + public boolean leave(Entity entity, boolean logout) { + if (entity instanceof Player && !logout) { + Player player = (Player) entity; + player.getInterfaceManager().closeOverlay(); + player.removeAttribute("brim-tag"); + player.removeAttribute("brim-tagcount"); + int iconSlot = player.getAttribute("brim-icon", -1); + if (iconSlot > -1) { + HintIconManager.removeHintIcon(player, iconSlot); + player.removeAttribute("brim-icon"); + } + } + return super.enter(entity); + } - @Override - public boolean interact(Entity entity, Node node, Option option) { - if (node instanceof Scenery) { - Scenery object = (Scenery) node; - if (object.getId() == 3610) { - ClimbActionHandler.climb((Player) entity, Animation.create(828), object.getLocation().transform(0, 0, 3)); - return true; - } - if (object.getId() == 3608 || object.getId() == 3581) { - Player player = (Player) entity; - if (!object.getLocation().equals(DISPENSERS[player.getAttribute("brim-tag", 0)])) { - player.getPacketDispatch().sendMessage("Tag the pillar indicated by the yellow arrow to get an Agility ticket."); - return true; - } - if (player.getAttribute("brim-tagged", false)) { - player.getPacketDispatch().sendMessage("You have already tagged this pillar."); - return true; - } - player.setAttribute("brim-tagged", true); - int tags = player.getAttribute("brim-tagcount", 0) + 1; - player.setAttribute("brim-tagcount", tags); - setVarp(player, 309, 4); - if (tags > 1) { - int amount = 1; - if (!player.getInventory().add(new Item(TICKET.getId(), amount))) { - GroundItemManager.create(new GroundItem(new Item(TICKET.getId(), amount), player.getLocation(), player)); - } - player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 0); - player.getDialogueInterpreter().sendItemMessage(TICKET.getId(), "You have received an Agility Arena Ticket!"); - player.getPacketDispatch().sendMessage("You have received an Agility Arena Ticket!"); - return true; - } - player.getPacketDispatch().sendMessage("You get tickets by tagging more than one pillar in a row, tag the next pillar!"); - player.getDialogueInterpreter().sendDialogue("You get tickets by tagging more than one pillar in a row. Tag the", "next pillar for a ticket!"); - return true; - } - } - return false; - } + @Override + public boolean interact(Entity entity, Node node, Option option) { + if (node instanceof Scenery) { + Scenery object = (Scenery) node; + if (object.getId() == 3610) { + ClimbActionHandler.climb((Player) entity, Animation.create(828), object.getLocation().transform(0, 0, 3)); + return true; + } + if (object.getId() == 3608 || object.getId() == 3581) { + Player player = (Player) entity; + if (!object.getLocation().equals(DISPENSERS[player.getAttribute("brim-tag", 0)])) { + player.getPacketDispatch().sendMessage("Tag the pillar indicated by the yellow arrow to get an Agility ticket."); + return true; + } + if (player.getAttribute("brim-tagged", false)) { + player.getPacketDispatch().sendMessage("You have already tagged this pillar."); + return true; + } + player.setAttribute("brim-tagged", true); + int tags = player.getAttribute("brim-tagcount", 0) + 1; + player.setAttribute("brim-tagcount", tags); + setVarp(player, 309, 4); + if (tags > 1) { + int amount = 1; + if (!player.getInventory().add(new Item(TICKET.getId(), amount))) { + GroundItemManager.create(new GroundItem(new Item(TICKET.getId(), amount), player.getLocation(), player)); + } + player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 0); + player.getDialogueInterpreter().sendItemMessage(TICKET.getId(), "You have received an Agility Arena Ticket!"); + player.getPacketDispatch().sendMessage("You have received an Agility Arena Ticket!"); + return true; + } + player.getPacketDispatch().sendMessage("You get tickets by tagging more than one pillar in a row, tag the next pillar!"); + player.getDialogueInterpreter().sendDialogue("You get tickets by tagging more than one pillar in a row. Tag the", "next pillar for a ticket!"); + return true; + } + } + return false; + } - @Override - public boolean move(Entity e, Location loc, Location dest) { - if (!e.getLocks().isMovementLocked() && e instanceof Player) { - MovementHook hook = LOCATION_TRAPS.get(loc); - if (hook != null) { - e.setDirection(Direction.getLogicalDirection(loc, dest)); - return hook.handle(e, loc); - } - } - return super.move(e, loc, dest); - } + @Override + public boolean move(Entity e, Location loc, Location dest) { + if (!e.getLocks().isMovementLocked() && e instanceof Player) { + MovementHook hook = LOCATION_TRAPS.get(loc); + if (hook != null) { + e.setDirection(Direction.getLogicalDirection(loc, dest)); + return hook.handle(e, loc); + } + } + return super.move(e, loc, dest); + } - @Override - public void locationUpdate(Entity e, Location last) { - if (!e.getLocks().isMovementLocked() && e instanceof Player) { - MovementHook hook = LOCATION_TRAPS.get(e.getLocation()); - if (hook != null) { - if (!hook.handle(e, e.getLocation())) { - if (e.getPulseManager().isMovingPulse()) { - e.getPulseManager().clear(); - } - e.getWalkingQueue().reset(); - } - } - } - } + @Override + public void locationUpdate(Entity e, Location last) { + if (!e.getLocks().isMovementLocked() && e instanceof Player) { + MovementHook hook = LOCATION_TRAPS.get(e.getLocation()); + if (hook != null) { + if (!hook.handle(e, e.getLocation())) { + if (e.getPulseManager().isMovingPulse()) { + e.getPulseManager().clear(); + } + e.getWalkingQueue().reset(); + } + } + } + } - @Override - public void configure() { - registerRegion(11157); - PressurePad pad = new PressurePad(); - LOCATION_TRAPS.put(Location.create(2800, 9579, 3), pad); - LOCATION_TRAPS.put(Location.create(2799, 9579, 3), pad); - LOCATION_TRAPS.put(Location.create(2800, 9557, 3), pad); - LOCATION_TRAPS.put(Location.create(2799, 9557, 3), pad); - LOCATION_TRAPS.put(Location.create(2772, 9585, 3), pad); - LOCATION_TRAPS.put(Location.create(2772, 9584, 3), pad); - FloorSpikes spikes = new FloorSpikes(); - LOCATION_TRAPS.put(Location.create(2800, 9568, 3), spikes); - LOCATION_TRAPS.put(Location.create(2799, 9568, 3), spikes); - LOCATION_TRAPS.put(Location.create(2772, 9552, 3), spikes); - LOCATION_TRAPS.put(Location.create(2772, 9551, 3), spikes); - LOCATION_TRAPS.put(Location.create(2761, 9573, 3), spikes); - LOCATION_TRAPS.put(Location.create(2761, 9574, 3), spikes); - DartTrap dart = new DartTrap(); - LOCATION_TRAPS.put(Location.create(2788, 9557, 3), dart); - LOCATION_TRAPS.put(Location.create(2789, 9557, 3), dart); - LOCATION_TRAPS.put(Location.create(2794, 9573, 3), dart); - LOCATION_TRAPS.put(Location.create(2794, 9574, 3), dart); - LOCATION_TRAPS.put(Location.create(2777, 9568, 3), dart); - LOCATION_TRAPS.put(Location.create(2778, 9568, 3), dart); - SpinningBlades blade = new SpinningBlades(); - LOCATION_TRAPS.put(Location.create(2778, 9579, 3), blade); - LOCATION_TRAPS.put(Location.create(2783, 9574, 3), blade); - LOCATION_TRAPS.put(Location.create(2778, 9557, 3), blade); - BladeTrap trap = new BladeTrap(); - LOCATION_TRAPS.put(Location.create(2788, 9579, 3), trap); - LOCATION_TRAPS.put(Location.create(2789, 9579, 3), trap); - LOCATION_TRAPS.put(Location.create(2783, 9551, 3), trap); - LOCATION_TRAPS.put(Location.create(2783, 9552, 3), trap); - LOCATION_TRAPS.put(Location.create(2761, 9584, 3), trap); - LOCATION_TRAPS.put(Location.create(2761, 9585, 3), trap); - int index = 0; - for (int x = 2761; x < 2815; x += 11) { - for (int y = 9546; y < 9600; y += 11) { - if (x == 2805 && y == 9590) { - continue; - } - DISPENSERS[index++] = Location.create(x, y, 3); - } - } + @Override + public void configure() { + registerRegion(11157); + PressurePad pad = new PressurePad(); + LOCATION_TRAPS.put(Location.create(2800, 9579, 3), pad); + LOCATION_TRAPS.put(Location.create(2799, 9579, 3), pad); + LOCATION_TRAPS.put(Location.create(2800, 9557, 3), pad); + LOCATION_TRAPS.put(Location.create(2799, 9557, 3), pad); + LOCATION_TRAPS.put(Location.create(2772, 9585, 3), pad); + LOCATION_TRAPS.put(Location.create(2772, 9584, 3), pad); + FloorSpikes spikes = new FloorSpikes(); + LOCATION_TRAPS.put(Location.create(2800, 9568, 3), spikes); + LOCATION_TRAPS.put(Location.create(2799, 9568, 3), spikes); + LOCATION_TRAPS.put(Location.create(2772, 9552, 3), spikes); + LOCATION_TRAPS.put(Location.create(2772, 9551, 3), spikes); + LOCATION_TRAPS.put(Location.create(2761, 9573, 3), spikes); + LOCATION_TRAPS.put(Location.create(2761, 9574, 3), spikes); + DartTrap dart = new DartTrap(); + LOCATION_TRAPS.put(Location.create(2788, 9557, 3), dart); + LOCATION_TRAPS.put(Location.create(2789, 9557, 3), dart); + LOCATION_TRAPS.put(Location.create(2794, 9573, 3), dart); + LOCATION_TRAPS.put(Location.create(2794, 9574, 3), dart); + LOCATION_TRAPS.put(Location.create(2777, 9568, 3), dart); + LOCATION_TRAPS.put(Location.create(2778, 9568, 3), dart); + SpinningBlades blade = new SpinningBlades(); + LOCATION_TRAPS.put(Location.create(2778, 9579, 3), blade); + LOCATION_TRAPS.put(Location.create(2783, 9574, 3), blade); + LOCATION_TRAPS.put(Location.create(2778, 9557, 3), blade); + BladeTrap trap = new BladeTrap(); + LOCATION_TRAPS.put(Location.create(2788, 9579, 3), trap); + LOCATION_TRAPS.put(Location.create(2789, 9579, 3), trap); + LOCATION_TRAPS.put(Location.create(2783, 9551, 3), trap); + LOCATION_TRAPS.put(Location.create(2783, 9552, 3), trap); + LOCATION_TRAPS.put(Location.create(2761, 9584, 3), trap); + LOCATION_TRAPS.put(Location.create(2761, 9585, 3), trap); + int index = 0; + for (int x = 2761; x < 2815; x += 11) { + for (int y = 9546; y < 9600; y += 11) { + if (x == 2805 && y == 9590) { + continue; + } + DISPENSERS[index++] = Location.create(x, y, 3); + } + } GameWorld.getPulser().submit(new Pulse(1) { - @Override - public boolean pulse() { - Region r = RegionManager.forId(11157); - if (!r.isActive()) { - return false; - } - if (GameWorld.getTicks() % 100 == 0) { - for (RegionPlane plane : r.getPlanes()) { - for (Player player : plane.getPlayers()) { - setDispenser(player); - } - } - handlePlankSwitching(); - } - int ticks = 3; - if (GameWorld.getTicks() % ticks == 0) { - sawBladeActive = !sawBladeActive; - if (sawBladeActive) { - Scenery object = RegionManager.getObject(3, 2788, 9579); - SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2789, 9579); - SceneryBuilder.replace(object, object.transform(0), ticks); + @Override + public boolean pulse() { + Region r = RegionManager.forId(11157); + if (!r.isActive()) { + return false; + } + if (GameWorld.getTicks() % 100 == 0) { + for (int z = 0; z < 4; z++) { + for (Player player : r.assemblePlayerList(z)) { + if (player != null) { + setDispenser(player); + } + } + } + handlePlankSwitching(); + } + int ticks = 3; + if (GameWorld.getTicks() % ticks == 0) { + sawBladeActive = !sawBladeActive; + if (sawBladeActive) { + Scenery object = RegionManager.getObject(3, 2788, 9579); + SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); + object = RegionManager.getObject(3, 2789, 9579); + SceneryBuilder.replace(object, object.transform(0), ticks); - object = RegionManager.getObject(3, 2783, 9551); - SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2783, 9552); - SceneryBuilder.replace(object, object.transform(0), ticks); + object = RegionManager.getObject(3, 2783, 9551); + SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); + object = RegionManager.getObject(3, 2783, 9552); + SceneryBuilder.replace(object, object.transform(0), ticks); - object = RegionManager.getObject(3, 2761, 9584); - SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2761, 9585); - SceneryBuilder.replace(object, object.transform(0), ticks); - } - } - return false; - } - }); - } + object = RegionManager.getObject(3, 2761, 9584); + SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); + object = RegionManager.getObject(3, 2761, 9585); + SceneryBuilder.replace(object, object.transform(0), ticks); + } + } + return false; + } + }); + } - /** - * Switches the plank states. - */ - private static void handlePlankSwitching() { - boolean[] available = new boolean[3]; - for (int i = 0; i < 1 + RandomFunction.randomize(2); i++) { - available[RandomFunction.randomize(3)] = true; - } - for (int i = 0; i < 3; i++) { - boolean avail = available[i]; - for (PlankSet set : PlankSet.values()) { - Location l = set.entrance[i]; - for (int x = 1; x < set.exit[i].getX() - l.getX(); x++) { - Scenery object = RegionManager.getObject(l.transform(x, 0, 0)); - if(object != null) - SceneryBuilder.replace(object, object.transform(avail ? 3573 : 3576)); - } - RegionManager.getObject(set.entrance[i]).setCharge(avail ? 1000 : 500); - RegionManager.getObject(set.exit[i]).setCharge(avail ? 1000 : 500); - } - } - } + /** + * Switches the plank states. + */ + private static void handlePlankSwitching() { + boolean[] available = new boolean[3]; + for (int i = 0; i < 1 + RandomFunction.randomize(2); i++) { + available[RandomFunction.randomize(3)] = true; + } + for (int i = 0; i < 3; i++) { + boolean avail = available[i]; + for (PlankSet set : PlankSet.values()) { + Location l = set.entrance[i]; + for (int x = 1; x < set.exit[i].getX() - l.getX(); x++) { + Scenery object = RegionManager.getObject(l.transform(x, 0, 0)); + if(object != null) + SceneryBuilder.replace(object, object.transform(avail ? 3573 : 3576)); + } + RegionManager.getObject(set.entrance[i]).setCharge(avail ? 1000 : 500); + RegionManager.getObject(set.exit[i]).setCharge(avail ? 1000 : 500); + } + } + } - /** - * The plank obstacles. - * - * @author Emperor - */ - private static enum PlankSet { - FIRST(new Location[]{Location.create(2797, 9591, 3), Location.create(2797, 9590, 3), Location.create(2797, 9589, 3)}, new Location[]{Location.create(2802, 9591, 3), Location.create(2802, 9590, 3), Location.create(2802, 9589, 3)}), SECOND(new Location[]{Location.create(2764, 9558, 3), Location.create(2764, 9557, 3), Location.create(2764, 9556, 3)}, new Location[]{Location.create(2769, 9558, 3), Location.create(2769, 9557, 3), Location.create(2769, 9556, 3)}); + /** + * The plank obstacles. + * + * @author Emperor + */ + private static enum PlankSet { + FIRST(new Location[]{Location.create(2797, 9591, 3), Location.create(2797, 9590, 3), Location.create(2797, 9589, 3)}, new Location[]{Location.create(2802, 9591, 3), Location.create(2802, 9590, 3), Location.create(2802, 9589, 3)}), SECOND(new Location[]{Location.create(2764, 9558, 3), Location.create(2764, 9557, 3), Location.create(2764, 9556, 3)}, new Location[]{Location.create(2769, 9558, 3), Location.create(2769, 9557, 3), Location.create(2769, 9556, 3)}); - /** - * Constructs a new {@code PlankSet} {@code Object}. - * - * @param entrance The entrance locations for each plank. - * @param exit The exit locations for each plank. - */ - private PlankSet(Location[] entrance, Location[] exit) { - this.entrance = entrance; - this.exit = exit; - } + /** + * Constructs a new {@code PlankSet} {@code Object}. + * + * @param entrance The entrance locations for each plank. + * @param exit The exit locations for each plank. + */ + private PlankSet(Location[] entrance, Location[] exit) { + this.entrance = entrance; + this.exit = exit; + } - /** - * The entrance location of the plank. - */ - Location[] entrance; + /** + * The entrance location of the plank. + */ + Location[] entrance; - /** - * The exit location of the plank. - */ - Location[] exit; - } + /** + * The exit location of the plank. + */ + Location[] exit; + } - @Override - public Plugin newInstance(Object arg) throws Throwable { - ZoneBuilder.configure(this); - return this; - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + ZoneBuilder.configure(this); + return this; + } - @Override - public Object fireEvent(String identifier, Object... args) { - return null; - } + @Override + public Object fireEvent(String identifier, Object... args) { + return null; + } } diff --git a/Server/src/main/content/global/skill/construction/BuildRoomDialogue.java b/Server/src/main/content/global/skill/construction/BuildRoomDialogue.java index b74e99cb3..9e9dde9df 100644 --- a/Server/src/main/content/global/skill/construction/BuildRoomDialogue.java +++ b/Server/src/main/content/global/skill/construction/BuildRoomDialogue.java @@ -241,7 +241,7 @@ public final class BuildRoomDialogue extends DialoguePlugin { } int rotation = directions[index].toInteger(); boundaries.clear(); - Location base = player.getViewport().getRegion().getBaseLocation().transform(roomX << 3, roomY << 3, player.getLocation().getZ()); + Location base = player.getLocation().getRegion().getBaseLocation().transform(roomX << 3, roomY << 3, player.getLocation().getZ()); for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { Scenery[] objects = room.getChunk().getObjects(x, y); diff --git a/Server/src/main/content/global/skill/construction/BuildingUtils.java b/Server/src/main/content/global/skill/construction/BuildingUtils.java index 2ee636337..158d7abbb 100644 --- a/Server/src/main/content/global/skill/construction/BuildingUtils.java +++ b/Server/src/main/content/global/skill/construction/BuildingUtils.java @@ -8,10 +8,7 @@ import core.game.node.item.Item; import core.game.node.scenery.Scenery; import core.game.node.scenery.SceneryBuilder; import core.game.system.task.Pulse; -import core.game.world.map.BuildRegionChunk; -import core.game.world.map.Direction; -import core.game.world.map.Location; -import core.game.world.map.Region; +import core.game.world.map.*; import core.game.world.update.flag.context.Animation; import core.net.packet.PacketRepository; import core.net.packet.context.ContainerContext; @@ -250,7 +247,7 @@ public final class BuildingUtils { if (reg == null) { continue; } - BuildRegionChunk chunk = (BuildRegionChunk) reg.getPlanes()[plane % 3].getChunks()[l.getChunkX()][l.getChunkY()]; + RegionChunk chunk = reg.getChunks()[l.getChunkX()][l.getChunkY()][plane % 3]; Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY()); for (Scenery o : objects) { if (o != null && o.getType() == object.getType()) { @@ -284,14 +281,15 @@ public final class BuildingUtils { hotspot.setDecorationIndex(decIndex); break; case RECURSIVE: - BuildRegionChunk chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()]; + RegionChunk chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y); if (h != null) { h.setDecorationIndex(decIndex); int objectId = hotspot.getHotspot().getObjectId(style); - Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId)); + int index = chunk.getIndex(x, y, objectId, -1); + Scenery o = chunk.getObjects()[index][x][y]; if (o != null && objectId == o.getId()) { SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getDecorations()[decIndex].getObjectId(style))); } @@ -301,7 +299,7 @@ public final class BuildingUtils { break; case LINKED: BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot()); - chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()]; + chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { for (BuildHotspot bh : linkedHotspots) { @@ -309,7 +307,8 @@ public final class BuildingUtils { if (h != null) { h.setDecorationIndex(decIndex); int objectId = bh.getObjectId(style); - Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId)); + int index = chunk.getIndex(x, y, objectId, -1); + Scenery o = chunk.getObjects()[index][x][y]; if (o != null && objectId == o.getId()) { SceneryBuilder.replace(o, o.transform(bh.getDecorations()[decIndex].getObjectId(style))); } @@ -385,7 +384,7 @@ public final class BuildingUtils { if (reg == null) { continue; } - BuildRegionChunk chunk = (BuildRegionChunk) reg.getPlanes()[plane % 3].getChunks()[l.getChunkX()][l.getChunkY()]; + RegionChunk chunk = reg.getChunks()[l.getChunkX()][l.getChunkY()][plane % 3]; Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY()); for (Scenery o : objects) { if (o != null && o.getType() == object.getType()) { @@ -417,13 +416,14 @@ public final class BuildingUtils { hotspot.setDecorationIndex(-1); break; case RECURSIVE: - BuildRegionChunk chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()]; + RegionChunk chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y); if (h != null) { int objectId = hotspot.getHotspot().getDecorations()[h.getDecorationIndex()].getObjectId(style); - Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId)); + int index = chunk.getIndex(x, y, objectId, -1); + Scenery o = chunk.getObjects()[index][x][y]; h.setDecorationIndex(-1); if (o != null && objectId == o.getId()) { SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getObjectId(style))); @@ -434,14 +434,15 @@ public final class BuildingUtils { break; case LINKED: BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot()); - chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()]; + chunk = region.getChunks()[l.getChunkX()][l.getChunkY()][l.getZ()]; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { for (BuildHotspot bh : linkedHotspots) { Hotspot h = room.getHotspot(bh, x, y); if (h != null) { int objectId = bh.getDecorations()[h.getDecorationIndex()].getObjectId(style); - Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId)); + int index = chunk.getIndex(x, y, objectId, -1); + Scenery o = chunk.getObjects()[index][x][y]; h.setDecorationIndex(-1); if (o != null && objectId == o.getId()) { SceneryBuilder.replace(o, o.transform(bh.getObjectId(style))); diff --git a/Server/src/main/content/global/skill/construction/HouseManager.java b/Server/src/main/content/global/skill/construction/HouseManager.java index 4db8e8191..884ce5a7f 100644 --- a/Server/src/main/content/global/skill/construction/HouseManager.java +++ b/Server/src/main/content/global/skill/construction/HouseManager.java @@ -10,6 +10,7 @@ import core.game.world.map.*; import core.game.world.map.build.DynamicRegion; import core.game.world.map.zone.ZoneBorders; import core.game.world.map.zone.ZoneBuilder; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.tools.Log; import org.jetbrains.annotations.NotNull; @@ -20,6 +21,7 @@ import core.game.world.GameWorld; import org.rs09.consts.Sounds; import java.awt.*; +import java.util.ArrayList; import static core.api.ContentAPIKt.*; import static core.api.regionspec.RegionSpecificationKt.fillWith; @@ -195,8 +197,8 @@ public final class HouseManager { } private void updateVarbits(Player player, boolean build) { - setVarp(player, 261, build ? 1 : 0); - setVarp(player, 262, getRoomAmount()); + setVarp(player, 261, build ? 1 : 0); + setVarp(player, 262, getRoomAmount()); } private void unlockMusicTrack(Player player) { @@ -241,13 +243,13 @@ public final class HouseManager { * Reloads the house. * @param player The player. * @param buildingMode If building mode should be enabled. - * NOTE: I think we should avoid this method, it might be causing some issues. It's actually really suspicious... + * NOTE: I think we should avoid this method, it might be causing some issues. It's actually really suspicious... */ public void reload(Player player, boolean buildingMode) { int diffX = player.getLocation().getLocalX(); int diffY = player.getLocation().getLocalY(); int diffZ = player.getLocation().getZ(); - boolean inDungeon = player.getViewport().getRegion() == dungeonRegion; + boolean inDungeon = player.getLocation().getRegion() == dungeonRegion; this.buildingMode = buildingMode; construct(); Location newLoc = (dungeonRegion == null ? houseRegion : (inDungeon ? dungeonRegion : houseRegion)).getBaseLocation().transform(diffX,diffY,diffZ); @@ -260,22 +262,17 @@ public final class HouseManager { */ public void expelGuests(Player player) { if (isLoaded()) { - for (RegionPlane plane : houseRegion.getPlanes()) { - for (Player p : plane.getPlayers()) { + for (int z = 0; z < 4; z++) { + ArrayList players = new ArrayList<>(houseRegion.assemblePlayerList(z)); + if (dungeonRegion != null) { + players.addAll(dungeonRegion.assemblePlayerList(z)); + } + for (Player p : players) { if (p != player) { leave(p); } } } - if (dungeonRegion != null) { - for (RegionPlane plane : dungeonRegion.getPlanes()) { - for (Player p : plane.getPlayers()) { - if (p != player) { - leave(p); - } - } - } - } } } @@ -375,7 +372,6 @@ public final class HouseManager { ZoneBorders borders = DynamicRegion.reserveArea(8,8); DynamicRegion region = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6); region.setBorders(borders); - region.setUpdateAllPlanes(true); region.setBuild(true); RegionManager.addRegion(region.getId(), region); return region; @@ -393,12 +389,12 @@ public final class HouseManager { } @Override - public BuildRegionChunk getChunk(int x, int y, int plane, @NotNull DynamicRegion dyn) { - return rooms[plane][x][y].getChunk().copy(dyn.getPlanes()[plane]); + public @Nullable RegionChunk getChunk(int x, int y, int plane, @NotNull DynamicRegion dyn) { + return rooms[plane][x][y].getChunk().copy(); } @Override - public void afterSetting(@Nullable BuildRegionChunk chunk, int x, int y, int plane, @NotNull DynamicRegion dyn) { + public void afterSetting(@Nullable RegionChunk chunk, int x, int y, int plane, @NotNull DynamicRegion dyn) { rooms[plane][x][y].loadDecorations(dyn != manager.dungeonRegion ? plane : 3, chunk, manager); } } @@ -406,8 +402,8 @@ public final class HouseManager { private void prepareHouseChunks(HousingStyle style, DynamicRegion target, boolean buildingMode, Room[][][] rooms) { Region from = RegionManager.forId(style.getRegionId()); Region.load(from, true); - RegionChunk defaultChunk = from.getPlanes()[style.getPlane()].getRegionChunk(1, 0); - RegionChunk defaultSkyChunk = from.getPlanes()[1].getRegionChunk(0,0); + RegionChunk defaultChunk = from.getChunks()[1][0][style.getPlane()]; + RegionChunk defaultSkyChunk = from.getChunks()[0][0][1]; RoomLoadContract loadRooms = new RoomLoadContract(this, buildingMode, rooms); RegionSpecification spec = new RegionSpecification( @@ -430,7 +426,7 @@ public final class HouseManager { private void prepareDungeonChunks(HousingStyle style, DynamicRegion target, DynamicRegion house, boolean buildingMode, Room[][] rooms) { Region from = RegionManager.forId(style.getRegionId()); Region.load(from, true); - RegionChunk defaultChunk = from.getPlanes()[style.getPlane()].getRegionChunk(3, 0); + RegionChunk defaultChunk = from.getChunks()[3][0][style.getPlane()]; RoomLoadContract loadRooms = new RoomLoadContract(this, buildingMode, new Room[][][]{rooms}); RegionSpecification spec = new RegionSpecification( @@ -688,7 +684,7 @@ public final class HouseManager { * @return {@code True} if so. */ public boolean isInHouse(Player player) { - return isLoaded() && (player.getViewport().getRegion() == houseRegion || player.getViewport().getRegion() == dungeonRegion); + return isLoaded() && (player.getLocation().getRegion() == houseRegion || player.getLocation().getRegion() == dungeonRegion); } /** @@ -697,7 +693,7 @@ public final class HouseManager { * @return {@code True} if so. */ public static boolean isInDungeon(Player player) { - return player.getViewport().getRegion() == player.getHouseManager().dungeonRegion; + return player.getLocation().getRegion() == player.getHouseManager().dungeonRegion; } /** diff --git a/Server/src/main/content/global/skill/construction/HousingStyle.java b/Server/src/main/content/global/skill/construction/HousingStyle.java index eace0e7bb..b9df17417 100644 --- a/Server/src/main/content/global/skill/construction/HousingStyle.java +++ b/Server/src/main/content/global/skill/construction/HousingStyle.java @@ -12,36 +12,35 @@ import java.util.Arrays; */ public enum HousingStyle { - // open door ids are doorId + 1 - - BASIC_WOOD (1, 5000, 7503, 0, 13100, 13101, 13098, Decoration.BASIC_WOOD_WINDOW), - BASIC_STONE (10, 5000, 7503, 1, 13094, 13096, 1902, Decoration.BASIC_STONE_WINDOW), - WHITEWASHED_STONE (20, 7500, 7503, 2, 13006, 13007, 1415, Decoration.WHITEWASHED_STONE_WINDOW), - FREMENNIK_STYLE_WOOD(30, 10000, 7503, 3, 13109, 13107, 13111, Decoration.FREMENNIK_WINDOW), - TROPICAL_WOOD (40, 15000, 7759, 0, 13016, 13015, 13011, Decoration.TROPICAL_WOOD_WINDOW), - FANCY_STONE (50, 25000, 7759, 1, 13119, 13118, 13116, Decoration.FANCY_STONE_WINDOW); + // open door ids are doorId + 1 + BASIC_WOOD (1, 5000, 7503, 0, 13100, 13101, 13098, 13098, Decoration.BASIC_WOOD_WINDOW), + BASIC_STONE (10, 5000, 7503, 1, 13094, 13096, 1902, 13090, Decoration.BASIC_STONE_WINDOW), + WHITEWASHED_STONE (20, 7500, 7503, 2, 13006, 13007, 1415, 1415, Decoration.WHITEWASHED_STONE_WINDOW), + FREMENNIK_STYLE_WOOD(30, 10000, 7503, 3, 13109, 13107, 13111, 13111, Decoration.FREMENNIK_WINDOW), + TROPICAL_WOOD (40, 15000, 7759, 0, 13016, 13015, 13011, 13011, Decoration.TROPICAL_WOOD_WINDOW), + FANCY_STONE (50, 25000, 7759, 1, 13119, 13118, 13116, 13116, Decoration.FANCY_STONE_WINDOW); - /** - * Array of all Dungeon Wall IDs. - * From Region 7503, Location.create(1898, 5084, 0) - */ - private static final int[] DUNGEON_WALL_IDS = { - 13019, 13020, 13021, 13022, 13023, 13024, 13025, 13026, 13027, 13028, - 13029, 13030, 13031, 13032, 13033, 13034, 13035, 13036, 13037, 13046, - 13048, 13049, 13050, 13051, 13055, 13056, 13058, 13059, 13060, 13061, - 13062, 13063, 13065, 13066, 13067, 13068, 13069, 13070, 13072, 13073, - 13074, 13075, 13076, 13077, 13079, 13080, 13081, 13082, 13083, 13084, - 13086, 13087, 13088, 13089 - }; + /** + * Array of all Dungeon Wall IDs. + * From Region 7503, Location.create(1898, 5084, 0) + */ + private static final int[] DUNGEON_WALL_IDS = { + 13019, 13020, 13021, 13022, 13023, 13024, 13025, 13026, 13027, 13028, + 13029, 13030, 13031, 13032, 13033, 13034, 13035, 13036, 13037, 13046, + 13048, 13049, 13050, 13051, 13055, 13056, 13058, 13059, 13060, 13061, + 13062, 13063, 13065, 13066, 13067, 13068, 13069, 13070, 13072, 13073, + 13074, 13075, 13076, 13077, 13079, 13080, 13081, 13082, 13083, 13084, + 13086, 13087, 13088, 13089 + }; - /** - * Checks if the provided ID is a dungeon wall. - * @param id The object ID. - * @return {@code true} if it's a dungeon wall. - */ - public static boolean isDungeonWall(int id) { - return Arrays.binarySearch(DUNGEON_WALL_IDS, id) >= 0; - } + /** + * Checks if the provided ID is a dungeon wall. + * @param id The object ID. + * @return {@code true} if it's a dungeon wall. + */ + public static boolean isDungeonWall(int id) { + return Arrays.binarySearch(DUNGEON_WALL_IDS, id) >= 0; + } /** * The level required. @@ -77,21 +76,26 @@ public enum HousingStyle { * The wall id. */ private final int wallId; + + /** + * A second wall id, used for walls behind fireplaces in some house styles. + * Only used for the basic stone house style, who knows why. Same as wallId for other house styles. + */ + private final int secondWallId; /** * The window style */ private final Decoration window; - /** - * Checks if the player has the level. - * - * @param player the player. - * @return {@code True} if so. - */ - public boolean hasLevel(Player player) { - return player.getSkills().getStaticLevel(Skills.CONSTRUCTION) >= levelRequirement; - } + /** + * Checks if the player has the level. + * @param player the player. + * @return {@code True} if so. + */ + public boolean hasLevel(Player player) { + return player.getSkills().getStaticLevel(Skills.CONSTRUCTION) >= levelRequirement; + } /** * Constructs a new {@code HousingStyle} {@code Object} @@ -100,8 +104,11 @@ public enum HousingStyle { * @param regionId The region id for this style. * @param plane The plane for this style. * @param doorId The door object id used in this style. + * @param secondDoorId The second-door object id used in this style. + * @param wallId The wall object id used in this style. + * @param secondWallId The second-wall object id used in this style. */ - private HousingStyle(int level, int cost, int regionId, int plane, int doorId, int secondDoorId, int wallId, Decoration window) { + HousingStyle(int level, int cost, int regionId, int plane, int doorId, int secondDoorId, int wallId, int secondWallId, Decoration window) { this.levelRequirement = level; this.cost = cost; this.regionId = regionId; @@ -109,6 +116,7 @@ public enum HousingStyle { this.doorId = doorId; this.secondDoorId = secondDoorId; this.wallId = wallId; + this.secondWallId = secondWallId; this.window = window; } @@ -159,7 +167,15 @@ public enum HousingStyle { public int getWallId() { return wallId; } - + + /** + * Gets the second wall used in this style. + * @return The wall object id. + */ + public int getSecondWallId() { + return secondWallId; + } + /** * Gets the window id for this style of house * @return The windows object id @@ -175,4 +191,4 @@ public enum HousingStyle { public int getSecondDoorId() { return secondDoorId; } -} \ No newline at end of file +} diff --git a/Server/src/main/content/global/skill/construction/Room.java b/Server/src/main/content/global/skill/construction/Room.java index ac7b56cec..28f068ac4 100644 --- a/Server/src/main/content/global/skill/construction/Room.java +++ b/Server/src/main/content/global/skill/construction/Room.java @@ -1,6 +1,5 @@ package content.global.skill.construction; - import core.game.node.entity.player.Player; import core.game.node.scenery.Constructed; import core.game.node.scenery.Scenery; @@ -16,7 +15,6 @@ import static core.api.ContentAPIKt.log; * */ public final class Room { - /** * The default room type. */ @@ -95,7 +93,7 @@ public final class Room { public void decorate(HousingStyle style) { Region region = RegionManager.forId(style.getRegionId()); Region.load(region, true); - chunk = region.getPlanes()[style.getPlane()].getRegionChunk(properties.getChunkX(), properties.getChunkY()); + chunk = region.getChunks()[properties.getChunkX()][properties.getChunkY()][style.getPlane()]; } /** @@ -126,28 +124,24 @@ public final class Room { * Loads all the decorations. * @param housePlane The plane. * @param chunk The chunk used in the dynamic region. - */ - public void loadDecorations(int housePlane, BuildRegionChunk chunk, HouseManager house) { - for (int i = 0; i < hotspots.length; i++) { - Hotspot spot = hotspots[i]; + */ + public void loadDecorations(int housePlane, RegionChunk chunk, HouseManager house) { + for (Hotspot spot : hotspots) { int x = spot.getChunkX(); int y = spot.getChunkY(); - if (spot.getHotspot() == null) { - continue; - } - int index = chunk.getIndex(x, y, spot.getHotspot().getObjectId(house.getStyle())); - Scenery[][] objects = chunk.getObjects(index); + int id = spot.getHotspot().getObjectId(house.getStyle()); + int index = chunk.getIndex(x, y, id, -1); + Scenery[][] objects = chunk.getObjects()[index]; Scenery object = objects[x][y]; if (object != null && object.getId() == spot.getHotspot().getObjectId(house.getStyle())) { if (spot.getDecorationIndex() > -1 && spot.getDecorationIndex() < spot.getHotspot().getDecorations().length) { - int id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getObjectId(house.getStyle()); + id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getObjectId(house.getStyle()); if (spot.getHotspot().getType() == BuildHotspotType.CREST) { id += house.getCrest().ordinal(); } SceneryBuilder.replace(object, object.transform(id, object.getRotation(), chunk.getCurrentBase().transform(x, y, 0))); - } - else if (object.getId() == BuildHotspot.WINDOW.getObjectId(house.getStyle()) || (!house.isBuildingMode() && object.getId() == BuildHotspot.CHAPEL_WINDOW.getObjectId(house.getStyle()))) { - chunk.add(object.transform(house.getStyle().getWindowStyle().getObjectId(house.getStyle()), object.getRotation(), object.getType())); + } else if (object.getId() == BuildHotspot.WINDOW.getObjectId(house.getStyle()) || (!house.isBuildingMode() && object.getId() == BuildHotspot.CHAPEL_WINDOW.getObjectId(house.getStyle()))) { + SceneryBuilder.replace(object, object.transform(house.getStyle().getWindowStyle().getObjectId(house.getStyle()), object.getRotation(), object.getType())); } int[] pos = RegionChunk.getRotatedPosition(x, y, object.getSizeX(), object.getSizeY(), 0, rotation.toInteger()); spot.setCurrentX(pos[0]); @@ -159,30 +153,29 @@ public final class Room { } if (!house.isBuildingMode()) { placeDoors(housePlane, house, chunk); - removeHotspots(housePlane, house, chunk); + removeHotspots(house, chunk); } } /** * Removes the building hotspots from the room. - * @param housePlane The room's plane in house. * @param house The house manager. * @param chunk The region chunk used. */ - private void removeHotspots(int housePlane, HouseManager house, BuildRegionChunk chunk) { + private void removeHotspots(HouseManager house, RegionChunk chunk) { if (properties.isRoof()) return; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { - for (int i = 0; i < BuildRegionChunk.ARRAY_SIZE; i++) { - Scenery object = chunk.get(x, y, i); + for (int i = 0; i < RegionChunk.ARRAY_SIZE; i++) { + Scenery object = chunk.getObjects()[i][x][y]; if (object != null) { - int id = object.getId(); - boolean isBuilt = object instanceof Constructed; - boolean isWall = HousingStyle.isDungeonWall(id) || id == house.getStyle().getWallId(); - boolean isDoor = id == house.getStyle().getDoorId() || id == house.getStyle().getSecondDoorId(); - if (!isBuilt && !isWall && !isDoor) { + int id = object.getId(); + boolean isBuilt = !object.getDefinition().hasAction("build"); + boolean isGround = object.getType() == 22 && !object.getDefinition().hasOptions(); + boolean isWall = HousingStyle.isDungeonWall(id) || id == house.getStyle().getWallId() || id == house.getStyle().getSecondWallId(); + boolean isDoor = id == house.getStyle().getDoorId() || id == house.getStyle().getSecondDoorId(); + if (!isBuilt && !isGround && !isWall && !isDoor) { SceneryBuilder.remove(object); - chunk.remove(object); } } } @@ -197,14 +190,14 @@ public final class Room { * @param house The house manager. * @param chunk The region chunk used. */ - private void placeDoors(int housePlane, HouseManager house, BuildRegionChunk chunk) { + private void placeDoors(int housePlane, HouseManager house, RegionChunk chunk) { Room[][][] rooms = house.getRooms(); int rx = chunk.getCurrentBase().getChunkX(); int ry = chunk.getCurrentBase().getChunkY(); - for (int i = 0; i < BuildRegionChunk.ARRAY_SIZE; i++) { + for (int i = 0; i < RegionChunk.ARRAY_SIZE; i++) { for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { - Scenery object = chunk.get(x, y, i); + Scenery object = chunk.getObjects()[i][x][y]; if (object != null && BuildingUtils.isDoorHotspot(object)) { boolean edge = false; Room otherRoom = null; @@ -274,7 +267,7 @@ public final class Room { return object.getId() % 2 != 0 ? house.getStyle().getDoorId() : house.getStyle().getSecondDoorId(); } } - return room.getProperties().isDungeon() ? 13065 : house.getStyle().getWallId(); + return room.getProperties().isDungeon() ? 13065 : house.getStyle().getWallId(); //otherWallId is only used behind fireplaces } /** @@ -423,5 +416,4 @@ public final class Room { public Direction getRotation() { return rotation; } - } diff --git a/Server/src/main/content/global/skill/construction/RoomProperties.java b/Server/src/main/content/global/skill/construction/RoomProperties.java index 80bc6e6ed..f4199d46f 100644 --- a/Server/src/main/content/global/skill/construction/RoomProperties.java +++ b/Server/src/main/content/global/skill/construction/RoomProperties.java @@ -920,7 +920,7 @@ public enum RoomProperties { public boolean[] getExits() { Region region = RegionManager.forId(7503); Region.load(region, true); - RegionChunk chunk = region.getPlanes()[0].getRegionChunk(chunkX, chunkY); + RegionChunk chunk = region.getChunks()[chunkX][chunkY][0]; return new boolean[] { isExit(chunk, 7, 3), isExit(chunk, 3, 0), isExit(chunk, 0, 3), isExit(chunk, 3, 7) }; } diff --git a/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java b/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java index 8c22d84ab..73a4cb12c 100644 --- a/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java +++ b/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java @@ -29,18 +29,18 @@ public final class StaircasePlugin extends OptionHandler { public Plugin newInstance(Object arg) throws Throwable { ClassScanner.definePlugin(new BuildDialogue()); ClassScanner.definePlugin(new ClimbPohLadder()); - // 13497 - 13502 are normal stairs - // 13503 - 13506 are spiral stairs + // 13497 - 13502 are normal stairs + // 13503 - 13506 are spiral stairs for (int i = 13497; i <= 13506; i++) { SceneryDefinition.forId(i).getHandlers().put("option:climb", this); SceneryDefinition.forId(i).getHandlers().put("option:climb-up", this); SceneryDefinition.forId(i).getHandlers().put("option:climb-down", this); SceneryDefinition.forId(i).getHandlers().put("option:remove-room", this); } - // 13409 is dungeon entrance + // 13409 is dungeon entrance SceneryDefinition.forId(13409).getHandlers().put("option:enter", this); SceneryDefinition.forId(13409).getHandlers().put("option:remove-room", this); - // 13328 - 13330 are dungeon ladders + // 13328 - 13330 are dungeon ladders for (int id = 13328; id <= 13330; id++) { SceneryDefinition.forId(id).getHandlers().put("option:climb", this); SceneryDefinition.forId(id).getHandlers().put("option:remove-room", this); @@ -74,43 +74,43 @@ public final class StaircasePlugin extends OptionHandler { return true; case "remove-room": - int currentZ = player.getLocation().getZ(); - int chunkX = player.getLocation().getChunkX(); - int chunkY = player.getLocation().getChunkY(); + int currentZ = player.getLocation().getZ(); + int chunkX = player.getLocation().getChunkX(); + int chunkY = player.getLocation().getChunkY(); - // must be in building mode - if(!player.getHouseManager().isBuildingMode()) { - player.getPacketDispatch().sendMessage("You can only do this in building mode."); - return true; - } + // must be in building mode + if(!player.getHouseManager().isBuildingMode()) { + player.getPacketDispatch().sendMessage("You can only do this in building mode."); + return true; + } - // if you're in the dungeon, try and remove the room at Z = 0 from the house region. - if (HouseManager.isInDungeon(player)) { - player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, 0); + // if you're in the dungeon, try and remove the room at Z = 0 from the house region. + if (HouseManager.isInDungeon(player)) { + player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, 0); - // From ground floor (z=0), stairs could lead to 1st floor (z=1) or the dungeon (z=3) - } else { - // garden dungeon entrance and oubliette ladders don't need a height selection - if(node.getId() == 13409 || node.getId() == 13675 || node.getId() == 13676 || node.getId() == 13677 || node.getId() == 13678 || node.getId() == 13679 || node.getId() == 13680) { - player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, 3); - } else { - player.getDialogueInterpreter().sendOptions("Remove which room?", "Room Above", "Room Below", "Cancel"); - player.getDialogueInterpreter().addAction((interId, btn) -> { - if (btn == 2) { // Above - player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, currentZ + 1); - } else if (btn == 3) { // Below - if (currentZ - 1 == -1) { - player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, 3); - } else { - player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, currentZ - 1); - } + // From ground floor (z=0), stairs could lead to 1st floor (z=1) or the dungeon (z=3) + } else { + // garden dungeon entrance and oubliette ladders don't need a height selection + if(node.getId() == 13409 || node.getId() == 13675 || node.getId() == 13676 || node.getId() == 13677 || node.getId() == 13678 || node.getId() == 13679 || node.getId() == 13680) { + player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, 3); + } else { + player.getDialogueInterpreter().sendOptions("Remove which room?", "Room Above", "Room Below", "Cancel"); + player.getDialogueInterpreter().addAction((interId, btn) -> { + if (btn == 2) { // Above + player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, currentZ + 1); + } else if (btn == 3) { // Below + if (currentZ - 1 == -1) { + player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, 3); + } else { + player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, currentZ - 1); + } - } - }); - } + } + }); + } - } - return true; + } + return true; case "climb": if (HouseManager.isInDungeon(player)) { @@ -151,7 +151,7 @@ public final class StaircasePlugin extends OptionHandler { if (plane < 0) { //Dungeon plane = 3; } - else if (player.getViewport().getRegion() == house.getDungeonRegion() && plane == 1) {//going up + else if (player.getLocation().getRegion() == house.getDungeonRegion() && plane == 1) {//going up plane = 0; } Room room = house.getRooms()[plane][roomX][roomY]; @@ -165,7 +165,7 @@ public final class StaircasePlugin extends OptionHandler { } } else { Location destination = l.transform(0, 0, z); - if (player.getViewport().getRegion() == house.getDungeonRegion()) { + if (player.getLocation().getRegion() == house.getDungeonRegion()) { destination = house.getHouseRegion().getBaseLocation().transform(l.getLocalX(), l.getLocalY(), 0); } else if (plane == 3) { @@ -417,7 +417,7 @@ public final class StaircasePlugin extends OptionHandler { for (Direction d : dirs) { if (d == room.getRotation()) { r.setRotation(d); - // todo this just puts a default set of stairs in the dungeon. The below code works for skill/quest hall, but not a dungeon entrance. + // todo this just puts a default set of stairs in the dungeon. The below code works for skill/quest hall, but not a dungeon entrance. //Hotspot stairs = room.getStairs(); //int index = stairs != null ? stairs.getDecorationIndex() : -1; BuildingUtils.buildRoom(player, r, plane, roomX, roomY, r.getExits(), true); diff --git a/Server/src/main/content/global/skill/construction/npc/HouseServantDialogue.java b/Server/src/main/content/global/skill/construction/npc/HouseServantDialogue.java index ddb967ebe..412f96da3 100644 --- a/Server/src/main/content/global/skill/construction/npc/HouseServantDialogue.java +++ b/Server/src/main/content/global/skill/construction/npc/HouseServantDialogue.java @@ -525,7 +525,7 @@ public class HouseServantDialogue extends DialoguePlugin { @Override public boolean pulse() { - if (player == null || player.getHouseManager().getHouseRegion() != player.getViewport().getRegion()) { //TODO: Check if in dungeon? + if (player == null || player.getHouseManager().getHouseRegion() != player.getLocation().getRegion()) { //TODO: Check if in dungeon? return true; } int amt = player.getBank().getAmount(item.getId()); diff --git a/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java b/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java index ae652f9a8..b7efeae3a 100644 --- a/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java +++ b/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java @@ -20,62 +20,62 @@ import static core.api.ContentAPIKt.playAudio; */ public final class SpinningPulse extends SkillPulse { - /** - * Represents the animation to use. - */ - private static final Animation ANIMATION = new Animation(896); + /** + * Represents the animation to use. + */ + private static final Animation ANIMATION = new Animation(896); - /** - * Represents the type of spinning item. - */ - private final SpinningItem type; + /** + * Represents the type of spinning item. + */ + private final SpinningItem type; - /** - * Represents the amount to spin. - */ - private int ammount; + /** + * Represents the amount to spin. + */ + private int ammount; - /** - * Represents the ticks passed. - */ - private int ticks; + /** + * Represents the ticks passed. + */ + private int ticks; - /** - * Constructs a new {@code SpinningPulse.java} {@Code Object} - * - * @param player - * @param node - */ - public SpinningPulse(Player player, Item node, int ammount, SpinningItem def) { - super(player, node); - this.type = def; - this.ammount = ammount; - } + /** + * Constructs a new {@code SpinningPulse.java} {@Code Object} + * + * @param player + * @param node + */ + public SpinningPulse(Player player, Item node, int ammount, SpinningItem def) { + super(player, node); + this.type = def; + this.ammount = ammount; + } - @Override - public boolean checkRequirements() { - player.getInterfaceManager().close(); - if (player.getSkills().getLevel(Skills.CRAFTING) < type.getLevel()) { - player.getPacketDispatch().sendMessage("You need a crafting level of " + type.getLevel() + " to make this."); - return false; - } - if (!player.getInventory().contains(type.getNeed(), 1)) { - player.getPacketDispatch().sendMessage("You need " + ItemDefinition.forId(type.getNeed()).getName() + " to do this."); - return false; - } - return true; - } + @Override + public boolean checkRequirements() { + player.getInterfaceManager().close(); + if (player.getSkills().getLevel(Skills.CRAFTING) < type.getLevel()) { + player.getPacketDispatch().sendMessage("You need a crafting level of " + type.getLevel() + " to make this."); + return false; + } + if (!player.getInventory().contains(type.getNeed(), 1)) { + player.getPacketDispatch().sendMessage("You need " + ItemDefinition.forId(type.getNeed()).getName() + " to do this."); + return false; + } + return true; + } - @Override - public void animate() { - if (ticks % 5 == 0) { - player.animate(ANIMATION); - playAudio(player, Sounds.SPINNING_2590); - } - } + @Override + public void animate() { + if (ticks % 5 == 0) { + player.animate(ANIMATION); + playAudio(player, Sounds.SPINNING_2590); + } + } - @Override - public boolean reward() { + @Override + public boolean reward() { int tickThreshhold = 4; if (player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(2) && player.getLocation().withinDistance(Location.create(2711,3471,1)) @@ -83,31 +83,31 @@ public final class SpinningPulse extends SkillPulse { && player.getEquipment().get(EquipmentContainer.SLOT_HAT).getId() == 14631) { tickThreshhold = 2; } - if (++ticks % tickThreshhold != 0) { - return false; - } - if (player.getInventory().remove(new Item(type.getNeed(), 1))) { - final Item item = new Item(type.getProduct(), 1); - player.getInventory().add(item); - player.getSkills().addExperience(Skills.CRAFTING, type.getExp(), true); + if (++ticks % tickThreshhold != 0) { + return false; + } + if (player.getInventory().remove(new Item(type.getNeed(), 1))) { + final Item item = new Item(type.getProduct(), 1); + player.getInventory().add(item); + player.getSkills().addExperience(Skills.CRAFTING, type.getExp(), true); - // Seers achievement diary - if (player.getViewport().getRegion().getId() == 10806 - && !player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(0, 4)) { - if (player.getAttribute("diary:seers:bowstrings-spun", 0) >= 4) { - player.setAttribute("/save:diary:seers:bowstrings-spun", 5); - player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 0, 4); - } else { - player.setAttribute("/save:diary:seers:bowstrings-spun", player.getAttribute("diary:seers:bowstrings-spun", 0) + 1); - } - } - } - ammount--; - return ammount < 1; - } + // Seers achievement diary + if (player.getLocation().getRegionId() == 10806 + && !player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(0, 4)) { + if (player.getAttribute("diary:seers:bowstrings-spun", 0) >= 4) { + player.setAttribute("/save:diary:seers:bowstrings-spun", 5); + player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 0, 4); + } else { + player.setAttribute("/save:diary:seers:bowstrings-spun", player.getAttribute("diary:seers:bowstrings-spun", 0) + 1); + } + } + } + ammount--; + return ammount < 1; + } - @Override - public void message(int type) { - } + @Override + public void message(int type) { + } } diff --git a/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java b/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java index 50b969efd..7fc0b070e 100644 --- a/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java +++ b/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java @@ -138,7 +138,7 @@ public final class FireMakingPulse extends SkillPulse { player.faceLocation(object.getFaceLocation(player.getLocation())); player.getSkills().addExperience(Skills.FIREMAKING,fire.getXp()); - int playerRegion = player.getViewport().getRegion().getId(); + int playerRegion = player.getLocation().getRegionId(); setLastFire(); player.dispatch(new LitFireEvent(fire.getLogId())); diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt index 5a4a137b8..41261ec05 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt @@ -29,6 +29,7 @@ import core.game.node.scenery.SceneryBuilder import core.game.system.command.sets.STATS_BASE import core.game.system.command.sets.STATS_LOGS import core.game.world.map.RegionManager +import core.game.world.repository.Repository import core.tools.RandomFunction import org.rs09.consts.Items import org.rs09.consts.NPCs @@ -212,14 +213,13 @@ class WoodcuttingListener : InteractionListener { fun animateWoodcutting(player: Player) { if (!player.animator.isAnimating) { player.animate(SkillingTool.getHatchet(player).animation) - val playersAroundMe: List = RegionManager.getLocalPlayers(player, 2) + val playersAroundMe: List = RegionManager.getLocalPlayers(player.location, 2) .stream() - .filter { p: Player -> p.username != player.username } + .filter { p -> p.name != player.name } .toList() val soundIndex = RandomFunction.random(0, woodcuttingSounds.size) - - for (p in playersAroundMe) { - playAudio(p, woodcuttingSounds[soundIndex]) + for (player in playersAroundMe) { + playAudio(player, woodcuttingSounds[soundIndex]) } } } @@ -260,7 +260,7 @@ class WoodcuttingListener : InteractionListener { } // Seers village medium reward - extra normal log while in seer's village - if (reward == 1511 && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) && player.getViewport().getRegion().getId() == 10806) { + if (reward == 1511 && player.achievementDiaryManager.getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) && player.getLocation().regionId == 10806) { amount = 2 } return amount diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java index d69c7fea1..cf0a4557a 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java @@ -21,6 +21,7 @@ import core.game.node.scenery.SceneryBuilder; import core.game.system.task.Pulse; import core.game.world.map.Location; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; import org.rs09.consts.Sounds; @@ -38,248 +39,244 @@ import static core.game.system.command.sets.StatAttributeKeysKt.STATS_LOGS; * @author ceik */ public class WoodcuttingSkillPulse extends Pulse { - private int[] woodcuttingSounds = { - Sounds.WOODCUTTING_HIT_3038, - Sounds.WOODCUTTING_HIT_3039, - Sounds.WOODCUTTING_HIT_3040, - Sounds.WOODCUTTING_HIT_3041, - Sounds.WOODCUTTING_HIT_3042 - }; + private int[] woodcuttingSounds = { + Sounds.WOODCUTTING_HIT_3038, + Sounds.WOODCUTTING_HIT_3039, + Sounds.WOODCUTTING_HIT_3040, + Sounds.WOODCUTTING_HIT_3041, + Sounds.WOODCUTTING_HIT_3042 + }; - private WoodcuttingNode resource; - private int ticks; - private Player player; - private Scenery node; - protected boolean resetAnimation = true; + private WoodcuttingNode resource; + private int ticks; + private Player player; + private Scenery node; + protected boolean resetAnimation = true; - public WoodcuttingSkillPulse(Player player, Scenery node) { - super(1, player, node); - this.player = player; - this.node = node; - super.stop(); - } + public WoodcuttingSkillPulse(Player player, Scenery node) { + super(1, player, node); + this.player = player; + this.node = node; + super.stop(); + } - public void message(int type) { - if (type == 0) { - player.getPacketDispatch().sendMessage("You swing your axe at the tree..."); - } - } + public void message(int type) { + if (type == 0) { + player.getPacketDispatch().sendMessage("You swing your axe at the tree..."); + } + } - @Override - public boolean pulse() { - if (!checkRequirements()) { - return true; - } - animate(); - return reward(); - } + @Override + public boolean pulse() { + if (!checkRequirements()) { + return true; + } + animate(); + return reward(); + } - @Override - public void stop() { - if (resetAnimation) { - player.animate(new Animation(-1, Animator.Priority.HIGH)); - } - super.stop(); - message(1); - } + @Override + public void stop() { + if (resetAnimation) { + player.animate(new Animation(-1, Animator.Priority.HIGH)); + } + super.stop(); + message(1); + } - @Override - public void start() { - resource = WoodcuttingNode.forId(node.getId()); - if (resource == null) { - return; - } - if (checkRequirements()) { - super.start(); - message(0); - } - } + @Override + public void start() { + resource = WoodcuttingNode.forId(node.getId()); + if (resource == null) { + return; + } + if (checkRequirements()) { + super.start(); + message(0); + } + } - public boolean checkRequirements() { - if (player.getSkills().getLevel(Skills.WOODCUTTING) < resource.getLevel()) { - player.getPacketDispatch().sendMessage("You need a woodcutting level of " + resource.getLevel() + " to chop this tree."); - return false; - } - if (SkillingTool.getHatchet(player) == null) { - player.getPacketDispatch().sendMessage("You do not have an axe to use."); - return false; - } - if (player.getInventory().freeSlots() < 1) { - player.getDialogueInterpreter().sendDialogue("Your inventory is too full to hold any more " + ItemDefinition.forId(resource.getReward()).getName().toLowerCase() + "."); - return false; - } - return true; - } + public boolean checkRequirements() { + if (player.getSkills().getLevel(Skills.WOODCUTTING) < resource.getLevel()) { + player.getPacketDispatch().sendMessage("You need a woodcutting level of " + resource.getLevel() + " to chop this tree."); + return false; + } + if (SkillingTool.getHatchet(player) == null) { + player.getPacketDispatch().sendMessage("You do not have an axe to use."); + return false; + } + if (player.getInventory().freeSlots() < 1) { + player.getDialogueInterpreter().sendDialogue("Your inventory is too full to hold any more " + ItemDefinition.forId(resource.getReward()).getName().toLowerCase() + "."); + return false; + } + return true; + } - public void animate() { - if(!player.getAnimator().isAnimating()) { - player.animate(SkillingTool.getHatchet(player).getAnimation()); + public void animate() { + if (!player.getAnimator().isAnimating()) { + player.animate(SkillingTool.getHatchet(player).getAnimation()); + for (Player p : RegionManager.getLocalPlayers(player.getLocation(), 2)) { + if (p.getName() == player.getName()) { + continue; + } + int soundIndex = RandomFunction.random(0, woodcuttingSounds.length); + playAudio(p, woodcuttingSounds[soundIndex]); + } + } + } - List playersAroundMe = RegionManager.getLocalPlayers(player, 2) - .stream() - .filter(p -> !p.getUsername().equals(player.getUsername())) - .collect(Collectors.toList()); + public boolean reward() { + if (++ticks % 4 != 0) { + return false; + } + if (node.getId() == 10041) { + player.getDialogueInterpreter().sendDialogues(2574, FacialExpression.FURIOUS, RandomFunction.random(2) == 1 ? "You'll blow my cover! I'm meant to be hidden!" : "Will you stop that?"); + return true; + } + if (!checkReward(SkillingTool.getHatchet(player))) { + return false; + } - int soundIndex = RandomFunction.random(0, woodcuttingSounds.length); + // 20% chance to auto burn logs when using "inferno adze" item + if (SkillingTool.getHatchet(player).getId() == 13661 && RandomFunction.random(100) < 25) { + player.sendMessage("You chop some logs. The heat of the inferno adze incinerates them."); + Projectile.create(player, null, 1776, 35, 30, 20, 25).transform(player, new Location(player.getLocation().getX() + 2, player.getLocation().getY()), true, 25, 25).send(); + player.getSkills().addExperience(Skills.WOODCUTTING, resource.getExperience()); + player.getSkills().addExperience(Skills.FIREMAKING, resource.getExperience()); + return rollDepletion(); + } - for (Player p : playersAroundMe) { - playAudio(p, woodcuttingSounds[soundIndex]); - } - } - } + //actual reward calculations + int reward = resource.getReward(); + int rewardAmount = 0; + if (reward > 0) { + reward = calculateReward(reward); // calculate rewards + rewardAmount = calculateRewardAmount(reward); // calculate amount - public boolean reward() { - if (++ticks % 4 != 0) { - return false; - } - if (node.getId() == 10041) { - player.getDialogueInterpreter().sendDialogues(2574, FacialExpression.FURIOUS, RandomFunction.random(2) == 1 ? "You'll blow my cover! I'm meant to be hidden!" : "Will you stop that?"); - return true; - } - if (!checkReward(SkillingTool.getHatchet(player))) { - return false; - } + //add experience + double experience = calculateExperience(resource.reward, rewardAmount); - // 20% chance to auto burn logs when using "inferno adze" item - if (SkillingTool.getHatchet(player).getId() == 13661 && RandomFunction.random(100) < 25) { - player.sendMessage("You chop some logs. The heat of the inferno adze incinerates them."); - Projectile.create(player, null, 1776, 35, 30, 20, 25).transform(player, new Location(player.getLocation().getX() + 2, player.getLocation().getY()), true, 25, 25).send(); - player.getSkills().addExperience(Skills.WOODCUTTING, resource.getExperience()); - player.getSkills().addExperience(Skills.FIREMAKING, resource.getExperience()); - return rollDepletion(); - } + player.getSkills().addExperience(Skills.WOODCUTTING, experience, true); - //actual reward calculations - int reward = resource.getReward(); - int rewardAmount = 0; - if (reward > 0) { - reward = calculateReward(reward); // calculate rewards - rewardAmount = calculateRewardAmount(reward); // calculate amount + //send the message for the resource reward + player.getPacketDispatch().sendMessage("You get some " + ItemDefinition.forId(reward).getName().toLowerCase() + "."); + //give the reward + player.getInventory().add(new Item(reward, rewardAmount)); + player.dispatch(new ResourceProducedEvent(reward, rewardAmount, node, -1)); + int cutLogs = player.getAttribute(STATS_BASE + ":" + STATS_LOGS,0); + player.setAttribute("/save:" + STATS_BASE + ":" + STATS_LOGS,++cutLogs); - //add experience - double experience = calculateExperience(resource.reward, rewardAmount); + //calculate bonus bird nest for mining + int chance = 282; + if (RandomFunction.random(chance) == chance / 2) { + if(SkillcapePerks.isActive(SkillcapePerks.NEST_HUNTER,player)){ + if(!player.getInventory().add(BirdNest.getRandomNest(false).getNest())){ + BirdNest.drop(player); + } + } else { + BirdNest.drop(player); + } + } - player.getSkills().addExperience(Skills.WOODCUTTING, experience, true); + } - //send the message for the resource reward - player.getPacketDispatch().sendMessage("You get some " + ItemDefinition.forId(reward).getName().toLowerCase() + "."); - //give the reward - player.getInventory().add(new Item(reward, rewardAmount)); - player.dispatch(new ResourceProducedEvent(reward, rewardAmount, node, -1)); - int cutLogs = player.getAttribute(STATS_BASE + ":" + STATS_LOGS,0); - player.setAttribute("/save:" + STATS_BASE + ":" + STATS_LOGS,++cutLogs); + return rollDepletion(); + } - //calculate bonus bird nest for mining - int chance = 282; - if (RandomFunction.random(chance) == chance / 2) { - if(SkillcapePerks.isActive(SkillcapePerks.NEST_HUNTER,player)){ - if(!player.getInventory().add(BirdNest.getRandomNest(false).getNest())){ - BirdNest.drop(player); - } - } else { - BirdNest.drop(player); - } - } + private boolean rollDepletion() { + //transform to depleted version + //OSRS and RS3 Wikis both agree: All trees present in 2009 are a 1/8 fell chance, aside from normal trees/dead trees which are 100% + //OSRS: https://oldschool.runescape.wiki/w/Woodcutting scroll down to the mechanics section + //RS3 : https://runescape.wiki/w/Woodcutting scroll down to the mechanics section, and expand the tree felling chances table + if (resource.getRespawnRate() > 0) { + if (RandomFunction.roll(8) || resource.identifier == 1 || resource.identifier == 2 || resource.identifier == 3 || resource.identifier == 6) { + if (resource.isFarming()) { + FarmingPatch fPatch = FarmingPatch.forObject(node.asScenery()); + if(fPatch != null) { + Patch patch = fPatch.getPatchFor(player, true); + patch.setCurrentState(patch.getCurrentState() + 1); + } + return true; + } + if (resource.getEmptyId() > -1) { + SceneryBuilder.replace(node, node.transform(resource.getEmptyId()), resource.getRespawnDuration()); + } else { + SceneryBuilder.replace(node, node.transform(0), resource.getRespawnDuration()); + } + node.setActive(false); - } + playAudio(player, Sounds.TREE_FALLING_2734); + return true; + } + } + return false; + } - return rollDepletion(); - } + private int calculateRewardAmount(int reward) { + int amount = 1; - private boolean rollDepletion() { - //transform to depleted version - //OSRS and RS3 Wikis both agree: All trees present in 2009 are a 1/8 fell chance, aside from normal trees/dead trees which are 100% - //OSRS: https://oldschool.runescape.wiki/w/Woodcutting scroll down to the mechanics section - //RS3 : https://runescape.wiki/w/Woodcutting scroll down to the mechanics section, and expand the tree felling chances table - if (resource.getRespawnRate() > 0) { - if (RandomFunction.roll(8) || resource.identifier == 1 || resource.identifier == 2 || resource.identifier == 3 || resource.identifier == 6) { - if (resource.isFarming()) { - FarmingPatch fPatch = FarmingPatch.forObject(node.asScenery()); - if(fPatch != null) { - Patch patch = fPatch.getPatchFor(player, true); - patch.setCurrentState(patch.getCurrentState() + 1); - } - return true; - } - if (resource.getEmptyId() > -1) { - SceneryBuilder.replace(node, node.transform(resource.getEmptyId()), resource.getRespawnDuration()); - } else { - SceneryBuilder.replace(node, node.transform(0), resource.getRespawnDuration()); - } - node.setActive(false); + // 3239: Hollow tree (bark) 10% chance of obtaining + if (reward == 3239 && RandomFunction.random(100) >= 10) { + amount = 0; + } - playAudio(player, Sounds.TREE_FALLING_2734); - return true; - } - } - return false; - } + // Seers village medium reward - extra normal log while in seer's village + if (reward == 1511 + && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) + && player.getLocation().getRegionId() == 10806) { + amount = 2; + } - private int calculateRewardAmount(int reward) { - int amount = 1; + return amount; + } - // 3239: Hollow tree (bark) 10% chance of obtaining - if (reward == 3239 && RandomFunction.random(100) >= 10) { - amount = 0; - } + private double calculateExperience(int reward, int amount) { + double experience = resource.getExperience(); - // Seers village medium reward - extra normal log while in seer's village - if (reward == 1511 - && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) - && player.getViewport().getRegion().getId() == 10806) { - amount = 2; - } + if(player.getLocation().getRegionId() == 10300){ + return 1.0; + } - return amount; - } + // Bark + if (reward == 3239) { + // If we receive the item, give the full experience points otherwise give the base amount + if (amount >= 1) { + experience = 275.2; + } else { + amount = 1; + } + } - private double calculateExperience(int reward, int amount) { - double experience = resource.getExperience(); + // Seers village medium reward - extra 10% xp from maples while wearing headband + if (reward == 1517 + && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) + && player.getEquipment().get(EquipmentContainer.SLOT_HAT) != null + && player.getEquipment().get(EquipmentContainer.SLOT_HAT).getId() == 14631) { + experience *= 1.10; + } - if(player.getLocation().getRegionId() == 10300){ - return 1.0; - } + return experience * amount; + } - // Bark - if (reward == 3239) { - // If we receive the item, give the full experience points otherwise give the base amount - if (amount >= 1) { - experience = 275.2; - } else { - amount = 1; - } - } + private int calculateReward(int reward) { + return reward; + } - // Seers village medium reward - extra 10% xp from maples while wearing headband - if (reward == 1517 - && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) - && player.getEquipment().get(EquipmentContainer.SLOT_HAT) != null - && player.getEquipment().get(EquipmentContainer.SLOT_HAT).getId() == 14631) { - experience *= 1.10; - } - - return experience * amount; - } - - private int calculateReward(int reward) { - return reward; - } - - /** - * Checks if the player gets rewarded. - * - * @return {@code True} if so. - */ - private boolean checkReward(SkillingTool tool) { - int skill = Skills.WOODCUTTING; - int level = player.getSkills().getLevel(skill) + player.getFamiliarManager().getBoost(skill); - double hostRatio = RandomFunction.randomDouble(100.0); - double lowMod = tool == SkillingTool.BLACK_AXE ? resource.tierModLow / 2 : resource.tierModLow; - double low = resource.baseLow + (tool.ordinal() * lowMod); - double highMod = tool == SkillingTool.BLACK_AXE ? resource.tierModHigh / 2 : resource.tierModHigh; - double high = resource.baseHigh + (tool.ordinal() * highMod); - double clientRatio = RandomFunction.getSkillSuccessChance(low,high,level); - return hostRatio < clientRatio; - } + /** + * Checks if the player gets rewarded. + * + * @return {@code True} if so. + */ + private boolean checkReward(SkillingTool tool) { + int skill = Skills.WOODCUTTING; + int level = player.getSkills().getLevel(skill) + player.getFamiliarManager().getBoost(skill); + double hostRatio = RandomFunction.randomDouble(100.0); + double lowMod = tool == SkillingTool.BLACK_AXE ? resource.tierModLow / 2 : resource.tierModLow; + double low = resource.baseLow + (tool.ordinal() * lowMod); + double highMod = tool == SkillingTool.BLACK_AXE ? resource.tierModHigh / 2 : resource.tierModHigh; + double high = resource.baseHigh + (tool.ordinal() * highMod); + double clientRatio = RandomFunction.getSkillSuccessChance(low,high,level); + return hostRatio < clientRatio; + } } diff --git a/Server/src/main/content/global/skill/hunter/implings/ImplingData.kt b/Server/src/main/content/global/skill/hunter/implings/ImplingData.kt index affe2032c..e2b8df17b 100644 --- a/Server/src/main/content/global/skill/hunter/implings/ImplingData.kt +++ b/Server/src/main/content/global/skill/hunter/implings/ImplingData.kt @@ -173,6 +173,6 @@ enum class ImplingSpawnLocations (val type: ImplingSpawnTypes, vararg val locati object ImplingClipper : ClipMaskSupplier { override fun getClippingFlag (z: Int, x: Int, y: Int) : Int { var flag = RegionManager.getClippingFlag(z, x, y) - return flag and (RegionFlags.SOLID_TILE.inv()) and (RegionFlags.TILE_OBJECT.inv()) //Allow walking on water and flying over small objects, but keep all other tile flags the same. + return flag and (ChunkFlags.SOLID_TILE.inv()) and (ChunkFlags.TILE_OBJECT.inv()) //Allow walking on water and flying over small objects, but keep all other tile flags the same. } } diff --git a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java index f79c85728..82b036755 100644 --- a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java @@ -2,6 +2,7 @@ package content.global.skill.magic.lunar; import core.game.node.entity.combat.spell.MagicSpell; import core.game.node.entity.combat.spell.Runes; +import core.game.world.repository.Repository; import core.plugin.Initializable; import core.game.node.entity.skill.Skills; import core.game.node.Node; @@ -111,14 +112,14 @@ public final class HealSpell extends MagicSpell { playGlobalAudio(o.getLocation(), Sounds.LUNAR_HEAL_OTHER_INDIVIDUAL_2892); o.graphics(GRAPHICS); } else { - List players = RegionManager.getLocalPlayers(player, 1); - if (!super.meetsRequirements(player, true, true)) { + if (!super.meetsRequirements(player, true, true)) { return false; } int percentage = (int) Math.ceil(player.getSkills().getLifepoints() * 0.75); + List players = RegionManager.getLocalPlayers(player.getLocation(), 1); for (Iterator it = players.iterator(); it.hasNext();) { Player p = it.next(); - if (p == player || !p.getSettings().isAcceptAid() || !p.isActive() || p.getSkills().getLifepoints() == p.getSkills().getMaximumLifepoints()) { + if (p.getName() == player.getName() || !p.getSettings().isAcceptAid() || !p.isActive() || p.getSkills().getLifepoints() == p.getSkills().getMaximumLifepoints()) { it.remove(); } } diff --git a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt index 8d70f99cb..c32a4b69d 100644 --- a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt +++ b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt @@ -497,16 +497,16 @@ class LunarListeners : SpellListener("lunar"), Commands { removeRunes(player, true) visualizeSpell(player, Animations.LUNAR_SPELLBOOK_CURE_GROUP_4409, Graphics.LUNAR_SPELLBOOK_CURE_GROUP_744, 130, Sounds.LUNAR_CURE_GROUP_2882) curePoison(player) - for(acct in RegionManager.getLocalPlayers(player, 1)) { - if(!acct.isActive || acct.locks.isInteractionLocked) { + for (player in RegionManager.getLocalPlayers(player.location, 1)) { + if (!player.isActive || player.locks.isInteractionLocked) { continue } - if(!acct.settings.isAcceptAid) { + if (!player.settings.isAcceptAid) { continue } - curePoison(acct) - sendMessage(acct, "You have been cured of poison.") - visualizeSpell(acct, -1, Graphics.LUNAR_SPELLBOOK_CURE_GROUP_744, 130, Sounds.LUNAR_CURE_OTHER_INDIVIDUAL_2889) + curePoison(player) + sendMessage(player, "You have been cured of poison.") + visualizeSpell(player, -1, Graphics.LUNAR_SPELLBOOK_CURE_GROUP_744, 130, Sounds.LUNAR_CURE_OTHER_INDIVIDUAL_2889) } addXP(player, 74.0) } @@ -818,12 +818,12 @@ class LunarListeners : SpellListener("lunar"), Commands { } private fun sendGroupTeleport(player: Player, xp: Double, destName: String, loc: Location){ - RegionManager.getLocalPlayers(player, 1).forEach { - if(it == player) return@forEach - if(it.isTeleBlocked) return@forEach - if(!it.isActive) return@forEach - if(!it.settings.isAcceptAid) return@forEach - if(it.ironmanManager.isIronman) return@forEach + RegionManager.getLocalPlayers(player.location, 1).forEach { + if (it.name == player.name) return@forEach + if (it.isTeleBlocked) return@forEach + if (!it.isActive) return@forEach + if (!it.settings.isAcceptAid) return@forEach + if (it.ironmanManager.isIronman) return@forEach setAttribute(it, "t-o_location", loc) openInterface(it, Components.TELEPORT_OTHER_326) setInterfaceText(it, player.username, Components.TELEPORT_OTHER_326, 1) diff --git a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java index 61aeee5f7..d86f83b07 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java @@ -12,6 +12,7 @@ import core.game.bots.AIPlayer; import core.game.node.entity.player.link.SpellBookManager.SpellBook; import core.game.node.item.Item; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; @@ -52,19 +53,17 @@ public final class StatBoostSpell extends MagicSpell { player.getPacketDispatch().sendMessage("You can't cast this spell on that item."); return false; } - List pl = RegionManager.getLocalPlayers(player, 1); - int plSize = pl.size() - 1; + List pl = RegionManager.getLocalPlayers(player.getLocation(), 1); int doses = potion.getDose(item); - if (pl.size() == 0) { + if (pl.isEmpty()) { return false; } if (!super.meetsRequirements(player, true, false)) { return false; } int size = 0; - for (Player players : pl) { - Player o = (Player) players; - if (size >= doses) break; + for (Player o : pl) { + if (size >= doses) break; if (!o.isActive() || o.getLocks().isInteractionLocked() || o == player) { continue; } @@ -86,11 +85,11 @@ public final class StatBoostSpell extends MagicSpell { player.animate(ANIMATION); player.graphics(GRAPHICS); player.getInventory().remove(item); - int newIndex = (potion.getIds().length - doses) + size; - if (newIndex > potion.getIds().length - 1) { - player.getInventory().add(new Item(229)); - return true; - } + int newIndex = (potion.getIds().length - doses) + size; + if (newIndex > potion.getIds().length - 1) { + player.getInventory().add(new Item(229)); + return true; + } player.getInventory().add(new Item(potion.getIds()[newIndex])); return true; } diff --git a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java index 1f984d2da..71b9ebf82 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java @@ -2,6 +2,7 @@ package content.global.skill.magic.lunar; import content.data.consumables.Consumables; import core.game.consumable.Potion; +import core.game.world.repository.Repository; import core.plugin.Initializable; import core.game.node.entity.combat.spell.MagicSpell; import core.game.node.entity.combat.spell.Runes; @@ -27,7 +28,7 @@ public class StatRestoreSpell extends MagicSpell { private static final Animation ANIMATION = new Animation(4413); private static final Graphics GRAPHICS = new Graphics(733, 130); - private static final Consumables[] acceptedPotions = new Consumables[] { Consumables.RESTORE, Consumables.SUPER_RESTO, Consumables.PRAYER, Consumables.ENERGY, Consumables.SUPER_ENERGY }; + private static final Consumables[] acceptedPotions = new Consumables[] { Consumables.RESTORE, Consumables.SUPER_RESTO, Consumables.PRAYER, Consumables.ENERGY, Consumables.SUPER_ENERGY }; public StatRestoreSpell() { super(SpellBook.LUNAR, 81, 84, null, null, null, new Item[] { new Item(Runes.ASTRAL_RUNE.getId(), 2), new Item(Runes.EARTH_RUNE.getId(), 10), new Item(Runes.WATER_RUNE.getId(), 10) }); @@ -45,34 +46,32 @@ public class StatRestoreSpell extends MagicSpell { Item item = ((Item) target); player.getInterfaceManager().setViewedTab(6); - if (Consumables.getConsumableById(item.getId()) == null) { - player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); - return false; - } + if (Consumables.getConsumableById(item.getId()) == null) { + player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); + return false; + } final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable(); if (potion == null) { - player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); + player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); return false; } if (!item.getDefinition().isTradeable() || !isRestore(potion)) { player.getPacketDispatch().sendMessage("You can't cast this spell on that item."); return false; } - List pl = RegionManager.getLocalPlayers(player, 2); - int plSize = pl.size() - 1; + List pl = RegionManager.getLocalPlayers(player.getLocation(), 2); int doses = potion.getDose(item); - if (pl.size() == 0) { + if (pl.isEmpty()) { return false; } if (!super.meetsRequirements(player, true, false)) { return false; } int size = 0; - for (Player players : pl) { - if (size >= doses) break; - Player o = (Player) players; + for (Player o : pl) { + if (size >= doses) break; if (!o.isActive() || o.getLocks().isInteractionLocked() || o == player) { continue; } @@ -93,20 +92,20 @@ public class StatRestoreSpell extends MagicSpell { player.animate(ANIMATION); player.graphics(GRAPHICS); player.getInventory().remove(item); - int newIndex = (potion.getIds().length - doses) + size; - if (newIndex > potion.getIds().length - 1) { - player.getInventory().add(new Item(229)); - return true; - } + int newIndex = (potion.getIds().length - doses) + size; + if (newIndex > potion.getIds().length - 1) { + player.getInventory().add(new Item(229)); + return true; + } player.getInventory().add(new Item(potion.getIds()[newIndex])); return true; } private boolean isRestore(Potion p) { - for (int i = 0; i < acceptedPotions.length; i++) { - if (p == acceptedPotions[i].getConsumable()) - return true; - } + for (int i = 0; i < acceptedPotions.length; i++) { + if (p == acceptedPotions[i].getConsumable()) + return true; + } return false; } diff --git a/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java b/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java index 3c560fc41..294a535fd 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java @@ -152,9 +152,9 @@ public class ForgeRegentNPC extends Familiar { familiar.moveStep(); GroundItemManager.destroy(ground); player.getSkills().addExperience(Skills.FIREMAKING, log.getXp() + 10); - familiar.faceLocation(object.getFaceLocation(familiar.getLocation())); + familiar.faceLocation(object.getFaceLocation(familiar.getLocation())); SceneryBuilder.add(object, log.getLife(), FireMakingPulse.getAsh(player, log, object)); - if (player.getViewport().getRegion().getId() == 10806) { + if (player.getLocation().getRegionId() == 10806) { player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 9); } return true; diff --git a/Server/src/main/content/global/skill/summoning/familiar/GiantChinchompaNPC.java b/Server/src/main/content/global/skill/summoning/familiar/GiantChinchompaNPC.java index c0c57202a..ec8479e9a 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/GiantChinchompaNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/GiantChinchompaNPC.java @@ -56,7 +56,7 @@ public class GiantChinchompaNPC extends Familiar { if (!isOwnerAttackable()) { return false; } - final List entitys = RegionManager.getLocalEntitys(owner, 6); + final List entitys = RegionManager.getLocalEntities(owner.getLocation(), 6); entitys.remove(owner); entitys.remove(this); sendChat("Squeak!"); diff --git a/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java b/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java index c4672b643..fc867c0d3 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java @@ -133,7 +133,7 @@ public class PyreLordNPC extends Familiar { player.getSkills().addExperience(Skills.FIREMAKING, log.getXp() + 10); familiar.faceLocation(object.getFaceLocation(familiar.getLocation())); SceneryBuilder.add(object, log.getLife(), FireMakingPulse.getAsh(player, log, object)); - if (player.getViewport().getRegion().getId() == 10806) { + if (player.getLocation().getRegionId() == 10806) { player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 9); } return true; diff --git a/Server/src/main/content/global/skill/summoning/familiar/SmokeDevilNPC.java b/Server/src/main/content/global/skill/summoning/familiar/SmokeDevilNPC.java index 49a79fa6a..65f8fea75 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/SmokeDevilNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/SmokeDevilNPC.java @@ -70,7 +70,7 @@ public class SmokeDevilNPC extends Familiar { if (!isOwnerAttackable()) { return false; } - final List entitys = RegionManager.getLocalEntitys(this, 1); + final List entitys = RegionManager.getLocalEntities(location, 1); entitys.remove(this); entitys.remove(owner); visualize(Animation.create(7820), Graphics.create(1375)); diff --git a/Server/src/main/content/global/skill/summoning/familiar/SpiritTzKihNPC.java b/Server/src/main/content/global/skill/summoning/familiar/SpiritTzKihNPC.java index 19f97c6ba..e48196763 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/SpiritTzKihNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/SpiritTzKihNPC.java @@ -41,7 +41,7 @@ public class SpiritTzKihNPC extends Familiar { @Override protected boolean specialMove(FamiliarSpecial special) { - final List entitys = RegionManager.getLocalEntitys(owner, 8); + final List entitys = RegionManager.getLocalEntities(owner.getLocation(), 8); if (entitys.size() == 0) { return false; } diff --git a/Server/src/main/content/global/skill/summoning/pet/KittenInteractDialogue.java b/Server/src/main/content/global/skill/summoning/pet/KittenInteractDialogue.java index 24a387d18..9f5ce24ae 100644 --- a/Server/src/main/content/global/skill/summoning/pet/KittenInteractDialogue.java +++ b/Server/src/main/content/global/skill/summoning/pet/KittenInteractDialogue.java @@ -72,7 +72,7 @@ public final class KittenInteractDialogue extends DialoguePlugin { player.sendChat("Go on puss...kill that rat!"); boolean cant = true; NPC rat = null; - for (NPC n : RegionManager.getLocalNpcs(player.getLocation(), 10)) { + for (NPC n : RegionManager.getLocalNPCs(player.getLocation(), 10)) { if (!n.getName().contains("rat")) { cant = false; continue; diff --git a/Server/src/main/content/global/skill/thieving/StallThiefPulse.java b/Server/src/main/content/global/skill/thieving/StallThiefPulse.java index b08185335..b3a5ea755 100644 --- a/Server/src/main/content/global/skill/thieving/StallThiefPulse.java +++ b/Server/src/main/content/global/skill/thieving/StallThiefPulse.java @@ -115,7 +115,7 @@ public final class StallThiefPulse extends SkillPulse { SceneryBuilder.replace(node, node.transform(stall.getEmpty(node.getId())), stall.getDelay()); } final Item item = stall.getRandomLoot(); - player.getInventory().add(item); + player.getInventory().add(item); player.getSkills().addExperience(Skills.THIEVING, stall.getExperience(), true); if (item.getId() == 1987) { player.getPacketDispatch().sendMessage("You steal grapes from the grape stall."); @@ -135,9 +135,9 @@ public final class StallThiefPulse extends SkillPulse { if(stall == Stall.CANDLES) { return; } - if (type == 0) { - player.getPacketDispatch().sendMessage("You attempt to steal some " + stall.msgItem + " from the " + stall.name().toLowerCase().replace('_', ' ')); - } + if (type == 0) { + player.getPacketDispatch().sendMessage("You attempt to steal some " + stall.msgItem + " from the " + stall.name().toLowerCase().replace('_', ' ')); + } } /** @@ -156,7 +156,7 @@ public final class StallThiefPulse extends SkillPulse { player.sendMessage("A higher power smites you"); return false; } - for (NPC npc : RegionManager.getLocalNpcs(player.getLocation(), 8)) { + for (NPC npc : RegionManager.getLocalNPCs(player.getLocation(), 8)) { if (!npc.getProperties().getCombatPulse().isAttacking() && (npc.getId() == 32 || npc.getId() == 2236)) { npc.sendChat("Hey! Get your hands off there!"); npc.getProperties().getCombatPulse().attack(player); diff --git a/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java b/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java index 48b95f68f..3654658bc 100644 --- a/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java +++ b/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java @@ -19,8 +19,11 @@ import content.global.skill.summoning.familiar.Familiar; import core.game.node.scenery.Scenery; import core.game.system.task.Pulse; import core.game.world.map.Location; +import core.game.world.map.Region; +import core.game.world.map.RegionChunk; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; import core.net.packet.context.CameraContext; @@ -32,6 +35,7 @@ import core.plugin.Initializable; import core.tools.RandomFunction; import core.game.world.GameWorld; import core.plugin.ClassScanner; +import org.jetbrains.annotations.NotNull; import java.util.stream.IntStream; @@ -84,37 +88,41 @@ public final class BarrowsActivityPlugin extends ActivityPlugin { @Override public boolean pulse() { boolean end = true; - for (Player p : RegionManager.getRegionPlayers(14231)) { - end = false; - int index = p.getAttribute("barrow:drain-index", -1); - if (index > -1) { - p.removeAttribute("barrow:drain-index"); - p.getPacketDispatch().sendItemOnInterface(-1, 1, 24, index); - continue; - } - if (p.getLocation().getZ() == 0 && p.getAttribute("barrow:looted", false) && getWorldTicks() % 3 == 0) { - if (RandomFunction.random(15) == 0) { - p.getImpactHandler().manualHit(p, RandomFunction.random(5), HitsplatType.NORMAL); - Graphics.send(Graphics.create(405), p.getLocation()); + Region region = RegionManager.forId(14231); + Region.load(region); + for (int z = 0; z < 4; z++) { + for (Player p : region.assemblePlayerList(z)) { + end = false; + int index = p.getAttribute("barrow:drain-index", -1); + if (index > -1) { + p.removeAttribute("barrow:drain-index"); + p.getPacketDispatch().sendItemOnInterface(-1, 1, 24, index); + continue; } - } - int drain = 8; + if (p.getLocation().getZ() == 0 && p.getAttribute("barrow:looted", false) && getWorldTicks() % 3 == 0) { + if (RandomFunction.random(15) == 0) { + p.getImpactHandler().manualHit(p, RandomFunction.random(5), HitsplatType.NORMAL); + Graphics.send(Graphics.create(405), p.getLocation()); + } + } + int drain = 8; - //if (p.getLocks().isLocked("barrow:drain") || RandomFunction.random(100) % 2 == 0) { - // continue; - //} - for (boolean killed : p.getSavedData().getActivityData().getBarrowBrothers()) { - if (killed) { - drain += 1; + //if (p.getLocks().isLocked("barrow:drain") || RandomFunction.random(100) % 2 == 0) { + // continue; + //} + for (boolean killed : p.getSavedData().getActivityData().getBarrowBrothers()) { + if (killed) { + drain += 1; + } + } + if (getWorldTicks() % 30 == 0) { + p.getSkills().decrementPrayerPoints(drain); + p.getLocks().lock("barrow:drain", (3 + RandomFunction.random(15)) * 3); + index = 1 + RandomFunction.random(6); + p.setAttribute("barrow:drain-index", index); + p.getPacketDispatch().sendItemZoomOnInterface(4761 + RandomFunction.random(12), 100, 24, index); + p.getPacketDispatch().sendAnimationInterface(9810, 24, index); } - } - if(getWorldTicks() % 30 == 0){ - p.getSkills().decrementPrayerPoints(drain); - p.getLocks().lock("barrow:drain", (3 + RandomFunction.random(15)) * 3); - index = 1 + RandomFunction.random(6); - p.setAttribute("barrow:drain-index", index); - p.getPacketDispatch().sendItemZoomOnInterface(4761 + RandomFunction.random(12), 100, 24, index); - p.getPacketDispatch().sendAnimationInterface(9810, 24, index); } } return end; @@ -130,7 +138,7 @@ public final class BarrowsActivityPlugin extends ActivityPlugin { @Override public void locationUpdate(Entity e, Location last) { - if (e instanceof Player && e.getViewport().getRegion().getId() == 14231) { + if (e instanceof Player && e.getLocation().getRegionId() == 14231) { boolean tunnel = false; for (ZoneBorders border : MINI_TUNNELS) { if (border.insideBorder(e)) { @@ -140,7 +148,7 @@ public final class BarrowsActivityPlugin extends ActivityPlugin { } Player player = (Player) e; if ((getVarp(player, 1270) == 1) != tunnel) { - setVarp(player, 1270, tunnel ? 3 : 0, true); + setVarp(player, 1270, tunnel ? 3 : 0, true); } } } @@ -213,7 +221,7 @@ public final class BarrowsActivityPlugin extends ActivityPlugin { public static void shuffleCatacombs(Player player) { int value = TUNNEL_CONFIGS[RandomFunction.random(TUNNEL_CONFIGS.length)]; value |= 1 << (6 + RandomFunction.random(4)); - setVarp(player, 452, value); + setVarp(player, 452, value); } @Override @@ -293,10 +301,10 @@ public final class BarrowsActivityPlugin extends ActivityPlugin { return true; case 6774: player.lock(1); - int brother = player.getSavedData().getActivityData().getBarrowTunnelIndex(); - if (!player.getSavedData().getActivityData().getBarrowBrothers()[brother] && !player.getAttribute("brother:" + brother, false)) { - BarrowsCrypt.getCrypt(brother).spawnBrother(player, RegionManager.getTeleportLocation(target.getCenterLocation(), 4)); - } + int brother = player.getSavedData().getActivityData().getBarrowTunnelIndex(); + if (!player.getSavedData().getActivityData().getBarrowBrothers()[brother] && !player.getAttribute("brother:" + brother, false)) { + BarrowsCrypt.getCrypt(brother).spawnBrother(player, RegionManager.getTeleportLocation(target.getCenterLocation(), 4)); + } player.setAttribute("barrow:opened_chest", true); sendConfiguration(player); return true; @@ -335,7 +343,7 @@ public final class BarrowsActivityPlugin extends ActivityPlugin { if (player.getAttribute("barrow:opened_chest", false)) { config |= 1 << 16; } - setVarp(player, 453, config); + setVarp(player, 453, config); } @Override diff --git a/Server/src/main/content/minigame/mta/TelekineticGrabSpell.java b/Server/src/main/content/minigame/mta/TelekineticGrabSpell.java index 72728d1e6..00486fad4 100644 --- a/Server/src/main/content/minigame/mta/TelekineticGrabSpell.java +++ b/Server/src/main/content/minigame/mta/TelekineticGrabSpell.java @@ -100,8 +100,9 @@ public final class TelekineticGrabSpell extends MagicSpell { @Override public boolean cast(final Entity entity, final Node target) { - if (!(target instanceof GroundItem)) - return false; + if (!(target instanceof GroundItem)) { + return false; + } final GroundItem ground = (GroundItem) target; if (!canCast(entity, ground)) { return false; @@ -131,32 +132,34 @@ public final class TelekineticGrabSpell extends MagicSpell { Player player = entity instanceof Player ? (Player) entity : null; GroundItem g = GroundItemManager.get(ground.getId(), ground.getLocation(), player); if (g == null) { - player.getPacketDispatch().sendMessage("Too late!"); + if (player != null) { + player.getPacketDispatch().sendMessage("Too late!"); + } return true; } - if (g == SpecialGroundItems.AHAB_BEER.asGroundItem()){ - player.getDialogueInterpreter().open(2692, new NPC(2692), true); + if (g == SpecialGroundItems.AHAB_BEER.asGroundItem()) { + if (player != null) { + player.getDialogueInterpreter().open(2692, new NPC(2692), true); + } return true; } if (player == null) { return true; } boolean teleZone = player.getZoneMonitor().isInZone("Telekinetic Theatre") && g.getId() == 6888; - if (player != null) { - if (g == null || !g.isActive()) { - player.getPacketDispatch().sendMessage("Too late!"); - return true; - } - playAudio(player, Sounds.VULNERABILITY_IMPACT_3008); - if (!teleZone) { - player.getInventory().add(new Item(g.getId(), g.getAmount(), g.getCharge())); - } else { - TelekineticZone zone = TelekineticZone.getZone(player); - zone.moveStatue(); - player.lock(getDelay()); - } - player.getPacketDispatch().sendPositionedGraphics(END_GRAPHIC, ground.getLocation()); + if (!g.isActive()) { + player.getPacketDispatch().sendMessage("Too late!"); + return true; } + playAudio(player, Sounds.VULNERABILITY_IMPACT_3008); + if (!teleZone) { + player.getInventory().add(new Item(g.getId(), g.getAmount(), g.getCharge())); + } else { + TelekineticZone zone = TelekineticZone.getZone(player); + zone.moveStatue(); + player.lock(getDelay()); + } + player.getPacketDispatch().sendPositionedGraphics(END_GRAPHIC, ground.getLocation()); if (!teleZone) { GroundItemManager.destroy(g); } diff --git a/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java b/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java index 741bbc4df..650842a1f 100644 --- a/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java +++ b/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java @@ -140,7 +140,7 @@ public final class PCObjectHandler extends OptionHandler { handleTurretTower(player, session, object); return true; } - if (!object.isActive() || !session.getBarricades().contains(object)) { + if (!object.isActive() || (getObjectType(object.getId()) == 9 && !session.getBarricades().contains(object))) { return true; } if (option.equals("repair")) { // Handle barricades @@ -229,16 +229,15 @@ public final class PCObjectHandler extends OptionHandler { int dir = open ? object.getRotation() : rotation; Direction direction = Direction.get(!open ? dir : ((3 + dir) % 4)); if (session.getBarricades().contains(object) && session.getBarricades().contains(second)) { - session.getBarricades().remove(object); - session.getBarricades().remove(second); - Location l = object.getLocation().transform(direction.getStepX(), direction.getStepY(), 0); Scenery replacement = new Scenery(object.getId() + (open ? 1 : -1), l, 0, open ? rotation : ((direction.toInteger() + 3) % 4)); + session.getBarricades().remove(object); SceneryBuilder.replace(object, replacement); session.getBarricades().add(replacement); l = second.getLocation().transform(direction.getStepX(), direction.getStepY(), 0); replacement = new Scenery(second.getId() + (open ? 1 : -1), l, 0, open ? getRotation(second) : ((direction.toInteger() + 3) % 4)); + session.getBarricades().remove(second); SceneryBuilder.replace(second, replacement); session.getBarricades().add(replacement); } @@ -295,7 +294,7 @@ public final class PCObjectHandler extends OptionHandler { * @param objectId The object id. * @return The object type. */ - private static int getObjectType(int objectId) { + static int getObjectType(int objectId) { if (objectId == 14225 || objectId == 14226 || objectId == 14228 || objectId == 14229) { return 9; } diff --git a/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java b/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java index 0bddb9a24..b28fa05c2 100644 --- a/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java +++ b/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java @@ -8,12 +8,9 @@ import core.game.node.entity.combat.BattleState; import core.game.node.entity.npc.AbstractNPC; import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; -import core.game.world.map.Direction; -import core.game.world.map.Location; -import core.game.world.map.RegionPlane; +import core.game.world.map.*; import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; -import content.minigame.pestcontrol.monsters.PCRavagerNPC; import content.minigame.pestcontrol.monsters.PCSpinnerNPC; /** @@ -146,8 +143,8 @@ public final class PCPortalNPC extends AbstractNPC { public void tick() { super.tick(); if (session != null) { - RegionPlane plane = getViewport().getCurrentPlane(); - if (plane != null && session.getTicks() % 35 - plane.getPlayers().size() == 0 && plane.getNpcs().size() < 100) { + Region region = RegionManager.forId(location.getRegionId()); + if (session.getTicks() % 35 - region.assemblePlayerList(0).size() == 0 && region.assembleNpcList(0).size() < 100) { spawnNPCs(); } if (updateLifepoints && session.getTicks() % 10 == 0) { @@ -187,9 +184,7 @@ public final class PCPortalNPC extends AbstractNPC { int index = getDifficultyIndex(); Random r = RandomFunction.RANDOM; int amount = index + 1; - if (getViewport().getCurrentPlane() != null) { - amount += getViewport().getCurrentPlane().getPlayers().size() / 10; - } + amount += RegionManager.getLocalPlayers(location).size() / 10; if (getDifficultyIndex() == 0) { amount += ((getDifficultyIndex() + 1) * 3) / 2; } diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java b/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java index f1fb680a0..a570ede1c 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java @@ -20,10 +20,12 @@ import core.game.node.item.Item; import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; +import core.game.world.map.RegionChunk; import core.game.world.map.build.DynamicRegion; import core.game.world.map.zone.RegionZone; import core.game.world.map.zone.ZoneBuilder; import core.game.world.map.zone.ZoneRestriction; +import core.game.world.repository.Repository; import core.plugin.Initializable; import core.plugin.ClassScanner; import core.tools.RandomFunction; @@ -125,40 +127,48 @@ public final class PestControlActivityPlugin extends ActivityPlugin { if (!session.isActive()) { return; } - for (final Player p : session.getRegion().getPlanes()[0].getPlayers()) { - p.getProperties().setTeleportLocation(getLeaveLocation()); - if (!success) { - p.getDialogueInterpreter().open(3781, true, 0, true); - // default, - // type, - // default - } else if (success && p.getAttribute("pc_zeal", 0) >= 50) { - int amount = type.ordinal() + 2; - p.getSavedData().getActivityData().increasePestPoints(amount); - Item coins = new Item(995, p.getProperties().getCurrentCombatLevel() * 10); - if (!p.getInventory().add(coins)) { - GroundItemManager.create(coins, p); + RegionChunk[][][] chunks = session.getRegion().getChunks(); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + RegionChunk chunk = chunks[x][y][z]; + for (Player p : chunk.getPlayers()) { + p.getProperties().setTeleportLocation(getLeaveLocation()); + if (!success) { + p.getDialogueInterpreter().open(3781, true, 0, true); + // default, + // type, + // default + } else if (p.getAttribute("pc_zeal", 0) >= 50) { + int amount = type.ordinal() + 2; + p.getSavedData().getActivityData().increasePestPoints(amount); + Item coins = new Item(995, p.getProperties().getCurrentCombatLevel() * 10); + if (!p.getInventory().add(coins)) { + GroundItemManager.create(coins, p); + } + // default, type, name + p.getDialogueInterpreter().open(3781, true, 1, type.ordinal() == 0 ? "two" : type.ordinal() == 1 ? "three" : "four"); + } else { + // default type, default + p.getDialogueInterpreter().open(3781, true, 2, true); + } + p.removeAttribute("pc_zeal"); + p.removeExtension(PestControlSession.class); + p.fullRestore(); + if (isPoisoned(p)) { + curePoison(p); + } + PulseManager.cancelDeathTask(p); + GameWorld.getPulser().submit(new Pulse(1, p) { + @Override + public boolean pulse() { + p.getSkills().restore(); + return true; + } + }); + } } - // default, type, name - p.getDialogueInterpreter().open(3781, true, 1, type.ordinal() == 0 ? "two" : type.ordinal() == 1 ? "three" : "four"); - } else { - // default type, default - p.getDialogueInterpreter().open(3781, true, 2, true); } - p.removeAttribute("pc_zeal"); - p.removeExtension(PestControlSession.class); - p.fullRestore(); - if (isPoisoned(p)) { - curePoison(p); - } - PulseManager.cancelDeathTask(p); - GameWorld.getPulser().submit(new Pulse(1, p) { - @Override - public boolean pulse() { - p.getSkills().restore(); - return true; - } - }); } session.getRegion().getRegionZones().clear(); session.setActive(false); @@ -293,7 +303,7 @@ public final class PestControlActivityPlugin extends ActivityPlugin { @Override public boolean death(Entity e, Entity killer) { - if (e instanceof Player && e.getViewport().getRegion().getRegionId() == 10536) { + if (e instanceof Player && e.getLocation().getRegion().getRegionId() == 10536) { PestControlSession session = e.getExtension(PestControlSession.class); if (session != null) { Location l = session.getRegion().getBaseLocation(); diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java index 8396f97b8..f24197b85 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java @@ -8,8 +8,6 @@ import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.node.scenery.Scenery; import core.game.world.map.Location; -import core.game.world.map.Point; -import core.game.world.map.RegionPlane; import core.game.world.map.build.DynamicRegion; import core.tools.RandomFunction; @@ -21,12 +19,6 @@ import static core.api.ContentAPIKt.*; * @author Emperor */ public final class PestControlSession { - - /** - * The barricade object offsets. - */ - private static final Point[] OBJECT_OFFSETS = { new Point(46, 33), new Point(46, 32), new Point(32, 25), new Point(33, 25), new Point(19, 32), new Point(19, 33), new Point(49, 33), new Point(49, 32), new Point(49, 31), new Point(49, 30), new Point(52, 27), new Point(52, 26), new Point(52, 25), new Point(52, 24), new Point(52, 14), new Point(52, 13), new Point(52, 12), new Point(52, 11), new Point(42, 18), new Point(43, 18), new Point(44, 18), new Point(45, 18), new Point(32, 15), new Point(33, 15), new Point(34, 15), new Point(35, 15), new Point(23, 18), new Point(24, 18), new Point(25, 18), new Point(26, 18), new Point(13, 11), new Point(13, 12), new Point(13, 13), new Point(13, 14), new Point(12, 28), new Point(12, 29), new Point(12, 30), new Point(12, 31), }; - /** * The object ids of non-attackable barricades/gates. */ @@ -123,7 +115,7 @@ public final class PestControlSession { * @param message The message to send. */ public void sendMessage(String message) { - for (Player p : region.getPlanes()[0].getPlayers()) { + for (Player p : region.assemblePlayerList(0)) { if (p.isActive()) { p.getPacketDispatch().sendMessage(message); } @@ -136,7 +128,7 @@ public final class PestControlSession { * @param child The child id. */ public void sendString(String message, int child) { - for (Player p : region.getPlanes()[0].getPlayers()) { + for (Player p : region.assemblePlayerList(0)) { if (p.isActive()) { p.getPacketDispatch().sendString(message, 408, child); } @@ -164,9 +156,9 @@ public final class PestControlSession { * @param value The message value to send. */ public void sendConfig(int value) { - for (Player p : region.getPlanes()[0].getPlayers()) { + for (Player p : region.assemblePlayerList(0)) { if (p.isActive()) { - setVarp(p, 719, value); + setVarp(p, 719, value); } } } @@ -191,7 +183,7 @@ public final class PestControlSession { message = "The red, south-western portal shield has dropped!"; break; } - for (Player p : region.getPlanes()[0].getPlayers()) { + for (Player p : region.assemblePlayerList(0)) { if (p.isActive()) { p.getPacketDispatch().sendInterfaceConfig(408, 18 + (index << 1), true); p.getPacketDispatch().sendMessage(message); @@ -233,8 +225,7 @@ public final class PestControlSession { } } - for (Player p : remainingPlayers) - { + for (Player p : remainingPlayers) { int priority = p.getAttribute("pc_prior", 0) + 1; p.getPacketDispatch().sendMessage("You have been given priority level " + priority + " over other players in joining the next"); p.getPacketDispatch().sendMessage("game."); @@ -264,7 +255,7 @@ public final class PestControlSession { Random r = RandomFunction.RANDOM; Location l = region.getBaseLocation(); p.getProperties().setTeleportLocation(l.transform(32 + r.nextInt(4), 49 + r.nextInt(6), 0)); - setVarp(p, 1147, 0); + setVarp(p, 1147, 0); p.getDialogueInterpreter().sendDialogues(3781, FacialExpression.FURIOUS, "You must defend the Void Knight while the portals are", "unsummoned. The ritual takes twenty minutes though,", "so you can help out by destroying them yourselves!", "Now GO GO GO!"); } @@ -272,9 +263,17 @@ public final class PestControlSession { * Initializes the barricades list. */ private void initBarricadesList() { - RegionPlane p = region.getPlanes()[0]; - for (Point point : OBJECT_OFFSETS) { - barricades.add(p.getObjects()[point.getX()][point.getY()]); + for (int chunkX = 0; chunkX < 8; chunkX++) { + for (int chunkY = 0; chunkY < 8; chunkY++) { + List objects = region.getChunks()[chunkX][chunkY][0].assembleObjectList(); + for (Scenery object : objects) { + boolean isActualBarricade = PCObjectHandler.getObjectType(object.getId()) == 9; + boolean isGate = object.getId() > 14232; + if (isActualBarricade || isGate) { + barricades.add(object); + } + } + } } } @@ -385,5 +384,4 @@ public final class PestControlSession { public List getBarricades() { return barricades; } - } diff --git a/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java b/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java index c0e7ca1de..c1c2a11c7 100644 --- a/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java +++ b/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java @@ -46,7 +46,7 @@ public class SquireDialogue extends DialoguePlugin { interpreter.sendDialogues(3781, FacialExpression.HALF_GUILTY, "Congratulations! You managed to destroy all the portals!", "We've awarded you " + points + " Void Knight Commendation", "points. Please also accept these coins as a reward."); stage = 100; } else {// won and not awarded. - interpreter.sendDialogues(3781, FacialExpression.HALF_GUILTY, "Congratulations! You managed to destroy all the portals!", "However, you did not succeed in reaching the required", "amount of damage delt we cannot grant you a reward."); + interpreter.sendDialogues(3781, FacialExpression.HALF_GUILTY, "Congratulations! You managed to destroy all the portals!", "However, you did not succeed in reaching the required", "amount of damage dealt we cannot grant you a reward."); stage = 101; } return true; diff --git a/Server/src/main/content/minigame/pestcontrol/VoidSealPlugin.java b/Server/src/main/content/minigame/pestcontrol/VoidSealPlugin.java index 95244ea66..d6c475b5b 100644 --- a/Server/src/main/content/minigame/pestcontrol/VoidSealPlugin.java +++ b/Server/src/main/content/minigame/pestcontrol/VoidSealPlugin.java @@ -29,7 +29,7 @@ public final class VoidSealPlugin extends OptionHandler { @Override public boolean handle(Player player, Node node, String option) { - if (player.getViewport().getRegion().getRegionId() != 10536) { + if (player.getLocation().getRegionId() != 10536) { player.getPacketDispatch().sendMessage("You can only use the seal in Pest Control."); return true; } @@ -48,7 +48,7 @@ public final class VoidSealPlugin extends OptionHandler { player.getInventory().replace(replace, item.getSlot()); } player.graphics(Graphics.create(1177)); - for (NPC npc : RegionManager.getLocalNpcs(player, 2)) { + for (NPC npc : RegionManager.getLocalNPCs(player.getLocation(), 2)) { if (canTarget(npc)) { npc.getImpactHandler().manualHit(player, 7 + RandomFunction.randomize(5), HitsplatType.NORMAL, 1); npc.graphics(Graphics.create(1176)); diff --git a/Server/src/main/content/minigame/pestcontrol/bots/CombatState.kt b/Server/src/main/content/minigame/pestcontrol/bots/CombatState.kt index dbfb2ee4a..d03ef42a6 100644 --- a/Server/src/main/content/minigame/pestcontrol/bots/CombatState.kt +++ b/Server/src/main/content/minigame/pestcontrol/bots/CombatState.kt @@ -7,8 +7,6 @@ import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.map.path.Pathfinder import core.tools.RandomFunction -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import content.minigame.pestcontrol.PestControlHelper.GATE_ENTRIES import content.minigame.pestcontrol.PestControlHelper.getMyPestControlSession1 import core.game.world.GameWorld @@ -63,7 +61,7 @@ class CombatState(val bot: PestControlTestBot) { if (portal != null) { if(bot.location.withinDistance(portal.location,10) && portal.isActive){ val spinners = ArrayList() - RegionManager.getLocalNpcs(bot).forEach { + RegionManager.getLocalNPCs(bot.location).forEach { if(it.name.toLowerCase().equals("spinner") && it.location.withinDistance(bot.location,10)) spinners.add(it) } if(spinners.isNotEmpty()){ diff --git a/Server/src/main/content/minigame/pestcontrol/bots/CombatStateIntermediate.kt b/Server/src/main/content/minigame/pestcontrol/bots/CombatStateIntermediate.kt index fbea681bd..669eca80b 100644 --- a/Server/src/main/content/minigame/pestcontrol/bots/CombatStateIntermediate.kt +++ b/Server/src/main/content/minigame/pestcontrol/bots/CombatStateIntermediate.kt @@ -7,8 +7,6 @@ import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.map.path.Pathfinder import core.tools.RandomFunction -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import content.minigame.pestcontrol.PestControlHelper.GATE_ENTRIES import content.minigame.pestcontrol.PestControlHelper.getMyPestControlSession2 import core.game.world.GameWorld @@ -62,7 +60,7 @@ class CombatStateIntermediate(val bot: PestControlTestBot2) { if (portal != null) { if(bot.location.withinDistance(portal.location,10) && portal.isActive){ val spinners = ArrayList() - RegionManager.getLocalNpcs(bot).forEach { + RegionManager.getLocalNPCs(bot.location).forEach { if(it.name.toLowerCase().equals("spinner") && it.location.withinDistance(bot.location,10)) spinners.add(it) } if(spinners.isNotEmpty()){ diff --git a/Server/src/main/content/minigame/pestcontrol/monsters/PCRavagerNPC.java b/Server/src/main/content/minigame/pestcontrol/monsters/PCRavagerNPC.java index 4fba76be2..4d45fee9b 100644 --- a/Server/src/main/content/minigame/pestcontrol/monsters/PCRavagerNPC.java +++ b/Server/src/main/content/minigame/pestcontrol/monsters/PCRavagerNPC.java @@ -114,7 +114,7 @@ public class PCRavagerNPC extends AbstractNPC { GameWorld.getPulser().submit(new Pulse(1, this, o) { @Override public boolean pulse() { - if (getViewport().getRegion().isActive() && session.getBarricades().remove(o)) { + if (getLocation().getRegion().isActive() && session.getBarricades().remove(o)) { session.getBarricades().add(newTarget); SceneryBuilder.replace(o, newTarget); } @@ -173,10 +173,10 @@ public class PCRavagerNPC extends AbstractNPC { return true; } - @Override - public boolean shouldPreventStacking(Entity mover) { - return mover instanceof NPC; - } + @Override + public boolean shouldPreventStacking(Entity mover) { + return mover instanceof NPC; + } @Override public void onImpact(final Entity entity, BattleState state) { diff --git a/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java b/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java index 60cc22a37..4bfedb5e0 100644 --- a/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java +++ b/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java @@ -15,6 +15,7 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; @@ -100,9 +101,9 @@ public final class PCSpinnerNPC extends AbstractNPC { */ public void explode() { animate(getProperties().getDeathAnimation()); - for (Player p : RegionManager.getLocalPlayers(this, 1)) { + for (Player p : RegionManager.getLocalPlayers(location, 1)) { p.getImpactHandler().manualHit(this, 5, HitsplatType.POISON); - applyPoison(p, this, 1); + applyPoison(p, this, 1); } GameWorld.getPulser().submit(new Pulse(1, this) { @Override diff --git a/Server/src/main/content/minigame/pestcontrol/monsters/PCSplatterNPC.java b/Server/src/main/content/minigame/pestcontrol/monsters/PCSplatterNPC.java index 5e5111211..cb8c83764 100644 --- a/Server/src/main/content/minigame/pestcontrol/monsters/PCSplatterNPC.java +++ b/Server/src/main/content/minigame/pestcontrol/monsters/PCSplatterNPC.java @@ -75,10 +75,10 @@ public final class PCSplatterNPC extends AbstractNPC { } } - @Override - public boolean shouldPreventStacking(Entity mover) { - return mover instanceof NPC; - } + @Override + public boolean shouldPreventStacking(Entity mover) { + return mover instanceof NPC; + } @Override public void onImpact(final Entity entity, BattleState state) { @@ -132,10 +132,10 @@ public final class PCSplatterNPC extends AbstractNPC { } } } - for (Player p : RegionManager.getLocalPlayers(this, 1)) { + for (Player p : RegionManager.getLocalPlayers(location, 1)) { p.getImpactHandler().manualHit(this, RandomFunction.random(minimum, maximum), null); } - for (NPC npc : RegionManager.getLocalNpcs(this, 1)) { + for (NPC npc : RegionManager.getLocalNPCs(location, 1)) { if (npc != this) { npc.getImpactHandler().manualHit(this, RandomFunction.random(minimum, maximum), null); } diff --git a/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt b/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt index 2c1bb509e..0dd282ed5 100644 --- a/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt +++ b/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt @@ -11,6 +11,7 @@ import core.game.world.map.zone.ZoneBorders import core.game.world.map.RegionManager import core.game.system.task.Pulse import content.global.skill.hunter.bnet.BNetTypes +import core.game.world.repository.Repository import org.rs09.consts.Items @@ -27,7 +28,7 @@ class ImpDefenderBehavior : NPCBehavior(6074) { var nextCaptureTick = getAttribute(self, "next-capture-tick", 0) if (getWorldTicks() < nextCaptureTick) return true - var players = RegionManager.getLocalPlayers(self, 2) + var players = RegionManager.getLocalPlayers(self.location, 2) for (player in players) { var lowestTierImpling = BNetTypes.getImpling(player) if (lowestTierImpling == null) continue diff --git a/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java b/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java index af3dbc8e7..ce1c6133c 100644 --- a/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java +++ b/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java @@ -1,7 +1,5 @@ package content.minigame.sorceress; -import java.util.List; - import core.game.component.Component; import core.game.node.entity.Entity; import core.game.node.entity.combat.CombatSwingHandler; @@ -12,6 +10,8 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Direction; import core.game.world.map.Location; +import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; @@ -194,20 +194,11 @@ public final class SorceressElementalNPC extends AbstractNPC { return respawn; } - /** - * Gets the tilesIndex. - * @return The tilesIndex. - */ - public int getTilesIndex() { - return tilesIndex; - } - @Override public void tick() { super.tick(); - List players = getViewport().getCurrentPlane().getPlayers(); - for (Player player : players) { - if (player == null || !player.isActive() || player.getLocks().isInteractionLocked() || DeathTask.isDead(player) || !canTeleport(player) || !CombatSwingHandler.isProjectileClipped(this, player, false)) { + for (Player player : RegionManager.getLocalPlayers(location)) { + if (!player.isActive() || player.getLocks().isInteractionLocked() || DeathTask.isDead(player) || !canTeleport(player) || !CombatSwingHandler.isProjectileClipped(this, player, false)) { continue; } animate(new Animation(5803)); diff --git a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt index 04fe7686a..bf7c42467 100644 --- a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt +++ b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt @@ -1,8 +1,6 @@ package content.minigame.vinesweeper -import BlinkinDialogue -import FarmerDialogue.Companion.FARMER_FLAG_LINES -import WinkinDialogue +import content.minigame.vinesweeper.FarmerDialogue.Companion.FARMER_FLAG_LINES import content.minigame.vinesweeper.Vinesweeper.Companion.FARMERS import content.minigame.vinesweeper.Vinesweeper.Companion.FARMER_CLEAR_RADIUS import content.minigame.vinesweeper.Vinesweeper.Companion.HOLES @@ -492,10 +490,10 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { dest.player.incrementAttribute("/save:vinesweeper:points", points) dest.player.inventory.add(Item(Items.FLAG_12625, 1)) sendUpdatedPoints(dest.player) - for (neighbor in RegionManager.getLocalPlayers(npc)) { - if (neighbor != dest.player) { - neighbor.incrementAttribute("/save:vinesweeper:points", points / 2) - sendUpdatedPoints(neighbor) + for (player in RegionManager.getLocalPlayers(npc.location)) { + if (player.name != dest.player.name) { + player.incrementAttribute("/save:vinesweeper:points", points / 2) + sendUpdatedPoints(player) } } } @@ -572,21 +570,23 @@ class VinesweeperNPC : AbstractNPC { } override fun handleTickActions() { val dest = seedDestinations.find { sd -> sd.loc == location } - if (locks.isMovementLocked() || locks.isInteractionLocked()) + if (locks.isMovementLocked || locks.isInteractionLocked) return - if(dest != null) { - for(npc in RegionManager.getRegionPlane(location).npcs) { - if(npc is VinesweeperNPC) { - npc.seedDestinations.remove(dest) - npc.resetWalk() + if (dest != null) { + val npcs = location.region.assembleNpcList(0) + for (npc in npcs) { + if (npc !is VinesweeperNPC || npc.seedDestinations.isEmpty() /*npc is not currently walking towards a seed*/) { + continue } + npc.seedDestinations.remove(dest) + npc.resetWalk() } val scenery = getScenery(dest.loc) - if(scenery != null) { - if(id in RABBITS) { + if (scenery != null) { + if (id in RABBITS) { handleRabbitSeed(scenery, dest) } else { - if(dest.alive) { + if (dest.alive) { handleFarmerFlag(scenery, dest) } else { handleFarmerSeed(scenery, dest) @@ -653,13 +653,13 @@ class VinesweeperNPC : AbstractNPC { animate(Animation(Animations.GNOME_FARMER_DIG_FLAG_8725)) GameWorld.Pulser.submit(object: Pulse(3) { override fun pulse(): Boolean { - when(i++) { + when (i++) { 0 -> { sendChat(FARMER_FLAG_LINES.FIND_FLAG.line) } 1 -> { SceneryBuilder.replace(scenery, scenery.transform(HOLES[0])) - if(SEED_LOCS.contains(dest.loc)) { + if (SEED_LOCS.contains(dest.loc)) { sendChat(FARMER_FLAG_LINES.FIND_SEED.line) animate(Animation(Animations.GNOME_FARMER_HOORAY_8731)) sendPoints(npc,dest) diff --git a/Server/src/main/content/minigame/vinesweeper/VinesweeperDialogues.kt b/Server/src/main/content/minigame/vinesweeper/VinesweeperDialogues.kt index 23c012487..49f50f72e 100644 --- a/Server/src/main/content/minigame/vinesweeper/VinesweeperDialogues.kt +++ b/Server/src/main/content/minigame/vinesweeper/VinesweeperDialogues.kt @@ -1,3 +1,5 @@ +package content.minigame.vinesweeper + import core.game.component.Component import core.game.node.item.GroundItemManager import core.game.node.item.Item diff --git a/Server/src/main/content/region/asgarnia/burthorpe/handlers/BurthorpeTrainNPC.java b/Server/src/main/content/region/asgarnia/burthorpe/handlers/BurthorpeTrainNPC.java index 518c70715..36db1cfee 100644 --- a/Server/src/main/content/region/asgarnia/burthorpe/handlers/BurthorpeTrainNPC.java +++ b/Server/src/main/content/region/asgarnia/burthorpe/handlers/BurthorpeTrainNPC.java @@ -126,7 +126,7 @@ public class BurthorpeTrainNPC extends AbstractNPC { case 1061:// sergant sendChat(MESSAGES[RandomFunction.random(MESSAGES.length)]); delay = System.currentTimeMillis() + 9000 + RandomFunction.random(1000, 5000); - final List soldiers = RegionManager.getLocalNpcs(this); + final List soldiers = RegionManager.getLocalNPCs(location); NPC soldier = null; while (soldier == null) { soldier = soldiers.get(RandomFunction.random(soldiers.size())); @@ -164,7 +164,7 @@ public class BurthorpeTrainNPC extends AbstractNPC { GameWorld.getPulser().submit(new Pulse(2) { @Override public boolean pulse() { - final List soldiers = RegionManager.getLocalNpcs(BurthorpeTrainNPC.this, 12); + final List soldiers = RegionManager.getLocalNPCs(location, 12); for (NPC n : soldiers) { if (n.getId() != 1064) { continue; diff --git a/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/dummy/DummyRoom.java b/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/dummy/DummyRoom.java index bc1ad6f5a..6a9a2e1a1 100644 --- a/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/dummy/DummyRoom.java +++ b/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/dummy/DummyRoom.java @@ -111,12 +111,18 @@ public final class DummyRoom extends OptionHandler { setDelay(10); timeStamp = GameWorld.getTicks(); dummy = RandomFunction.getRandomElement(Dummy.values()); - SceneryBuilder.replace(RegionManager.getObject(dummy.getObject().getLocation()), dummy.getObject(), 11); + Scenery dummyObject = RegionManager.getObject(dummy.getObject().getLocation()); + if (dummyObject != null) { + SceneryBuilder.replace(dummyObject, dummy.getObject(), 11); + } activeDummy = true; if (dummy == Dummy.CONTROLLED && controlled == null) { Location l = Location.create(2860, 3551, 0); controlled = new Scenery(dummy.getObject().getId(), l, 10, 1); - SceneryBuilder.replace(RegionManager.getObject(l), controlled, 11); + Scenery controlledObject = RegionManager.getObject(l); + if (controlledObject != null) { + SceneryBuilder.replace(controlledObject, controlled, 11); + } } return false; } diff --git a/Server/src/main/content/region/asgarnia/falador/diary/FaladorAchievementDiary.kt b/Server/src/main/content/region/asgarnia/falador/diary/FaladorAchievementDiary.kt index aac922c9a..93a55d438 100644 --- a/Server/src/main/content/region/asgarnia/falador/diary/FaladorAchievementDiary.kt +++ b/Server/src/main/content/region/asgarnia/falador/diary/FaladorAchievementDiary.kt @@ -143,7 +143,7 @@ class FaladorAchievementDiary : DiaryEventHookBase(DiaryType.FALADOR) { ) override fun onInteracted(player: Player, event: InteractionEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12084 -> { if (event.option == "burst" && event.target.id in PARTY_BALLOONS) { finishTask( @@ -179,7 +179,7 @@ class FaladorAchievementDiary : DiaryEventHookBase(DiaryType.FALADOR) { } override fun onResourceProduced(player: Player, event: ResourceProducedEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 11828 -> when (event.itemId) { Items.YEW_LOGS_1515, Items.MAGIC_LOGS_1513 -> { if (inBorders(player, PARK_TREE_PATCH_AREA)) { @@ -195,7 +195,7 @@ class FaladorAchievementDiary : DiaryEventHookBase(DiaryType.FALADOR) { } override fun onNpcKilled(player: Player, event: NPCKillEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 11828 -> if (event.npc.id in PARK_DUCKS && inBorders(event.npc, PARK_POND_AREA)) { finishTask( player, diff --git a/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java b/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java index 20edbb3ac..e9f3735e5 100644 --- a/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java +++ b/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java @@ -26,6 +26,7 @@ import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.impl.DarkZone; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; diff --git a/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java b/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java index 51fa14058..7910ec29c 100644 --- a/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java +++ b/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java @@ -201,7 +201,7 @@ public class FortressGuardDialogue extends DialoguePlugin { case 54: end(); DoorActionHandler.handleAutowalkDoor(player, RegionManager.getObject(0, 3020, 3515)); - List npcs = RegionManager.getLocalNpcs(player); + List npcs = RegionManager.getLocalNPCs(player.getLocation()); for (NPC npc : npcs) { if (npc.getId() == 179) { npc.getProperties().getCombatPulse().attack(player); diff --git a/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java b/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java index 0c34e38d0..e5128d1ba 100644 --- a/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java +++ b/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java @@ -103,7 +103,7 @@ public final class GoblinVillageNPC extends AbstractNPC { if (delay < System.currentTimeMillis() && !getProperties().getCombatPulse().isAttacking()) { final int rand = RandomFunction.random(1, 4); if (rand == 2) { - final List surronding = RegionManager.getLocalNpcs(this, 10); + final List surronding = RegionManager.getLocalNPCs(location, 10); for (NPC n : surronding) { if (n.getId() == getId()) { continue; diff --git a/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillagePopulationListener.kt b/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillagePopulationListener.kt index 401d09d54..79102017a 100644 --- a/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillagePopulationListener.kt +++ b/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillagePopulationListener.kt @@ -3,14 +3,14 @@ package content.region.asgarnia.goblinvillage.handlers import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.node.entity.combat.DeathTask -import core.game.world.map.RegionManager.getLocalNpcs +import core.game.world.map.RegionManager.getLocalNPCs import org.rs09.consts.Scenery class GoblinVillagePopulationListener : InteractionListener{ override fun defineListeners() { on(Scenery.SIGNPOST_31301, IntType.SCENERY, "read") { player, node -> var population = 3 // This covers General Wartface, General Bentnoze and Grubfoot - val npcs = getLocalNpcs(player, 50) // This radius covers more than the goblin village. + val npcs = getLocalNPCs(player.location, 50) // This radius covers more than the goblin village. // There should be 18 Goblins walking around. // 10 are within the village walls where the generals are. // 8 of them are fighting each other on the west of the path to the village. diff --git a/Server/src/main/content/region/asgarnia/handlers/WineOfZamorakInteraction.kt b/Server/src/main/content/region/asgarnia/handlers/WineOfZamorakInteraction.kt index d908028b4..f11eef2a7 100644 --- a/Server/src/main/content/region/asgarnia/handlers/WineOfZamorakInteraction.kt +++ b/Server/src/main/content/region/asgarnia/handlers/WineOfZamorakInteraction.kt @@ -15,7 +15,7 @@ class WineOfZamorakInteraction : InteractionListener { PickupHandler.take(player, wine as GroundItem) return@on true } - val npcs = RegionManager.getLocalNpcs(player) + val npcs = RegionManager.getLocalNPCs(player.location) for (n in npcs) { if (n.id == 188) { n.sendChat("Hands off zamorak's wine!") diff --git a/Server/src/main/content/region/asgarnia/taverley/dialogue/PetshopOwnerTaverly.java b/Server/src/main/content/region/asgarnia/taverley/dialogue/PetshopOwnerTaverly.java index 39f24867c..42a750302 100644 --- a/Server/src/main/content/region/asgarnia/taverley/dialogue/PetshopOwnerTaverly.java +++ b/Server/src/main/content/region/asgarnia/taverley/dialogue/PetshopOwnerTaverly.java @@ -53,7 +53,7 @@ public final class PetshopOwnerTaverly extends DialoguePlugin { @Override public boolean open(Object... args) { if (args.length > 1) { - List npcs = RegionManager.getLocalNpcs(player); + List npcs = RegionManager.getLocalNPCs(player.getLocation()); for (NPC n : npcs) { if (n.getId() == 6893) { npc = n; diff --git a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java index 2192bf840..30d12d34a 100644 --- a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java +++ b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java @@ -9,6 +9,8 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Direction; import core.game.world.map.Location; +import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; @@ -28,122 +30,122 @@ import java.util.List; @Initializable public class NoraTHaggNPC extends AbstractNPC { - boolean walkdir; + boolean walkdir; - public NoraTHaggNPC() { - super(896, Location.create(2904, 3463, 0)); - } - private Location getRespawnLocation() { - return Location.create(2900, 3473, 0); - } + public NoraTHaggNPC() { + super(896, Location.create(2904, 3463, 0)); + } + private Location getRespawnLocation() { + return Location.create(2900, 3473, 0); + } - private NoraTHaggNPC(int id, Location location) { - super(id, location); - } + private NoraTHaggNPC(int id, Location location) { + super(id, location); + } - @Override - public Plugin newInstance(Object arg) throws Throwable { - this.configure(); - init(); - return super.newInstance(arg); - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + this.configure(); + init(); + return super.newInstance(arg); + } - private boolean canTeleport(Entity t) { - int playerX = t.getLocation().getX(); - int npcX = getLocation().getX(); - int[] sectors = { 2904, 2907, 2910, 2914, 2918, 2922, 2926, 2928 }; - for (int i = 0; i < sectors.length -1; i++) { - if (npcX >= sectors[i] && npcX <= sectors[i+1] && playerX >= sectors[i] && playerX <= sectors[i+1]) { - if (playerX < npcX && getDirection() == Direction.WEST || playerX > npcX && getDirection() == Direction.EAST) { - return true; - } - if (playerX == npcX) { - return true; - } - } - } - return false; - } + private boolean canTeleport(Entity t) { + int playerX = t.getLocation().getX(); + int npcX = getLocation().getX(); + int[] sectors = { 2904, 2907, 2910, 2914, 2918, 2922, 2926, 2928 }; + for (int i = 0; i < sectors.length -1; i++) { + if (npcX >= sectors[i] && npcX <= sectors[i+1] && playerX >= sectors[i] && playerX <= sectors[i+1]) { + if (playerX < npcX && getDirection() == Direction.WEST || playerX > npcX && getDirection() == Direction.EAST) { + return true; + } + if (playerX == npcX) { + return true; + } + } + } + return false; + } - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new NoraTHaggNPC(id, location); - } + @Override + public AbstractNPC construct(int id, Location location, Object... objects) { + return new NoraTHaggNPC(id, location); + } - @Override - public int[] getIds() { - return new int[] { 896 }; - } + @Override + public int[] getIds() { + return new int[] { 896 }; + } - @Override - public int getWalkRadius() { - return 50; - } + @Override + public int getWalkRadius() { + return 50; + } - public void configure() { - super.configure(); - setWalks(false); - setPathBoundMovement(true); - } + public void configure() { + super.configure(); + setWalks(false); + setPathBoundMovement(true); + } - private void sendTeleport(final Player player) { - player.lock(); - GameWorld.getPulser().submit(new Pulse(1) { - int delay = 0; + private void sendTeleport(final Player player) { + player.lock(); + GameWorld.getPulser().submit(new Pulse(1) { + int delay = 0; - @Override - public boolean pulse() { - if (delay == 0) { - face(player); - player.getInventory().remove(WitchsHousePlugin.BALL); - player.getInventory().remove(WitchsHousePlugin.KEY); - player.getInventory().remove(WitchsHousePlugin.DOOR_KEY); - sendChat("Stop! Thief!"); - player.getPacketDispatch().sendMessage("You've been spotted by the witch."); - player.graphics(new Graphics(110, 100)); - PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2)); - } else if (delay == 2) { - sendChat("Klarata... Seppteno... Valkan!"); - face(null); - } else if (delay == 4) { - player.getProperties().setTeleportLocation(Location.create(getRespawnLocation())); - PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0)); - face(null); - player.unlock(); - return true; - } - delay++; - return false; - } - }); - } + @Override + public boolean pulse() { + if (delay == 0) { + face(player); + player.getInventory().remove(WitchsHousePlugin.BALL); + player.getInventory().remove(WitchsHousePlugin.KEY); + player.getInventory().remove(WitchsHousePlugin.DOOR_KEY); + sendChat("Stop! Thief!"); + player.getPacketDispatch().sendMessage("You've been spotted by the witch."); + player.graphics(new Graphics(110, 100)); + PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2)); + } else if (delay == 2) { + sendChat("Klarata... Seppteno... Valkan!"); + face(null); + } else if (delay == 4) { + player.getProperties().setTeleportLocation(Location.create(getRespawnLocation())); + PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0)); + face(null); + player.unlock(); + return true; + } + delay++; + return false; + } + }); + } - @Override - public void tick() { - super.tick(); - List players = getViewport().getCurrentPlane().getPlayers(); - if(getLocation().getX() == 2930){ - walkdir = false; - } else if(getLocation().getX() == 2904){ - walkdir = true; - } - for (Player player : players) { - if (player == null || !player.isActive() || player.getLocks().isInteractionLocked() || DeathTask.isDead(player) || !canTeleport(player) || !CombatSwingHandler.isProjectileClipped(this, player, false)) { - continue; - } - animate(new Animation(5803)); - sendTeleport(player); - player.getPacketDispatch().sendMessage("" + getLocation() + " matches? " + (getLocation().getX() == 2904)); - } - if (location.getX() != 2930 && walkdir) { - this.getWalkingQueue().reset(); - this.getWalkingQueue().addPath(location.getX() + 1,3463,true); - } else if (location.getX() != 2904 && !walkdir) { - this.getWalkingQueue().reset(); - this.getWalkingQueue().addPath(location.getX() - 1,3463,true); - } - } + @Override + public void tick() { + super.tick(); + List players = RegionManager.getLocalPlayers(location); + if(getLocation().getX() == 2930){ + walkdir = false; + } else if(getLocation().getX() == 2904){ + walkdir = true; + } + for (Player player : players) { + if (player == null || !player.isActive() || player.getLocks().isInteractionLocked() || DeathTask.isDead(player) || !canTeleport(player) || !CombatSwingHandler.isProjectileClipped(this, player, false)) { + continue; + } + animate(new Animation(5803)); + sendTeleport(player); + player.getPacketDispatch().sendMessage("" + getLocation() + " matches? " + (getLocation().getX() == 2904)); + } + if (location.getX() != 2930 && walkdir) { + this.getWalkingQueue().reset(); + this.getWalkingQueue().addPath(location.getX() + 1,3463,true); + } else if (location.getX() != 2904 && !walkdir) { + this.getWalkingQueue().reset(); + this.getWalkingQueue().addPath(location.getX() - 1,3463,true); + } + } } diff --git a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java index 5f1e46e06..8a99ad831 100644 --- a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java +++ b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java @@ -19,165 +19,165 @@ import core.plugin.Initializable; @Initializable public class WitchsExperimentNPC extends AbstractNPC { - private ExperimentType type; - private boolean commenced; - Player p; + private ExperimentType type; + private boolean commenced; + Player p; - public WitchsExperimentNPC() { - super(0, null); - } + public WitchsExperimentNPC() { + super(0, null); + } - WitchsExperimentNPC(int id, Location location, Player player) { - super(id, location); - this.setWalks(true); - this.setRespawn(false); - this.type = WitchsExperimentNPC.ExperimentType.forId(id); - p = player; - } + WitchsExperimentNPC(int id, Location location, Player player) { + super(id, location); + this.setWalks(true); + this.setRespawn(false); + this.type = WitchsExperimentNPC.ExperimentType.forId(id); + p = player; + } - @Override - public void handleTickActions() { - super.handleTickActions(); - if(!p.isActive() || !RegionManager.getLocalPlayers(this).contains(p)){ - p.removeAttribute("witchs-experiment:npc_spawned"); - clear(); - } - if (!getProperties().getCombatPulse().isAttacking()) { - getProperties().getCombatPulse().attack(p); - } - } + @Override + public void handleTickActions() { + super.handleTickActions(); + if (!p.isActive() || !RegionManager.getLocalPlayers(location).contains(p)) { + p.removeAttribute("witchs-experiment:npc_spawned"); + clear(); + } + if (!getProperties().getCombatPulse().isAttacking()) { + getProperties().getCombatPulse().attack(p); + } + } - @Override - public void startDeath(Entity killer) { - if (killer == p) { - type.transform(this, p); - return; - } - super.startDeath(killer); - } + @Override + public void startDeath(Entity killer) { + if (killer == p) { + type.transform(this, p); + return; + } + super.startDeath(killer); + } - @Override - public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { - return p == entity; - } + @Override + public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { + return p == entity; + } - @Override - public boolean canSelectTarget(Entity target) { - if (target instanceof Player) { - Player p = (Player) target; - return p == this.p; - } - return true; - } + @Override + public boolean canSelectTarget(Entity target) { + if (target instanceof Player) { + Player p = (Player) target; + return p == this.p; + } + return true; + } - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new WitchsExperimentNPC(id, location, null); - } + @Override + public AbstractNPC construct(int id, Location location, Object... objects) { + return new WitchsExperimentNPC(id, location, null); + } - @Override - public int[] getIds() { - return new int[] { 897, 898, 899, 900 }; - } + @Override + public int[] getIds() { + return new int[] { 897, 898, 899, 900 }; + } - public void setType(ExperimentType type) { - this.type = type; - } + public void setType(ExperimentType type) { + this.type = type; + } - public ExperimentType getType() { - return type; - } + public ExperimentType getType() { + return type; + } - public void setCommenced(boolean commenced) { - this.commenced = commenced; - } + public void setCommenced(boolean commenced) { + this.commenced = commenced; + } - public enum ExperimentType { - FIRST(897, ""), - SECOND(898, "The shapeshifter's body begins to deform!", "The shapeshifter turns into a spider!"), - THIRD(899, "The shapeshifter's body begins to twist!", "The shapeshifter turns into a bear!"), - FOURTH(900, "The shapeshifter's body pulses!", "The shapeshifter turns into a wolf!"), - END(-1, ""), + public enum ExperimentType { + FIRST(897, ""), + SECOND(898, "The shapeshifter's body begins to deform!", "The shapeshifter turns into a spider!"), + THIRD(899, "The shapeshifter's body begins to twist!", "The shapeshifter turns into a bear!"), + FOURTH(900, "The shapeshifter's body pulses!", "The shapeshifter turns into a wolf!"), + END(-1, ""), - ; + ; - private int id; - private String[] message; + private int id; + private String[] message; - ExperimentType(int id, String... message) { - this.id = id; - this.message = message; - } + ExperimentType(int id, String... message) { + this.id = id; + this.message = message; + } - /** - * Transforms the new npc. - */ - public void transform(final WitchsExperimentNPC npc, final Player player) { - final ExperimentType newType = next(); - npc.lock(); - npc.getPulseManager().clear(); - npc.getWalkingQueue().reset(); - player.setAttribute("/save:witchs_house:experiment_id",this.id); - GameWorld.getPulser().submit(new Pulse(1, npc, player) { - int counter; + /** + * Transforms the new npc. + */ + public void transform(final WitchsExperimentNPC npc, final Player player) { + final ExperimentType newType = next(); + npc.lock(); + npc.getPulseManager().clear(); + npc.getWalkingQueue().reset(); + player.setAttribute("/save:witchs_house:experiment_id",this.id); + GameWorld.getPulser().submit(new Pulse(1, npc, player) { + int counter; - @Override - public boolean pulse() { - switch (++counter) { + @Override + public boolean pulse() { + switch (++counter) { - case 1: - npc.unlock(); - npc.getAnimator().reset(); - npc.fullRestore(); - npc.setType(newType); - npc.transform(newType.getId()); - npc.getImpactHandler().setDisabledTicks(1); - if (newType != END) { - npc.getProperties().getCombatPulse().attack(player); - } - if (newType.getMessage() != null && newType != END) { - player.sendMessage(newType.getMessage()[0]); - player.sendMessage(newType.getMessage()[1]); - } - if (newType == END) { - player.setAttribute("witchs_house:experiment_killed",true); - npc.clear(); - return false; - } - player.unlock(); - return true; - } - return false; - } + case 1: + npc.unlock(); + npc.getAnimator().reset(); + npc.fullRestore(); + npc.setType(newType); + npc.transform(newType.getId()); + npc.getImpactHandler().setDisabledTicks(1); + if (newType != END) { + npc.getProperties().getCombatPulse().attack(player); + } + if (newType.getMessage() != null && newType != END) { + player.sendMessage(newType.getMessage()[0]); + player.sendMessage(newType.getMessage()[1]); + } + if (newType == END) { + player.setAttribute("witchs_house:experiment_killed",true); + npc.clear(); + return false; + } + player.unlock(); + return true; + } + return false; + } - }); - } + }); + } - public static ExperimentType forId(int id) { - for (ExperimentType type : values()) { - if (type.getId() == id) { - return type; - } - } - return null; - } + public static ExperimentType forId(int id) { + for (ExperimentType type : values()) { + if (type.getId() == id) { + return type; + } + } + return null; + } - private static ExperimentType[] experimentTypes = values(); + private static ExperimentType[] experimentTypes = values(); - public ExperimentType next() - { - return experimentTypes[this.ordinal() + 1]; - } + public ExperimentType next() + { + return experimentTypes[this.ordinal() + 1]; + } - public int getId() { - return id; - } + public int getId() { + return id; + } - public String[] getMessage() { - return message; - } + public String[] getMessage() { + return message; + } - } + } } diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java index 540d48f02..551b314b6 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java @@ -12,8 +12,10 @@ import core.game.node.entity.combat.equipment.ArmourSet; import core.game.node.entity.impl.Projectile; import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.npc.NPC; +import core.game.node.entity.player.Player; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; @@ -66,7 +68,7 @@ public final class GWDGraardorSwingHandler extends CombatSwingHandler { ticks += (int) Math.ceil(entity.getLocation().getDistance(victim.getLocation()) * 0.3); NPC npc = (NPC) entity; List list = new ArrayList<>(20); - for (Entity t : RegionManager.getLocalPlayers(npc, 28)) { + for (Player t : RegionManager.getLocalPlayers(npc.getLocation(), 28)) { if (!CHAMBER.insideBorder(t.getLocation())) { continue; } diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java index 925f917fd..56176d84b 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java @@ -12,10 +12,12 @@ import core.game.node.entity.combat.equipment.ArmourSet; import core.game.node.entity.impl.Projectile; import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.npc.NPC; +import core.game.node.entity.player.Player; import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; @@ -83,7 +85,7 @@ public final class GWDKreeArraSwingHandler extends CombatSwingHandler { ticks += (int) Math.ceil(entity != null ? entity.getLocation().getDistance(victim.getLocation()) : 0.0 * 0.3); NPC npc = (NPC) entity; List list = new ArrayList<>(20); - for (Entity t : RegionManager.getLocalPlayers(npc, 28)) { + for (Player t : RegionManager.getLocalPlayers(npc.getLocation(), 28)) { if (!CHAMBER.insideBorder(t.getLocation())) { continue; } diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java index a1f060d9a..4fa4fea33 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java @@ -11,7 +11,9 @@ import core.game.node.entity.combat.InteractionType; import core.game.node.entity.combat.equipment.ArmourSet; import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.npc.NPC; +import core.game.node.entity.player.Player; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; @@ -59,7 +61,7 @@ public class GWDZilyanaSwingHandler extends CombatSwingHandler { } else { NPC npc = (NPC) entity; List list = new ArrayList<>(20); - for (Entity t : RegionManager.getLocalPlayers(npc.getCenterLocation(), (npc.size() >> 1) + 2)) { + for (Player t : RegionManager.getLocalPlayers(npc.getCenterLocation(), (npc.size() >> 1) + 2)) { if (t.getLocation().getX() < 2908 && t.isAttackable(npc, CombatStyle.MAGIC, false)) { list.add(new BattleState(entity, t)); } diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodWarsNPC.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodWarsNPC.java index 215de9f11..4dae4b212 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodWarsNPC.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodWarsNPC.java @@ -61,7 +61,7 @@ public final class GodWarsNPC extends AbstractNPC { @Override public List getPossibleTargets(Entity entity, int radius) { List targets = new ArrayList<>(20); - for (Player player : RegionManager.getLocalPlayers(entity, radius)) { + for (Player player : RegionManager.getLocalPlayers(entity.getLocation(), radius)) { if (canSelectTarget(entity, player)) { targets.add(player); } @@ -69,7 +69,7 @@ public final class GodWarsNPC extends AbstractNPC { if (!targets.isEmpty()) { return targets; } - for (NPC npc : RegionManager.getLocalNpcs(entity, radius)) { + for (NPC npc : RegionManager.getLocalNPCs(entity.getLocation(), radius)) { if (canSelectTarget(entity, npc)) { targets.add(npc); } @@ -115,9 +115,9 @@ public final class GodWarsNPC extends AbstractNPC { @Override public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { if (style == CombatStyle.MELEE && faction == GodWarsFaction.ARMADYL && entity instanceof Player) { - if(message) { - ((Player) entity).getPacketDispatch().sendMessage("The aviansie is flying too high for you to attack using melee."); - } + if(message) { + ((Player) entity).getPacketDispatch().sendMessage("The aviansie is flying too high for you to attack using melee."); + } return false; } return super.isAttackable(entity, style, message); diff --git a/Server/src/main/content/region/desert/alkharid/handlers/AlKharidWarriorNPC.kt b/Server/src/main/content/region/desert/alkharid/handlers/AlKharidWarriorNPC.kt index ba1b4662d..0f56be285 100644 --- a/Server/src/main/content/region/desert/alkharid/handlers/AlKharidWarriorNPC.kt +++ b/Server/src/main/content/region/desert/alkharid/handlers/AlKharidWarriorNPC.kt @@ -49,7 +49,7 @@ class AlKharidWarriorNPC : AbstractNPC { if (entity is Player) { if (target == null) { target = entity - RegionManager.getLocalNpcs(entity, supportRange).forEach { + RegionManager.getLocalNPCs(entity.location, supportRange).forEach { if (it.id == NPCs.AL_KHARID_WARRIOR_18 && !it.properties.combatPulse.isAttacking && it != this) { it.sendChat("Brother, I shall help thee with this infidel!") it.attack(entity) diff --git a/Server/src/main/content/region/desert/alkharid/quest/princealirescue/LadyKeliDialogue.java b/Server/src/main/content/region/desert/alkharid/quest/princealirescue/LadyKeliDialogue.java index 038567099..2c8985dec 100644 --- a/Server/src/main/content/region/desert/alkharid/quest/princealirescue/LadyKeliDialogue.java +++ b/Server/src/main/content/region/desert/alkharid/quest/princealirescue/LadyKeliDialogue.java @@ -64,7 +64,7 @@ public final class LadyKeliDialogue extends DialoguePlugin { case 60: case 100: npc.sendChat("You tricked me, and tied me up, Guards kill this stranger!"); - List npcc = RegionManager.getLocalNpcs(player); + List npcc = RegionManager.getLocalNPCs(player.getLocation()); for (NPC n : npcc) { if (n.getId() == 917) { n.sendChat("Yes M'lady"); diff --git a/Server/src/main/content/region/desert/bandits/handlers/BanditNPC.kt b/Server/src/main/content/region/desert/bandits/handlers/BanditNPC.kt index 29a7809d1..beadf788e 100644 --- a/Server/src/main/content/region/desert/bandits/handlers/BanditNPC.kt +++ b/Server/src/main/content/region/desert/bandits/handlers/BanditNPC.kt @@ -23,8 +23,7 @@ class BanditNPC(id: Int = NPCs.BANDIT_1926, location: Location? = null) : Abstra override fun tick() { if (!inCombat()) { - val players = RegionManager.getLocalPlayers(this, 5) - for (player in players) { + for (player in RegionManager.getLocalPlayers(location, 5)) { if (player.inCombat()) continue if (hasGodItem(player, God.SARADOMIN)) { sendChat("Time to die, Saradominist filth!") @@ -47,7 +46,7 @@ class BanditNPC(id: Int = NPCs.BANDIT_1926, location: Location? = null) : Abstra override fun onImpact(entity: Entity?, state: BattleState?) { if (entity is Player) { - RegionManager.getLocalNpcs(entity, supportRange).forEach { + RegionManager.getLocalNPCs(entity.location, supportRange).forEach { if (it.id == NPCs.BANDIT_1926 && !it.properties.combatPulse.isAttacking && it != this) { it.sendChat("You picked the wrong place to start trouble!") it.attack(entity) diff --git a/Server/src/main/content/region/desert/bedabin/handlers/BedabinPlugin.java b/Server/src/main/content/region/desert/bedabin/handlers/BedabinPlugin.java index a0a2870a9..99411ee68 100644 --- a/Server/src/main/content/region/desert/bedabin/handlers/BedabinPlugin.java +++ b/Server/src/main/content/region/desert/bedabin/handlers/BedabinPlugin.java @@ -47,7 +47,7 @@ public final class BedabinPlugin extends OptionHandler { player.getPacketDispatch().sendMessage("You walk back out the tent."); break; } - player.getDialogueInterpreter().open(834, RegionManager.getNpc(player, 834)); + player.getDialogueInterpreter().open(834, RegionManager.getNpc(player.getLocation(), 834, 16)); break; } break; diff --git a/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java b/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java index 39dbc9399..7637a1baf 100644 --- a/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java +++ b/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java @@ -19,6 +19,7 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; @@ -211,7 +212,7 @@ public final class KalphiteQueenNPC extends AbstractNPC { */ private BattleState[] getRangeTargets(Entity e, Entity victim) { List list = new ArrayList<>(20); - for (Entity t : RegionManager.getLocalPlayers(victim, -1 + (int) e.getCenterLocation().getDistance(victim.getLocation()))) { + for (Player t : RegionManager.getLocalPlayers(victim.getLocation(), -1 + (int) e.getCenterLocation().getDistance(victim.getLocation()))) { if (t.isAttackable(e, CombatStyle.RANGE, false)) { list.add(new BattleState(e, t)); } @@ -315,12 +316,12 @@ public final class KalphiteQueenNPC extends AbstractNPC { return; } if (style == CombatStyle.MAGIC) { - BattleState[] states = new BattleState[entity.getViewport().getCurrentPlane().getPlayers().size() + 1]; + BattleState[] states = new BattleState[RegionManager.getLocalPlayers(entity.getLocation()).size() + 1]; int index = 1; if (states.length == 0) { return; } - for (Player p : entity.getViewport().getCurrentPlane().getPlayers()) { + for (Player p : RegionManager.getLocalPlayers(entity.getLocation())) { if (p != victim) { states[index++] = new BattleState(entity, p); } diff --git a/Server/src/main/content/region/desert/handlers/KhardianInteractionPlugin.java b/Server/src/main/content/region/desert/handlers/KhardianInteractionPlugin.java index c2dbc4200..89d5dc1ab 100644 --- a/Server/src/main/content/region/desert/handlers/KhardianInteractionPlugin.java +++ b/Server/src/main/content/region/desert/handlers/KhardianInteractionPlugin.java @@ -80,7 +80,7 @@ public final class KhardianInteractionPlugin extends OptionHandler { if (!failed) { player.getSkills().addExperience(Skills.WOODCUTTING, 10, true); } - SceneryBuilder.replace(((Scenery) node), new Scenery(DRY_CACTUS, node.getLocation()), SPAWN_DELAY + RandomFunction.random(RegionManager.getLocalPlayers(player).size() / 2)); + SceneryBuilder.replace(((Scenery) node), new Scenery(DRY_CACTUS, node.getLocation()), SPAWN_DELAY + RandomFunction.random(RegionManager.getLocalPlayers(player.getLocation()).size() / 2)); break; } return true; diff --git a/Server/src/main/content/region/desert/quest/thetouristrap/AnaDialogue.java b/Server/src/main/content/region/desert/quest/thetouristrap/AnaDialogue.java index efb949796..ed8bb63a9 100644 --- a/Server/src/main/content/region/desert/quest/thetouristrap/AnaDialogue.java +++ b/Server/src/main/content/region/desert/quest/thetouristrap/AnaDialogue.java @@ -108,7 +108,7 @@ public final class AnaDialogue extends DialoguePlugin { case 3: player.getInventory().add(TouristTrap.WROUGHT_IRON_KEY, player); player.getPacketDispatch().sendMessage("Ana spots Irena and waves..."); - NPC irena = RegionManager.getNpc(player, 4986); + NPC irena = RegionManager.getNpc(player.getLocation(), 4986, 16); irena.sendChat("Hi Ana!"); quest.setStage(player, 98); end(); diff --git a/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java b/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java index 9c9a08367..623a4ecef 100644 --- a/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java +++ b/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java @@ -12,6 +12,7 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.plugin.ClassScanner; import core.tools.RandomFunction; @@ -307,8 +308,8 @@ public final class DesertGuardDialogue extends DialoguePlugin { * Method used to warn players whom are breaking rules. */ private void warn() { - final List players = RegionManager.getLocalPlayers(this); - for (final Player player : players) { + final List players = RegionManager.getLocalPlayers(location); + for (Player player : players) { if (player.getAttribute("guard-warning", 0) > GameWorld.getTicks() || !player.getZoneMonitor().isInZone("mining camp") || player.inCombat() || !player.getLocation().withinDistance(this.getLocation(), 8)) { continue; } diff --git a/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java b/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java index 463d61272..e486577e7 100644 --- a/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java +++ b/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java @@ -49,1653 +49,1653 @@ import static core.api.ContentAPIKt.*; */ public final class TouristTrapPlugin extends OptionHandler { - @Override - public Plugin newInstance(Object arg) throws Throwable { - SceneryDefinition.forId(2673).getHandlers().put("option:open", this); - SceneryDefinition.forId(2674).getHandlers().put("option:open", this); - SceneryDefinition.forId(2673).getHandlers().put("option:search", this); - SceneryDefinition.forId(2674).getHandlers().put("option:search", this); - SceneryDefinition.forId(2688).getHandlers().put("option:open", this); - SceneryDefinition.forId(2688).getHandlers().put("option:search", this); - SceneryDefinition.forId(2687).getHandlers().put("option:open", this); - SceneryDefinition.forId(2687).getHandlers().put("option:search", this); - SceneryDefinition.forId(2685).getHandlers().put("option:open", this); - SceneryDefinition.forId(2685).getHandlers().put("option:open", this); - SceneryDefinition.forId(2686).getHandlers().put("option:search", this); - SceneryDefinition.forId(2686).getHandlers().put("option:search", this); - SceneryDefinition.forId(18958).getHandlers().put("option:search", this); - SceneryDefinition.forId(18958).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18959).getHandlers().put("option:search", this); - SceneryDefinition.forId(18959).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18888).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18888).getHandlers().put("option:operate", this); - SceneryDefinition.forId(36748).getHandlers().put("option:talk-to", this); - SceneryDefinition.forId(18869).getHandlers().put("option:bend", this); - SceneryDefinition.forId(18870).getHandlers().put("option:escape", this); - SceneryDefinition.forId(2689).getHandlers().put("option:open", this); - SceneryDefinition.forId(1528).getHandlers().put("option:open", this); - SceneryDefinition.forId(1529).getHandlers().put("option:close", this); - SceneryDefinition.forId(18899).getHandlers().put("option:search", this); - SceneryDefinition.forId(18899).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18878).getHandlers().put("option:search", this); - SceneryDefinition.forId(18878).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18879).getHandlers().put("option:search", this); - SceneryDefinition.forId(18879).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18898).getHandlers().put("option:search", this); - SceneryDefinition.forId(18898).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18902).getHandlers().put("option:search", this); - SceneryDefinition.forId(18871).getHandlers().put("option:climb", this); - SceneryDefinition.forId(18923).getHandlers().put("option:climb-up", this); - SceneryDefinition.forId(18924).getHandlers().put("option:climb-down", this); - SceneryDefinition.forId(2676).getHandlers().put("option:open", this); - SceneryDefinition.forId(2675).getHandlers().put("option:open", this); - SceneryDefinition.forId(2676).getHandlers().put("option:watch", this); - SceneryDefinition.forId(2675).getHandlers().put("option:watch", this); - SceneryDefinition.forId(2690).getHandlers().put("option:open", this); - SceneryDefinition.forId(2691).getHandlers().put("option:open", this); - SceneryDefinition.forId(2698).getHandlers().put("option:walk through", this); - SceneryDefinition.forId(2699).getHandlers().put("option:walk through", this); - SceneryDefinition.forId(2677).getHandlers().put("option:open", this); - SceneryDefinition.forId(2678).getHandlers().put("option:search", this); - SceneryDefinition.forId(2684).getHandlers().put("option:search", this); - SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); - SceneryDefinition.forId(2680).getHandlers().put("option:search", this); - SceneryDefinition.forId(2680).getHandlers().put("option:look-in", this); - SceneryDefinition.forId(2681).getHandlers().put("option:search", this); - SceneryDefinition.forId(2681).getHandlers().put("option:look in", this); - SceneryDefinition.forId(18962).getHandlers().put("option:search", this); - SceneryDefinition.forId(18962).getHandlers().put("option:look in", this); - SceneryDefinition.forId(18963).getHandlers().put("option:search", this); - SceneryDefinition.forId(18963).getHandlers().put("option:look in", this); - SceneryDefinition.forId(18951).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18951).getHandlers().put("option:use", this); - SceneryDefinition.forId(2684).getHandlers().put("option:search", this); - SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18875).getHandlers().put("option:inspect", this); - NPCDefinition.forId(830).getHandlers().put("option:watch", this); - NPCDefinition.forId(4975).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(4976).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(4977).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(4978).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(5002).getHandlers().put("option:talk-to", this); - TouristTrap.TECHNICAL_PLANS.getDefinition().getHandlers().put("option:read", this); - TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:look", this); - TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:drop", this); - ClassScanner.definePlugin(new BedabinKeyHandler()); - ClassScanner.definePlugin(new BedabinAnvilHandler()); - ClassScanner.definePlugin(new BarrelDialogue()); - ClassScanner.definePlugin(new WinchDialogue()); - ClassScanner.definePlugin(new MineCartDialogue()); - ClassScanner.definePlugin(new AnnaCartHandler()); - ClassScanner.definePlugin(new AnnaCartCutscene()); - ClassScanner.definePlugin(new AnnaWinchHandler()); - ClassScanner.definePlugin(new WinchCutscene()); - ClassScanner.definePlugin(new CartDialogue()); - return this; - } - - @Override - public boolean handle(final Player player, Node node, String option) { - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - final int id = node.getId(); - switch (option) { - case "read": - player.getDialogueInterpreter().sendDialogue("The plans look very technical! But you can see that this item will", "require a bronze bar and at least 10 feathers."); - break; - case "watch": - switch (id) { - case 2676: - case 2675: - player.getDialogueInterpreter().sendDialogue("You watch the doors for some time. You notice that only slaves seem", "to do down there. You might be able to sneak down if you pass as a", "slave."); - break; - default: - player.getDialogueInterpreter().sendDialogue("You watch the Mercenary Captain for some time. He has a large", "metal key attached to his belt. You notice that he usually gets his", "men to do his dirty work."); - break; - } - break; - case "walk through": - switch (id) { - case 2698: - case 2699: - if (quest.getStage(player) < 60) { - player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you! You're not allowed in there."); - break; - } - if (!TouristTrap.hasSlaveClothes(player)) { - player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you're not a slave!"); - break; - } - player.getProperties().setTeleportLocation(player.getLocation().transform(player.getLocation().getX() >= 3284 ? -4 : 4, 0, 0)); - player.getPacketDispatch().sendMessages("You walk into the darkness of the cavern...", "... and emerge in a different part of this huge underground complex."); - break; - } - break; - case "look": - player.getDialogueInterpreter().sendDialogues(823, null, "Let me out of here, I feel sick!"); - break; - case "drop": - player.getDialogueInterpreter().sendDialogues(823, null, "Don't let me out!"); - break; - case "open": - switch (id) { - case 2688: - case 2687: - if (!player.getInventory().containsItem(TouristTrap.WROUGHT_IRON_KEY)) { - player.getPacketDispatch().sendMessage("This gate looks like it needs a key to open it."); - break; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - break; - case 2686: - case 2685: - player.getDialogueInterpreter().sendDialogues(4999, null, "Hey, move away from the gate. There's nothing", "interesting for you here."); - break; - case 2677: - if (!player.getInventory().containsItem(TouristTrap.BEDABIN_KEY)) { - player.getPacketDispatch().sendMessage("This chest needs a key to unlock it."); - break; - } - if (quest.getStage(player) <= 54 && quest.getStage(player) != 53) { - player.getPacketDispatch().sendMessage("The captain spots you before you manage to open the chest..."); - player.lock(3); - GameWorld.getPulser().submit(new Pulse(2, player) { - @Override - public boolean pulse() { - player.getDialogueInterpreter().open(831, RegionManager.getNpc(player, 831)); - return true; - } - }); - } else if (quest.getStage(player) == 53) { - if (!player.hasItem(TouristTrap.TECHNICAL_PLANS)) { - player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "While the Captain's distracted, you quickly unlock the", "chest with the Bedabins' copy of the key. You take out", "the plans."); - player.getInventory().add(TouristTrap.TECHNICAL_PLANS, player); - } - } - break; - case 2690: - case 2691: - player.setAttribute("ana-delay", GameWorld.getTicks() + 2); - player.getProperties().setTeleportLocation(Location.create(3301, 3035, 0)); - break; - case 2676: - case 2675: - if (!TouristTrap.hasSlaveClothes(player)) { - player.getDialogueInterpreter().sendDialogues(4997, null, "Watch it! Only slaves can travel into the mine."); - break; - } - player.setAttribute("ana-delay", GameWorld.getTicks() + 2); - player.getProperties().setTeleportLocation(Location.create(3278, 9427, 0)); - player.getDialogueInterpreter().sendDialogue("The huge doors open into a dark, dank and smelly tunnel. The", "associated smells of a hundred sweaty miners greets your nostrils.", "And your ears ring with the 'CLANG CLANG CLANG' as metal hits", "rock."); - break; - case 2674: - case 2673: - if (quest.getStage(player) > 60 && quest.getStage(player) < 98 && player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { - player.lock(); - player.getDialogueInterpreter().sendDialogues(4999, null, true, "Would you like me to take that heavy barrel", "for you?"); - GameWorld.getPulser().submit(new Pulse(4, player) { - int counter; - - @Override - public boolean pulse() { - switch (++counter) { - case 1: - player.getDialogueInterpreter().sendDialogues(player, null, "No, please don't."); - break; - case 2: - player.getDialogueInterpreter().close(); - player.getPacketDispatch().sendMessage("The guards search you!"); - break; - case 3: - player.getPacketDispatch().sendMessage("You are roughed up by the guards and manhandled into a cell."); - break; - case 4: - player.unlock(); - player.getInventory().remove(TouristTrap.ANNA_BARREL); - TouristTrap.addConfig(player, (1 << 4)); - quest.setStage(player, 61); - player.getProperties().setTeleportLocation(Location.create(3285, 3034, 0)); - return true; - } - return false; - } - }); - return true; - } - if (node.getLocation().withinDistance(new Location(3273, 3028, 0)) && !((player.getLocation().getX() >= 3274))) { - if (!player.getInventory().containsItem(TouristTrap.METAL_KEY)) { - player.getPacketDispatch().sendMessage("The gate needs a key in order to be opened."); - return true; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - player.getPacketDispatch().sendMessage("The guards search you thoroughly as you go through the gates."); - return true; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - break; - case 2689: - if (!player.getInventory().containsItem(TouristTrap.CELL_DOOR_KEY)) { - player.getPacketDispatch().sendMessage("The door seems to be pretty locked."); - break; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - break; - case 1528: - SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1529)); - break; - } - break; - case "close": - if (id == 1529) { - SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1528)); - } - break; - case "look-in": - case "look in": - switch (id) { - case 2681: - case 18962: - case 18963: - player.getDialogueInterpreter().sendDialogue("This looks like an empty mining barrel. Slaves use this to load up the", "rocks and stones that they're mining."); - break; - case 2680: - player.getDialogueInterpreter().sendDialogue("You search the full barrel... It's full of rocks."); - break; - } - break; - case "use": - if (id == 18951) { - player.getDialogueInterpreter().open("winch dialogue"); - } - break; - case "search": - switch (id) { - case 2688: - case 2687: - player.getDialogueInterpreter().sendDialogue("These wrought iron gates look like they're designed to keep people out.", "it looks like you'll need a key to get past these."); - break; - case 2686: - case 2685: - player.getDialogueInterpreter().sendDialogue("It looks as if this is where very difficult prisoners are sent as a", "punishment."); - break; - case 2681: - case 18962: - case 18963: - player.getDialogueInterpreter().open("barrel dialogue", node); - break; - case 2680:// barrel of rocks. - player.getDialogueInterpreter().sendDialogue("This looks like a full mining barrel. Slaves use this to load up the", "rocks and stones that they're mining. This barrel is full of rocks."); - break; - case 2684:// cart - player.getDialogueInterpreter().open("cart dialogue", node); - break; - case 2678: - if (quest.getStage(player) == 51) { - quest.setStage(player, 52); - } - player.getDialogueInterpreter().sendItemMessage(9904, "You notice several books on the subject of sailing."); - break; - case 2673: - case 2674: - player.getDialogueInterpreter().sendDialogue("You see what looks like a mining compound. There seems to be people", "mining rocks. They look as if they're chained to the rocks and they're", "being watched over by the guards. It's not a very happy place."); - break; - case 18958: - case 18959: - if (quest.getStage(player) == 90) { - player.getDialogueInterpreter().open("ana cart dialogue"); - break; - } - player.getPacketDispatch().sendMessage("This looks like a mine cart which takes barrels out of the encampment to Al Kharid."); - break; - case 18899: - case 18898: - case 18878: - case 18879: - player.getDialogueInterpreter().sendDialogue("You search the footsteps more closely. You can see that there are", "five sets of footprints. One set of footprints seem lighter than the", "others. The four other footsteps were made by heavier people", "with boots."); - break; - case 18902: - if (hasItem(player, TouristTrap.CELL_DOOR_KEY)) { - player.getInventory().add(TouristTrap.CELL_DOOR_KEY, player); - player.getDialogueInterpreter().sendItemMessage(TouristTrap.CELL_DOOR_KEY, "You find a cell door key."); - break; - } else if (hasItem(player, TouristTrap.WROUGHT_IRON_KEY) && player.getQuestRepository().isComplete(Quests.THE_TOURIST_TRAP)) { - player.getInventory().add(TouristTrap.WROUGHT_IRON_KEY, player); - player.getDialogueInterpreter().sendItemMessage(TouristTrap.WROUGHT_IRON_KEY, "You find the key to the main gate."); - break; - } - player.getPacketDispatch().sendMessage("You search the captains desk while he's not looking..."); - player.getPacketDispatch().sendMessage("...but you find nothing of interest."); - break; - } - break; - case "operate": - if (quest.getStage(player) != 71) { - player.getDialogueInterpreter().sendDialogue("There doesn't seem anything to lift."); - break; - } - ActivityManager.start(player, "winch cutscene", false); - break; - case "look at": - switch (id) { - case 18888: - player.getDialogueInterpreter().sendDialogue("This looks like a winch, it probably brings rocks up from", "underground."); - break; - case 18951: - player.getDialogueInterpreter().sendDialogue("This looks like a lift of some sort. You see barrels of rocks being", "placed on the lift and they're hauled up to the surface."); - break; - case 2684: - if (node.getLocation().getX() == 3318) { - player.getDialogueInterpreter().sendDialogue("This mine cart is being loaded up with new rocks and stone.", "It gets sent to a different section of the mine for unloading."); - break; - } - player.getDialogueInterpreter().sendDialogue("This cart is being unloaded into this section of the mine. Before being", "sent back to another section for another load."); - break; - case 18958: - case 18959: - player.getDialogueInterpreter().sendDialogue("A sturdy looking cart for carrying barrels of rocks out of ", "the mining camp."); - break; - case 18900: - case 18899: - case 18898: - case 18887: - case 18886: - case 18885: - case 18884: - case 18883: - case 18882: - case 18881: - case 18880: - case 18879: - case 18878: - case 18877: - player.getDialogueInterpreter().sendDialogue("This looks like some disturbed sand. Footsteps seem to be heading off", "towards the South."); - break; - } - break; - case "talk-to": - switch (id) { - case 5002: - ((NPC) node).sendChat("Move along please, don't want any trouble today!"); - break; - case 36748: - player.getDialogueInterpreter().sendDialogues(player, null, "Mmm... looks like that camel would make a nice kebab."); - break; - case 4975: - case 4977: - case 4978: - case 4976: - ((NPC) node).sendChat("Hey leave me alone, can't you see that i'm busy?"); - break; - } - break; - case "bend": - player.animate(Animation.create(5037)); - GameWorld.getPulser().submit(new Pulse(5, player) { - @Override - public boolean pulse() { - player.getPacketDispatch().sendMessage("You bend the bars back."); - setVarp(player, 907, getVarp(player, 907) + 1); - return true; - } - }); - break; - case "escape": - player.getPacketDispatch().sendMessage("You prepare to squeeze through the bars."); - AgilityHandler.forceWalk(player, 0, player.getLocation(), player.getLocation().transform(player.getLocation().getX() <= node.getLocation().getX() ? 1 : -1, 0, 0), Animation.create(5038), 4, 0.0, null); - break; - case "climb": - player.getPacketDispatch().sendMessage("You scrape your hands and knees as you climb up."); - AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3279, 3037, 0), Animation.create(5041), 10, 0, null); - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.getAnimator().reset(); - return true; - } - }); - break; - case "climb-up": - if (id == 18923) { - if (player.getLocation().getX() <= 3278) { - return true; - } - player.animate(Animation.create(5039)); - GameWorld.getPulser().submit(new Pulse(6, player) { - @Override - public boolean pulse() { - player.getAnimator().reset(); - player.getProperties().setTeleportLocation(Location.create(3278, 3037, 0)); - return true; - } - }); - } - break; - case "climb-down": - if (id == 18924) { - if (player.getLocation().getX() <= 3273) { - return true; - } - AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3270, 3039, 0), Animation.create(5040), 20, 0, null); - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.getAnimator().reset(); - return true; - } - }); - } - break; - case "inspect": - if (id == 18875) { - sendDialogue(player, "You remember that Irena mentioned something about Ana wearing a red scarf before she left for the desert."); - } - break; - } - return true; - } - - @Override - public boolean isWalk(final Player player, Node node) { - return !(node instanceof Item); - } - - @Override - public boolean isWalk() { - return false; - } - - @Override - public Location getDestination(Node node, Node n) { - if (n.getId() == 18923) { - return new Location(3279, 3037, 0); - } - return null; - } - - /** - * Checks if the player contains an item. - * - * @param player the player. - * @param item the item. - * @return the item. - */ - private boolean hasItem(final Player player, final Item item) { - return !player.getInventory().containsItem(item) && !player.getBank().containsItem(item); - } - - /** - * The winch dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class WinchDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code WinchDialogue} {@code Object}. - */ - public WinchDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code WinchDialogue} {@code Object}. - * - * @param player the player. - */ - public WinchDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new WinchDialogue(player); - } - - @Override - public boolean open(Object... args) { - if (args.length >= 1) { - interpreter.sendDialogue("The guard notices the barrel (with Ana in it) that you're carrying."); - stage = 500; - return true; - } - interpreter.sendDialogues(4999, null, "Hey there, what do you want?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 500:// winch - interpreter.sendDialogues(5002, null, "Hey, that Barrel looks heavy, do you need a hand?"); - stage++; - break; - case 501: - player("Yes please."); - stage++; - break; - case 502: - interpreter.sendDialogue("The guard comes over and helps you. He takes one end of the", "barrel."); - stage++; - break; - case 503: - interpreter.sendDialogues(5002, null, "Blimey! This is heavy!"); - stage++; - break; - case 504: - interpreter.sendDialogues(823, null, "Why you cheeky....!"); - stage++; - break; - case 505: - interpreter.sendDialogues(5002, null, "- The guard looks around surprised at Ana's outburst. -", "What was that?"); - stage++; - break; - case 506: - player("Oh, it was nothing."); - stage++; - break; - case 507: - interpreter.sendDialogues(5002, null, "I could have sworn I heard something!"); - stage++; - break; - case 508: - interpreter.sendDialogues(823, null, "Yes you did you ignoramus."); - stage++; - break; - case 509: - interpreter.sendDialogues(5002, null, "What was that you said?"); - stage++; - break; - case 510: - player("I said you were very gregarious!"); - stage++; - break; - case 511: - interpreter.sendDialogues(823, null, "You creep!"); - stage++; - break; - case 512: - interpreter.sendDialogues(5002, null, "Oh, right, how very nice of you to say so.", "-- The guard seems flattered. --"); - stage++; - break; - case 513: - interpreter.sendDialogues(5002, null, "Anyway, let's get this barrel up to the surface, plenty", "more work for you to do!"); - stage++; - break; - case 514: - interpreter.sendDialogue("The guard places the barrel carefully on the lift platform."); - stage++; - break; - case 515: - interpreter.sendDialogues(5002, null, "Oh, there's no one operating the lift up top, hope this", "barrel isn't urgent? You'd better get back to work!"); - stage = 516; - break; - case 516: - player.getInventory().remove(TouristTrap.ANNA_BARREL); - player.getBank().remove(TouristTrap.ANNA_BARREL); - player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 71); - end(); - break; - case 0: - options("What is this thing?", "Can I use this?"); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - player("What is this thing?"); - stage = 10; - break; - case 2: - player("Can I use this?"); - stage = 20; - break; - } - break; - case 10: - interpreter.sendDialogues(4999, null, "It is quite clearly a lift. Any fool can see that it's used to", "transport rock to the surface."); - stage++; - break; - case 11: - case 21: - end(); - break; - case 20: - interpreter.sendDialogues(4999, null, "Of course not, you'd be doing me out of a job. Anyway", "you haven't got any barrels that need to go to", "the surface."); - stage++; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("winch dialogue")}; - } - - } - - /** - * The use with handler for anna on the cart. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class AnnaCartHandler extends UseWithHandler { - - /** - * Constructs a new {@code AnnaCartHandler} {@code Object}. - */ - public AnnaCartHandler() { - super(TouristTrap.ANNA_BARREL.getId()); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(2684, OBJECT_TYPE, this); - addHandler(18958, OBJECT_TYPE, this); - return this; - } - - @Override - public boolean handle(final NodeUsageEvent event) { - final Player player = event.getPlayer(); - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if (event.getUsedWith().getId() == 18958) {// cart - if (quest.getStage(player) == 72) { - player.lock(4); - player.animate(Animation.create(5050)); - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.getInventory().remove(event.getUsedItem()); - TouristTrap.addConfig(player, 4096 + (2048 + (1 << 4))); - quest.setStage(player, 80); - player.getDialogueInterpreter().sendDialogue("You place Ana (In the barrel) carefully on the cart. This was the last", "barrel to go on the cart, but the cart driver doesn't seem to be", "any rush to get going. And the desert heat will soon get to Ana."); - return true; - } - }); - } - return true; - } - if (!event.getUsedWith().getLocation().equals(Location.create(3318, 9430, 0))) { - return false; - } - if (quest.getStage(player) != 61) { - return false; - } - player.getDialogueInterpreter().sendDialogue("You carefully place Ana in the barrel into the mine", "cart. Soon the cart moves out of sight and then it", "returns."); - player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); - ActivityManager.start(player, "ana cart", false); - return true; - } - - /** - * The ana cart cutscene plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class AnnaCartCutscene extends CutscenePlugin { - - /** - * The paths. - */ - private static final Location[][] PATHS = new Location[][]{{Location.create(3315, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9428, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3316, 9417, 0), Location.create(3314, 9417, 0), Location.create(3303, 9417, 0)}}; - - /** - * Constructs a new {@code AnnaCartCutscene} {@code Object}. - */ - public AnnaCartCutscene() { - super("ana cart"); - } - - /** - * Constructs a new {@code AnnaCartCutscene} {@code Object}. - * - * @param player the player. - */ - public AnnaCartCutscene(final Player player) { - super("ana cart"); - this.player = player; - } - - @Override - public void open() { - super.open(); - player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); - player.faceLocation(base.transform(54, 22, 0)); - GameWorld.getPulser().submit(new Pulse(1, player) { - int counter; - NPC cart; - - @Override - public boolean pulse() { - switch (++counter) { - case 1: - player.animate(Animation.create(5052)); - break; - case 3: - SceneryBuilder.remove(RegionManager.getObject(base.transform(54, 22, 0))); - cart = NPC.create(4980, base.transform(54, 22, 0)); - cart.init(); - break; - case 4: - cart.getWalkingQueue().reset(); - for (Location l : PATHS[1]) { - Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); - cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); - } - break; - case 18: - cart.clear(); - break; - case 22: - cart = NPC.create(4981, base.transform(51, 9, 0)); - cart.init(); - cart.getWalkingQueue().reset(); - for (Location l : PATHS[0]) { - Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); - cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); - } - break; - case 33: - player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 70); - player.getInventory().remove(TouristTrap.ANNA_BARREL); - player.removeAttribute("ana-delay"); - AnnaCartCutscene.this.stop(true); - return true; - } - return false; - } - }); - } - - @Override - public ActivityPlugin newInstance(Player p) { - return new AnnaCartCutscene(p); - } - - @Override - public Location getSpawnLocation() { - return null; - } - - @Override - public Location getStartLocation() { - return base.transform(54, 23, 0); - } - - @Override - public void configure() { - region = DynamicRegion.create(13203); - setRegionBase(); - registerRegion(region.getId()); - } - } - } - - /** - * The cart dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class CartDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code CartDialogue} {@code Object}. - * - * @param player the player. - */ - public CartDialogue(final Player player) { - super(player); - } - - /** - * Constructs a new {@code CartDialogue} {@code Object}. - */ - public CartDialogue() { - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new CartDialogue(player); - } - - @Override - public boolean open(Object... args) { - interpreter.sendDialogue("There is space on the cart for you get on, would you like to try?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - options("Yes, I'll get on.", "No, I've got other plans."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - interpreter.sendDialogue("You decide to climb onto the cart."); - stage++; - break; - case 2: - end(); - break; - } - break; - case 2: - player.lock(); - player.animate(ClimbActionHandler.CLIMB_UP); - GameWorld.getPulser().submit(new Pulse(1, player) { - int counter; - - @Override - public boolean pulse() { - switch (counter++) { - case 1: - player.getInterfaceManager().openOverlay(new Component(115)); - break; - case 4: - player.getDialogueInterpreter().sendDialogue("As soon as you get on the cart, it starts to move.", "Before too long you are past the gates. You jump off", "the cart taking Ana with you."); - break; - case 6: - player.unlock(); - player.getInterfaceManager().closeOverlay(); - player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 95); - player.getInterfaceManager().close(); - player.getProperties().setTeleportLocation(Location.create(3258, 3029, 0)); - player.getInventory().add(TouristTrap.ANNA_BARREL); - return true; - } - return false; - } - }); - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("ana cart dialogue")}; - } - - } - - /** - * The minecart dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class MineCartDialogue extends DialoguePlugin { - - /** - * The failing animation of getting in the cart. - */ - private static final Animation FAIL_ANIMATION = new Animation(5048); - - /** - * The jumping animation. - */ - private static final Animation JUMP_ANIMATION = new Animation(5049); - - /** - * The cart. - */ - private Scenery cart; - - /** - * Constructs a new {@code MineCartDialogue} {@code Object}. - */ - public MineCartDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code MineCartDialogue} {@code Object}. - * - * @param player the player. - */ - public MineCartDialogue(final Player player) { - super(player); - } - - @Override - public void init() { - super.init(); - ClassScanner.definePlugin(new MiningCartCutscene()); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new MineCartDialogue(player); - } - - @Override - public boolean open(Object... args) { - cart = (Scenery) args[0]; - if (player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { - player("There's not enough room for both of us."); - stage = -1; - return true; - } - interpreter.sendDialogue("You search the mine cart..."); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case -1: - end(); - break; - case 0: - interpreter.sendDialogue("There may be just enough space to squeeze yourself into the cart.", "Would you like to try?"); - stage++; - break; - case 1: - options("Yes, of course.", "No thanks, it looks pretty dangerous."); - stage++; - break; - case 2: - switch (buttonId) { - case 1: - end(); - enterCart(player); - break; - case 2: - end(); - break; - } - break; - } - return true; - } - - /** - * Method used to enter the cart. - * - * @param player the player. - */ - public void enterCart(final Player player) { - if (RandomFunction.random(3) == 1) { - player.lock(FAIL_ANIMATION.getDelay()); - player.animate(FAIL_ANIMATION); - player.getImpactHandler().manualHit(player, 2, HitsplatType.NORMAL); - player.getPacketDispatch().sendMessages("You fail to fit yourself into the cart in time before it starts its journey.", "You bang your head on the cart as you try to jump in."); - } else { - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.animate(JUMP_ANIMATION); - return true; - } - }); - ActivityManager.start(player, "mining cart", false, cart.getLocation().getX() == 3303 ? 0 : 1); - } - } - - /** - * The mining cart cutscene plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class MiningCartCutscene extends CutscenePlugin { - - /** - * The paths. - */ - private static final Location[][] PATHS = new Location[][]{{Location.create(3303, 9417, 0), Location.create(3316, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9430, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3303, 9417, 0)}}; - - /** - * The path index. - */ - private int index; - - /** - * Constructs a new {@code MiningCartCutscene} {@code Object}. - */ - public MiningCartCutscene() { - super("mining cart"); - } - - /** - * Constructs a new {@code MiningCartCutscene} {@code Object}. - * - * @param player the player. - */ - public MiningCartCutscene(final Player player) { - super("mining cart"); - this.player = player; - } - - @Override - public boolean start(final Player player, boolean login, Object... args) { - index = (int) args[0]; - return super.start(player, login, args); - } - - @Override - public void open() { - SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0))); - SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[getPath().length - 1].getLocalX(), getPath()[getPath().length - 1].getLocalY(), 0))); - player.getAppearance().setAnimations(Animation.create(211)); - player.getAppearance().setRidingMinecart(true); - player.getAppearance().sync(); - player.getWalkingQueue().reset(); - for (Location l : getPath()) { - Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); - player.getWalkingQueue().addPath(loc.getX(), loc.getY(), true); - } - GameWorld.getPulser().submit(new Pulse(22, player) { - @Override - public boolean pulse() { - player.setAttribute("real-end", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); - player.setAttribute("cutscene:original-loc", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); - MiningCartCutscene.this.stop(true); - return true; - } - }); - } - - @Override - public void end() { - super.end(); - player.getAppearance().setDefaultAnimations(); - player.getAppearance().setRidingMinecart(false); - player.getAppearance().sync(); - } - - @Override - public void fade() { - if (index == 0) { - player.getDialogueInterpreter().sendDialogue("You appear in a large open room with what looks like lots of miners", "working away. This is a very rough looking area, the miners look like", "they're on their last legs."); - } else { - player.getDialogueInterpreter().sendDialogue("You appear back in the barrel loading room. A nearby slave looks", "surprised to see you popping out of the cart."); - } - } - - @Override - public ActivityPlugin newInstance(Player p) { - return new MiningCartCutscene(p); - } - - @Override - public Location getSpawnLocation() { - return null; - } - - @Override - public Location getStartLocation() { - return base.transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0); - } - - @Override - public void configure() { - region = DynamicRegion.create(13203); - setRegionBase(); - registerRegion(region.getId()); - } - - /** - * Gets the path index. - * - * @return the location. - */ - public Location[] getPath() { - return PATHS[index]; - } - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("cart dialogue")}; - } - - } - - /** - * The winch cutscene plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class WinchCutscene extends CutscenePlugin { - - /** - * Constructs a new {@code WinchCutscene} {@code Object}. - */ - public WinchCutscene() { - super("winch cutscene"); - } - - /** - * Constructs a new {@code WinchCutscene} {@code Object}. - * - * @param player the player. - */ - public WinchCutscene(final Player player) { - super("winch cutscene"); - this.player = player; - } - - @Override - public ActivityPlugin newInstance(Player p) { - return new WinchCutscene(p); - } - - @Override - public void open() { - super.open(); - player.getPacketDispatch().sendMessage("You try to operate the winch."); - player.faceLocation(base.transform(15, 9, 0)); - player.animate(Animation.create(5054)); - GameWorld.getPulser().submit(new Pulse(AnimationDefinition.forId(5054).getDurationTicks(), player) { - @Override - public boolean pulse() { - TouristTrap.addConfig(player, 2048 + (1 << 4)); - WinchCutscene.this.stop(true); - player.getDialogueInterpreter().open(822, true, true); - return true; - } - }); - } - - @Override - public Location getSpawnLocation() { - return null; - } - - @Override - public Location getStartLocation() { - return base.transform(16, 10, 0); - } - - @Override - public void configure() { - region = DynamicRegion.create(13103); - setRegionBase(); - registerRegion(region.getId()); - } - - } - - /** - * The use with handler on the chest. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BedabinKeyHandler extends UseWithHandler { - - /** - * Constructs a new {@code BedabinKeyHandler} {@code Object}. - */ - public BedabinKeyHandler() { - super(TouristTrap.BEDABIN_KEY.getId()); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(2677, OBJECT_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - player.getDialogueInterpreter().open(831, RegionManager.getNpc(player, 831)); - return true; - } - - } - - /** - * The barrel dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BarrelDialogue extends DialoguePlugin { - - /** - * The scenery barrel. - */ - private Scenery barrel; - - /** - * The quest. - */ - private Quest quest; - - /** - * Constructs a new {@code BarrelDialogue} {@code Object}. - */ - public BarrelDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code BarrelDialogue} {@code Object}. - * - * @param player the player. - */ - public BarrelDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new BarrelDialogue(player); - } - - @Override - public boolean open(Object... args) { - barrel = (Scenery) args[0]; - quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if ((quest.getStage(player) == 70 || quest.getStage(player) == 72) && !player.hasItem(TouristTrap.ANNA_BARREL)) { - interpreter.sendDialogue("You search the barrels and find Ana."); - stage = 400; - return true; - } - if (player.getInventory().containsItem(TouristTrap.BARREL)) { - player.getPacketDispatch().sendMessage("You can only manage to have one of these at a time."); - end(); - return true; - } - interpreter.sendItemMessage(TouristTrap.BARREL, "This barrel is quite big. but you may be able to carry one. Would you like to take one?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 400:// finding anna. - interpreter.sendDialogues(823, null, "Let me out!"); - stage++; - break; - case 401: - if (!player.getInventory().hasSpaceFor(TouristTrap.ANNA_BARREL)) { - end(); - return true; - } - player.getPacketDispatch().sendMessage("You pick up Ana in a Barrel."); - player.getInventory().add(TouristTrap.ANNA_BARREL); - end(); - break; - case 402: - end(); - break; - case 0: - options("Yeah, cool!", "No thanks."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - interpreter.sendItemMessage(TouristTrap.BARREL, "You take the barrel, it's not heavy, just awkward."); - stage = 3; - break; - case 2: - end(); - break; - } - break; - case 3: - end(); - player.getInventory().add(TouristTrap.BARREL, player); - SceneryBuilder.remove(barrel); - GameWorld.getPulser().submit(new Pulse(40) { - @Override - public boolean pulse() { - SceneryBuilder.add(barrel); - return true; - } - }); - break; - - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("barrel dialogue")}; - } - - } - - /** - * The use with handler for the bedabin anvil. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BedabinAnvilHandler extends UseWithHandler { - - /** - * Constructs a new {@code BedabinAnvilHandler} {@code Object}. - */ - public BedabinAnvilHandler() { - super(2349); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(2672, OBJECT_TYPE, this); - ClassScanner.definePlugin(new PrototypeDartHandler()); - ClassScanner.definePlugin(new BedabinAnvilDialogue()); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if (quest.getStage(player) == 54 && player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { - player.getDialogueInterpreter().open("bedabin-anvil"); - return true; - } else { - player.getPacketDispatch().sendMessage("You need technical plans in order to do this."); - } - return true; - } - - /** - * The handler used to handle the anna barrel on the winch. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class AnnaWinchHandler extends UseWithHandler { - - /** - * Constructs a new {@code AnnaWinchHandler} {@code Object}. - */ - public AnnaWinchHandler() { - super(TouristTrap.ANNA_BARREL.getId()); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(18951, OBJECT_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if (!event.getUsedWith().getLocation().equals(Location.create(3292, 9423, 0))) { - return false; - } - if (quest.getStage(player) == 70) { - player.getDialogueInterpreter().open("winch dialogue", true); - return true; - } - return false; - } - - } - - /** - * The prototype dart creation handler. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class PrototypeDartHandler extends UseWithHandler { - - /** - * Constructs a new {@code PrototypeDartHandler} {@code Object}. - */ - public PrototypeDartHandler() { - super(314); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(TouristTrap.PROTOTYPE_DART_TIP.getId(), ITEM_TYPE, this); - ClassScanner.definePlugin(new ProtoTypeDialogue()); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - player.getDialogueInterpreter().open("prototype dart"); - return true; - } - - /** - * The prototype dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class ProtoTypeDialogue extends DialoguePlugin { - - /** - * The feathers item. - */ - private static final Item FEATHERS = new Item(314, 10); - - /** - * Constructs a new {@code ProtoTypeDialogue} {@code Object}. - * - * @param player the player. - */ - public ProtoTypeDialogue(final Player player) { - super(player); - } - - /** - * Constructs a new {@code ProtoTypeDialogue} {@code Object}. - */ - public ProtoTypeDialogue() { - /** - * empty. - */ - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new ProtoTypeDialogue(player); - } - - @Override - public boolean open(Object... args) { - if (!player.getInventory().containsItem(FEATHERS)) { - interpreter.sendDialogue("You need 10 feathers in order to do this."); - stage = 10; - return false; - } - interpreter.sendItemMessage(314, "You try to attach feathers to the bronze dart tip."); - stage = 1; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 1: - interpreter.sendDialogue("Following the plans is tricky, but you persevere."); - stage++; - break; - case 2: - interpreter.sendItemMessage(TouristTrap.PROTOTYPE_DART, "You successfully attach the feathers to the dart tip."); - stage++; - break; - case 3: - player.getInventory().remove(FEATHERS, TouristTrap.PROTOTYPE_DART_TIP); - player.getInventory().add(TouristTrap.PROTOTYPE_DART); - end(); - break; - case 4: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("prototype dart")}; - } - - } - } - - /** - * The bedabin dialogue plugin handler. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BedabinAnvilDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. - */ - public BedabinAnvilDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. - * - * @param player the player. - */ - public BedabinAnvilDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new BedabinAnvilDialogue(player); - } - - @Override - public boolean open(Object... args) { - if (!player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { - player.getPacketDispatch().sendMessage("You need the plans to do this."); - return false; - } - player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "Do you want to follow the technical plans ?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - options("Yes. I'd like to try.", "No, not just yet."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - end(); - player.getPulseManager().run(new ProtoTypePulse(player)); - break; - case 2: - end(); - break; - } - break; - } - return true; - } - - /** - * The skill pulse used to make a prototype dart. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class ProtoTypePulse extends SkillPulse { - - /** - * The hammer item. - */ - private static final Item HAMMER = new Item(2347); - - /** - * The ticks passed. - */ - private int ticks; - - /** - * Constructs a new {@code ProtoTypePulse} {@code Object}. - * - * @param player the player. - */ - public ProtoTypePulse(Player player) { - super(player, null); - } - - @Override - public boolean checkRequirements() { - if (!player.getInventory().hasSpaceFor(TouristTrap.PROTOTYPE_DART_TIP)) { - player.getPacketDispatch().sendMessage("Not enough inventory space."); - return false; - } - if (!player.getInventory().containsItem(HAMMER)) { - player.getPacketDispatch().sendMessage("You need a hammer in order to work metal with."); - return false; - } - return player.getInventory().containsItem(Bar.BRONZE.getProduct()); - } - - @Override - public void animate() { - if (ticks % 4 == 0) { - player.animate(Animation.create(898)); - } - } - - @Override - public boolean reward() { - if (++ticks % 4 != 0) { - return false; - } - if (ticks == 4) { - player.getDialogueInterpreter().sendPlainMessage(true, "You begin experimenting in forging the weapon..."); - } else if (ticks == 8) { - player.getInventory().remove(Bar.BRONZE.getProduct()); - player.getInventory().add(TouristTrap.PROTOTYPE_DART_TIP); - player.getDialogueInterpreter().sendItemMessage(TouristTrap.PROTOTYPE_DART_TIP, "You follow the plans carefully, and after some careful", "work, you finally manage to forge a sharp, pointed...", "dart tip."); - return true; - } - return false; - } - - @Override - public void stop() { - super.stop(); - } - - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("bedabin-anvil")}; - } - - } - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + SceneryDefinition.forId(2673).getHandlers().put("option:open", this); + SceneryDefinition.forId(2674).getHandlers().put("option:open", this); + SceneryDefinition.forId(2673).getHandlers().put("option:search", this); + SceneryDefinition.forId(2674).getHandlers().put("option:search", this); + SceneryDefinition.forId(2688).getHandlers().put("option:open", this); + SceneryDefinition.forId(2688).getHandlers().put("option:search", this); + SceneryDefinition.forId(2687).getHandlers().put("option:open", this); + SceneryDefinition.forId(2687).getHandlers().put("option:search", this); + SceneryDefinition.forId(2685).getHandlers().put("option:open", this); + SceneryDefinition.forId(2685).getHandlers().put("option:open", this); + SceneryDefinition.forId(2686).getHandlers().put("option:search", this); + SceneryDefinition.forId(2686).getHandlers().put("option:search", this); + SceneryDefinition.forId(18958).getHandlers().put("option:search", this); + SceneryDefinition.forId(18958).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18959).getHandlers().put("option:search", this); + SceneryDefinition.forId(18959).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18888).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18888).getHandlers().put("option:operate", this); + SceneryDefinition.forId(36748).getHandlers().put("option:talk-to", this); + SceneryDefinition.forId(18869).getHandlers().put("option:bend", this); + SceneryDefinition.forId(18870).getHandlers().put("option:escape", this); + SceneryDefinition.forId(2689).getHandlers().put("option:open", this); + SceneryDefinition.forId(1528).getHandlers().put("option:open", this); + SceneryDefinition.forId(1529).getHandlers().put("option:close", this); + SceneryDefinition.forId(18899).getHandlers().put("option:search", this); + SceneryDefinition.forId(18899).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18878).getHandlers().put("option:search", this); + SceneryDefinition.forId(18878).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18879).getHandlers().put("option:search", this); + SceneryDefinition.forId(18879).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18898).getHandlers().put("option:search", this); + SceneryDefinition.forId(18898).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18902).getHandlers().put("option:search", this); + SceneryDefinition.forId(18871).getHandlers().put("option:climb", this); + SceneryDefinition.forId(18923).getHandlers().put("option:climb-up", this); + SceneryDefinition.forId(18924).getHandlers().put("option:climb-down", this); + SceneryDefinition.forId(2676).getHandlers().put("option:open", this); + SceneryDefinition.forId(2675).getHandlers().put("option:open", this); + SceneryDefinition.forId(2676).getHandlers().put("option:watch", this); + SceneryDefinition.forId(2675).getHandlers().put("option:watch", this); + SceneryDefinition.forId(2690).getHandlers().put("option:open", this); + SceneryDefinition.forId(2691).getHandlers().put("option:open", this); + SceneryDefinition.forId(2698).getHandlers().put("option:walk through", this); + SceneryDefinition.forId(2699).getHandlers().put("option:walk through", this); + SceneryDefinition.forId(2677).getHandlers().put("option:open", this); + SceneryDefinition.forId(2678).getHandlers().put("option:search", this); + SceneryDefinition.forId(2684).getHandlers().put("option:search", this); + SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); + SceneryDefinition.forId(2680).getHandlers().put("option:search", this); + SceneryDefinition.forId(2680).getHandlers().put("option:look-in", this); + SceneryDefinition.forId(2681).getHandlers().put("option:search", this); + SceneryDefinition.forId(2681).getHandlers().put("option:look in", this); + SceneryDefinition.forId(18962).getHandlers().put("option:search", this); + SceneryDefinition.forId(18962).getHandlers().put("option:look in", this); + SceneryDefinition.forId(18963).getHandlers().put("option:search", this); + SceneryDefinition.forId(18963).getHandlers().put("option:look in", this); + SceneryDefinition.forId(18951).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18951).getHandlers().put("option:use", this); + SceneryDefinition.forId(2684).getHandlers().put("option:search", this); + SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18875).getHandlers().put("option:inspect", this); + NPCDefinition.forId(830).getHandlers().put("option:watch", this); + NPCDefinition.forId(4975).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(4976).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(4977).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(4978).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(5002).getHandlers().put("option:talk-to", this); + TouristTrap.TECHNICAL_PLANS.getDefinition().getHandlers().put("option:read", this); + TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:look", this); + TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:drop", this); + ClassScanner.definePlugin(new BedabinKeyHandler()); + ClassScanner.definePlugin(new BedabinAnvilHandler()); + ClassScanner.definePlugin(new BarrelDialogue()); + ClassScanner.definePlugin(new WinchDialogue()); + ClassScanner.definePlugin(new MineCartDialogue()); + ClassScanner.definePlugin(new AnnaCartHandler()); + ClassScanner.definePlugin(new AnnaCartCutscene()); + ClassScanner.definePlugin(new AnnaWinchHandler()); + ClassScanner.definePlugin(new WinchCutscene()); + ClassScanner.definePlugin(new CartDialogue()); + return this; + } + + @Override + public boolean handle(final Player player, Node node, String option) { + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + final int id = node.getId(); + switch (option) { + case "read": + player.getDialogueInterpreter().sendDialogue("The plans look very technical! But you can see that this item will", "require a bronze bar and at least 10 feathers."); + break; + case "watch": + switch (id) { + case 2676: + case 2675: + player.getDialogueInterpreter().sendDialogue("You watch the doors for some time. You notice that only slaves seem", "to do down there. You might be able to sneak down if you pass as a", "slave."); + break; + default: + player.getDialogueInterpreter().sendDialogue("You watch the Mercenary Captain for some time. He has a large", "metal key attached to his belt. You notice that he usually gets his", "men to do his dirty work."); + break; + } + break; + case "walk through": + switch (id) { + case 2698: + case 2699: + if (quest.getStage(player) < 60) { + player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you! You're not allowed in there."); + break; + } + if (!TouristTrap.hasSlaveClothes(player)) { + player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you're not a slave!"); + break; + } + player.getProperties().setTeleportLocation(player.getLocation().transform(player.getLocation().getX() >= 3284 ? -4 : 4, 0, 0)); + player.getPacketDispatch().sendMessages("You walk into the darkness of the cavern...", "... and emerge in a different part of this huge underground complex."); + break; + } + break; + case "look": + player.getDialogueInterpreter().sendDialogues(823, null, "Let me out of here, I feel sick!"); + break; + case "drop": + player.getDialogueInterpreter().sendDialogues(823, null, "Don't let me out!"); + break; + case "open": + switch (id) { + case 2688: + case 2687: + if (!player.getInventory().containsItem(TouristTrap.WROUGHT_IRON_KEY)) { + player.getPacketDispatch().sendMessage("This gate looks like it needs a key to open it."); + break; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + break; + case 2686: + case 2685: + player.getDialogueInterpreter().sendDialogues(4999, null, "Hey, move away from the gate. There's nothing", "interesting for you here."); + break; + case 2677: + if (!player.getInventory().containsItem(TouristTrap.BEDABIN_KEY)) { + player.getPacketDispatch().sendMessage("This chest needs a key to unlock it."); + break; + } + if (quest.getStage(player) <= 54 && quest.getStage(player) != 53) { + player.getPacketDispatch().sendMessage("The captain spots you before you manage to open the chest..."); + player.lock(3); + GameWorld.getPulser().submit(new Pulse(2, player) { + @Override + public boolean pulse() { + player.getDialogueInterpreter().open(831, RegionManager.getNpc(player.getLocation(), 831, 16)); + return true; + } + }); + } else if (quest.getStage(player) == 53) { + if (!player.hasItem(TouristTrap.TECHNICAL_PLANS)) { + player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "While the Captain's distracted, you quickly unlock the", "chest with the Bedabins' copy of the key. You take out", "the plans."); + player.getInventory().add(TouristTrap.TECHNICAL_PLANS, player); + } + } + break; + case 2690: + case 2691: + player.setAttribute("ana-delay", GameWorld.getTicks() + 2); + player.getProperties().setTeleportLocation(Location.create(3301, 3035, 0)); + break; + case 2676: + case 2675: + if (!TouristTrap.hasSlaveClothes(player)) { + player.getDialogueInterpreter().sendDialogues(4997, null, "Watch it! Only slaves can travel into the mine."); + break; + } + player.setAttribute("ana-delay", GameWorld.getTicks() + 2); + player.getProperties().setTeleportLocation(Location.create(3278, 9427, 0)); + player.getDialogueInterpreter().sendDialogue("The huge doors open into a dark, dank and smelly tunnel. The", "associated smells of a hundred sweaty miners greets your nostrils.", "And your ears ring with the 'CLANG CLANG CLANG' as metal hits", "rock."); + break; + case 2674: + case 2673: + if (quest.getStage(player) > 60 && quest.getStage(player) < 98 && player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { + player.lock(); + player.getDialogueInterpreter().sendDialogues(4999, null, true, "Would you like me to take that heavy barrel", "for you?"); + GameWorld.getPulser().submit(new Pulse(4, player) { + int counter; + + @Override + public boolean pulse() { + switch (++counter) { + case 1: + player.getDialogueInterpreter().sendDialogues(player, null, "No, please don't."); + break; + case 2: + player.getDialogueInterpreter().close(); + player.getPacketDispatch().sendMessage("The guards search you!"); + break; + case 3: + player.getPacketDispatch().sendMessage("You are roughed up by the guards and manhandled into a cell."); + break; + case 4: + player.unlock(); + player.getInventory().remove(TouristTrap.ANNA_BARREL); + TouristTrap.addConfig(player, (1 << 4)); + quest.setStage(player, 61); + player.getProperties().setTeleportLocation(Location.create(3285, 3034, 0)); + return true; + } + return false; + } + }); + return true; + } + if (node.getLocation().withinDistance(new Location(3273, 3028, 0)) && !((player.getLocation().getX() >= 3274))) { + if (!player.getInventory().containsItem(TouristTrap.METAL_KEY)) { + player.getPacketDispatch().sendMessage("The gate needs a key in order to be opened."); + return true; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + player.getPacketDispatch().sendMessage("The guards search you thoroughly as you go through the gates."); + return true; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + break; + case 2689: + if (!player.getInventory().containsItem(TouristTrap.CELL_DOOR_KEY)) { + player.getPacketDispatch().sendMessage("The door seems to be pretty locked."); + break; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + break; + case 1528: + SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1529)); + break; + } + break; + case "close": + if (id == 1529) { + SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1528)); + } + break; + case "look-in": + case "look in": + switch (id) { + case 2681: + case 18962: + case 18963: + player.getDialogueInterpreter().sendDialogue("This looks like an empty mining barrel. Slaves use this to load up the", "rocks and stones that they're mining."); + break; + case 2680: + player.getDialogueInterpreter().sendDialogue("You search the full barrel... It's full of rocks."); + break; + } + break; + case "use": + if (id == 18951) { + player.getDialogueInterpreter().open("winch dialogue"); + } + break; + case "search": + switch (id) { + case 2688: + case 2687: + player.getDialogueInterpreter().sendDialogue("These wrought iron gates look like they're designed to keep people out.", "it looks like you'll need a key to get past these."); + break; + case 2686: + case 2685: + player.getDialogueInterpreter().sendDialogue("It looks as if this is where very difficult prisoners are sent as a", "punishment."); + break; + case 2681: + case 18962: + case 18963: + player.getDialogueInterpreter().open("barrel dialogue", node); + break; + case 2680:// barrel of rocks. + player.getDialogueInterpreter().sendDialogue("This looks like a full mining barrel. Slaves use this to load up the", "rocks and stones that they're mining. This barrel is full of rocks."); + break; + case 2684:// cart + player.getDialogueInterpreter().open("cart dialogue", node); + break; + case 2678: + if (quest.getStage(player) == 51) { + quest.setStage(player, 52); + } + player.getDialogueInterpreter().sendItemMessage(9904, "You notice several books on the subject of sailing."); + break; + case 2673: + case 2674: + player.getDialogueInterpreter().sendDialogue("You see what looks like a mining compound. There seems to be people", "mining rocks. They look as if they're chained to the rocks and they're", "being watched over by the guards. It's not a very happy place."); + break; + case 18958: + case 18959: + if (quest.getStage(player) == 90) { + player.getDialogueInterpreter().open("ana cart dialogue"); + break; + } + player.getPacketDispatch().sendMessage("This looks like a mine cart which takes barrels out of the encampment to Al Kharid."); + break; + case 18899: + case 18898: + case 18878: + case 18879: + player.getDialogueInterpreter().sendDialogue("You search the footsteps more closely. You can see that there are", "five sets of footprints. One set of footprints seem lighter than the", "others. The four other footsteps were made by heavier people", "with boots."); + break; + case 18902: + if (hasItem(player, TouristTrap.CELL_DOOR_KEY)) { + player.getInventory().add(TouristTrap.CELL_DOOR_KEY, player); + player.getDialogueInterpreter().sendItemMessage(TouristTrap.CELL_DOOR_KEY, "You find a cell door key."); + break; + } else if (hasItem(player, TouristTrap.WROUGHT_IRON_KEY) && player.getQuestRepository().isComplete(Quests.THE_TOURIST_TRAP)) { + player.getInventory().add(TouristTrap.WROUGHT_IRON_KEY, player); + player.getDialogueInterpreter().sendItemMessage(TouristTrap.WROUGHT_IRON_KEY, "You find the key to the main gate."); + break; + } + player.getPacketDispatch().sendMessage("You search the captains desk while he's not looking..."); + player.getPacketDispatch().sendMessage("...but you find nothing of interest."); + break; + } + break; + case "operate": + if (quest.getStage(player) != 71) { + player.getDialogueInterpreter().sendDialogue("There doesn't seem anything to lift."); + break; + } + ActivityManager.start(player, "winch cutscene", false); + break; + case "look at": + switch (id) { + case 18888: + player.getDialogueInterpreter().sendDialogue("This looks like a winch, it probably brings rocks up from", "underground."); + break; + case 18951: + player.getDialogueInterpreter().sendDialogue("This looks like a lift of some sort. You see barrels of rocks being", "placed on the lift and they're hauled up to the surface."); + break; + case 2684: + if (node.getLocation().getX() == 3318) { + player.getDialogueInterpreter().sendDialogue("This mine cart is being loaded up with new rocks and stone.", "It gets sent to a different section of the mine for unloading."); + break; + } + player.getDialogueInterpreter().sendDialogue("This cart is being unloaded into this section of the mine. Before being", "sent back to another section for another load."); + break; + case 18958: + case 18959: + player.getDialogueInterpreter().sendDialogue("A sturdy looking cart for carrying barrels of rocks out of ", "the mining camp."); + break; + case 18900: + case 18899: + case 18898: + case 18887: + case 18886: + case 18885: + case 18884: + case 18883: + case 18882: + case 18881: + case 18880: + case 18879: + case 18878: + case 18877: + player.getDialogueInterpreter().sendDialogue("This looks like some disturbed sand. Footsteps seem to be heading off", "towards the South."); + break; + } + break; + case "talk-to": + switch (id) { + case 5002: + ((NPC) node).sendChat("Move along please, don't want any trouble today!"); + break; + case 36748: + player.getDialogueInterpreter().sendDialogues(player, null, "Mmm... looks like that camel would make a nice kebab."); + break; + case 4975: + case 4977: + case 4978: + case 4976: + ((NPC) node).sendChat("Hey leave me alone, can't you see that i'm busy?"); + break; + } + break; + case "bend": + player.animate(Animation.create(5037)); + GameWorld.getPulser().submit(new Pulse(5, player) { + @Override + public boolean pulse() { + player.getPacketDispatch().sendMessage("You bend the bars back."); + setVarp(player, 907, getVarp(player, 907) + 1); + return true; + } + }); + break; + case "escape": + player.getPacketDispatch().sendMessage("You prepare to squeeze through the bars."); + AgilityHandler.forceWalk(player, 0, player.getLocation(), player.getLocation().transform(player.getLocation().getX() <= node.getLocation().getX() ? 1 : -1, 0, 0), Animation.create(5038), 4, 0.0, null); + break; + case "climb": + player.getPacketDispatch().sendMessage("You scrape your hands and knees as you climb up."); + AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3279, 3037, 0), Animation.create(5041), 10, 0, null); + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.getAnimator().reset(); + return true; + } + }); + break; + case "climb-up": + if (id == 18923) { + if (player.getLocation().getX() <= 3278) { + return true; + } + player.animate(Animation.create(5039)); + GameWorld.getPulser().submit(new Pulse(6, player) { + @Override + public boolean pulse() { + player.getAnimator().reset(); + player.getProperties().setTeleportLocation(Location.create(3278, 3037, 0)); + return true; + } + }); + } + break; + case "climb-down": + if (id == 18924) { + if (player.getLocation().getX() <= 3273) { + return true; + } + AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3270, 3039, 0), Animation.create(5040), 20, 0, null); + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.getAnimator().reset(); + return true; + } + }); + } + break; + case "inspect": + if (id == 18875) { + sendDialogue(player, "You remember that Irena mentioned something about Ana wearing a red scarf before she left for the desert."); + } + break; + } + return true; + } + + @Override + public boolean isWalk(final Player player, Node node) { + return !(node instanceof Item); + } + + @Override + public boolean isWalk() { + return false; + } + + @Override + public Location getDestination(Node node, Node n) { + if (n.getId() == 18923) { + return new Location(3279, 3037, 0); + } + return null; + } + + /** + * Checks if the player contains an item. + * + * @param player the player. + * @param item the item. + * @return the item. + */ + private boolean hasItem(final Player player, final Item item) { + return !player.getInventory().containsItem(item) && !player.getBank().containsItem(item); + } + + /** + * The winch dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class WinchDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code WinchDialogue} {@code Object}. + */ + public WinchDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code WinchDialogue} {@code Object}. + * + * @param player the player. + */ + public WinchDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new WinchDialogue(player); + } + + @Override + public boolean open(Object... args) { + if (args.length >= 1) { + interpreter.sendDialogue("The guard notices the barrel (with Ana in it) that you're carrying."); + stage = 500; + return true; + } + interpreter.sendDialogues(4999, null, "Hey there, what do you want?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 500:// winch + interpreter.sendDialogues(5002, null, "Hey, that Barrel looks heavy, do you need a hand?"); + stage++; + break; + case 501: + player("Yes please."); + stage++; + break; + case 502: + interpreter.sendDialogue("The guard comes over and helps you. He takes one end of the", "barrel."); + stage++; + break; + case 503: + interpreter.sendDialogues(5002, null, "Blimey! This is heavy!"); + stage++; + break; + case 504: + interpreter.sendDialogues(823, null, "Why you cheeky....!"); + stage++; + break; + case 505: + interpreter.sendDialogues(5002, null, "- The guard looks around surprised at Ana's outburst. -", "What was that?"); + stage++; + break; + case 506: + player("Oh, it was nothing."); + stage++; + break; + case 507: + interpreter.sendDialogues(5002, null, "I could have sworn I heard something!"); + stage++; + break; + case 508: + interpreter.sendDialogues(823, null, "Yes you did you ignoramus."); + stage++; + break; + case 509: + interpreter.sendDialogues(5002, null, "What was that you said?"); + stage++; + break; + case 510: + player("I said you were very gregarious!"); + stage++; + break; + case 511: + interpreter.sendDialogues(823, null, "You creep!"); + stage++; + break; + case 512: + interpreter.sendDialogues(5002, null, "Oh, right, how very nice of you to say so.", "-- The guard seems flattered. --"); + stage++; + break; + case 513: + interpreter.sendDialogues(5002, null, "Anyway, let's get this barrel up to the surface, plenty", "more work for you to do!"); + stage++; + break; + case 514: + interpreter.sendDialogue("The guard places the barrel carefully on the lift platform."); + stage++; + break; + case 515: + interpreter.sendDialogues(5002, null, "Oh, there's no one operating the lift up top, hope this", "barrel isn't urgent? You'd better get back to work!"); + stage = 516; + break; + case 516: + player.getInventory().remove(TouristTrap.ANNA_BARREL); + player.getBank().remove(TouristTrap.ANNA_BARREL); + player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 71); + end(); + break; + case 0: + options("What is this thing?", "Can I use this?"); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + player("What is this thing?"); + stage = 10; + break; + case 2: + player("Can I use this?"); + stage = 20; + break; + } + break; + case 10: + interpreter.sendDialogues(4999, null, "It is quite clearly a lift. Any fool can see that it's used to", "transport rock to the surface."); + stage++; + break; + case 11: + case 21: + end(); + break; + case 20: + interpreter.sendDialogues(4999, null, "Of course not, you'd be doing me out of a job. Anyway", "you haven't got any barrels that need to go to", "the surface."); + stage++; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("winch dialogue")}; + } + + } + + /** + * The use with handler for anna on the cart. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class AnnaCartHandler extends UseWithHandler { + + /** + * Constructs a new {@code AnnaCartHandler} {@code Object}. + */ + public AnnaCartHandler() { + super(TouristTrap.ANNA_BARREL.getId()); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(2684, OBJECT_TYPE, this); + addHandler(18958, OBJECT_TYPE, this); + return this; + } + + @Override + public boolean handle(final NodeUsageEvent event) { + final Player player = event.getPlayer(); + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if (event.getUsedWith().getId() == 18958) {// cart + if (quest.getStage(player) == 72) { + player.lock(4); + player.animate(Animation.create(5050)); + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.getInventory().remove(event.getUsedItem()); + TouristTrap.addConfig(player, 4096 + (2048 + (1 << 4))); + quest.setStage(player, 80); + player.getDialogueInterpreter().sendDialogue("You place Ana (In the barrel) carefully on the cart. This was the last", "barrel to go on the cart, but the cart driver doesn't seem to be", "any rush to get going. And the desert heat will soon get to Ana."); + return true; + } + }); + } + return true; + } + if (!event.getUsedWith().getLocation().equals(Location.create(3318, 9430, 0))) { + return false; + } + if (quest.getStage(player) != 61) { + return false; + } + player.getDialogueInterpreter().sendDialogue("You carefully place Ana in the barrel into the mine", "cart. Soon the cart moves out of sight and then it", "returns."); + player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); + ActivityManager.start(player, "ana cart", false); + return true; + } + + /** + * The ana cart cutscene plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class AnnaCartCutscene extends CutscenePlugin { + + /** + * The paths. + */ + private static final Location[][] PATHS = new Location[][]{{Location.create(3315, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9428, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3316, 9417, 0), Location.create(3314, 9417, 0), Location.create(3303, 9417, 0)}}; + + /** + * Constructs a new {@code AnnaCartCutscene} {@code Object}. + */ + public AnnaCartCutscene() { + super("ana cart"); + } + + /** + * Constructs a new {@code AnnaCartCutscene} {@code Object}. + * + * @param player the player. + */ + public AnnaCartCutscene(final Player player) { + super("ana cart"); + this.player = player; + } + + @Override + public void open() { + super.open(); + player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); + player.faceLocation(base.transform(54, 22, 0)); + GameWorld.getPulser().submit(new Pulse(1, player) { + int counter; + NPC cart; + + @Override + public boolean pulse() { + switch (++counter) { + case 1: + player.animate(Animation.create(5052)); + break; + case 3: + SceneryBuilder.remove(RegionManager.getObject(base.transform(54, 22, 0))); + cart = NPC.create(4980, base.transform(54, 22, 0)); + cart.init(); + break; + case 4: + cart.getWalkingQueue().reset(); + for (Location l : PATHS[1]) { + Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); + cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); + } + break; + case 18: + cart.clear(); + break; + case 22: + cart = NPC.create(4981, base.transform(51, 9, 0)); + cart.init(); + cart.getWalkingQueue().reset(); + for (Location l : PATHS[0]) { + Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); + cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); + } + break; + case 33: + player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 70); + player.getInventory().remove(TouristTrap.ANNA_BARREL); + player.removeAttribute("ana-delay"); + AnnaCartCutscene.this.stop(true); + return true; + } + return false; + } + }); + } + + @Override + public ActivityPlugin newInstance(Player p) { + return new AnnaCartCutscene(p); + } + + @Override + public Location getSpawnLocation() { + return null; + } + + @Override + public Location getStartLocation() { + return base.transform(54, 23, 0); + } + + @Override + public void configure() { + region = DynamicRegion.create(13203); + setRegionBase(); + registerRegion(region.getId()); + } + } + } + + /** + * The cart dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class CartDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code CartDialogue} {@code Object}. + * + * @param player the player. + */ + public CartDialogue(final Player player) { + super(player); + } + + /** + * Constructs a new {@code CartDialogue} {@code Object}. + */ + public CartDialogue() { + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new CartDialogue(player); + } + + @Override + public boolean open(Object... args) { + interpreter.sendDialogue("There is space on the cart for you get on, would you like to try?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + options("Yes, I'll get on.", "No, I've got other plans."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + interpreter.sendDialogue("You decide to climb onto the cart."); + stage++; + break; + case 2: + end(); + break; + } + break; + case 2: + player.lock(); + player.animate(ClimbActionHandler.CLIMB_UP); + GameWorld.getPulser().submit(new Pulse(1, player) { + int counter; + + @Override + public boolean pulse() { + switch (counter++) { + case 1: + player.getInterfaceManager().openOverlay(new Component(115)); + break; + case 4: + player.getDialogueInterpreter().sendDialogue("As soon as you get on the cart, it starts to move.", "Before too long you are past the gates. You jump off", "the cart taking Ana with you."); + break; + case 6: + player.unlock(); + player.getInterfaceManager().closeOverlay(); + player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 95); + player.getInterfaceManager().close(); + player.getProperties().setTeleportLocation(Location.create(3258, 3029, 0)); + player.getInventory().add(TouristTrap.ANNA_BARREL); + return true; + } + return false; + } + }); + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("ana cart dialogue")}; + } + + } + + /** + * The minecart dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class MineCartDialogue extends DialoguePlugin { + + /** + * The failing animation of getting in the cart. + */ + private static final Animation FAIL_ANIMATION = new Animation(5048); + + /** + * The jumping animation. + */ + private static final Animation JUMP_ANIMATION = new Animation(5049); + + /** + * The cart. + */ + private Scenery cart; + + /** + * Constructs a new {@code MineCartDialogue} {@code Object}. + */ + public MineCartDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code MineCartDialogue} {@code Object}. + * + * @param player the player. + */ + public MineCartDialogue(final Player player) { + super(player); + } + + @Override + public void init() { + super.init(); + ClassScanner.definePlugin(new MiningCartCutscene()); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new MineCartDialogue(player); + } + + @Override + public boolean open(Object... args) { + cart = (Scenery) args[0]; + if (player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { + player("There's not enough room for both of us."); + stage = -1; + return true; + } + interpreter.sendDialogue("You search the mine cart..."); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case -1: + end(); + break; + case 0: + interpreter.sendDialogue("There may be just enough space to squeeze yourself into the cart.", "Would you like to try?"); + stage++; + break; + case 1: + options("Yes, of course.", "No thanks, it looks pretty dangerous."); + stage++; + break; + case 2: + switch (buttonId) { + case 1: + end(); + enterCart(player); + break; + case 2: + end(); + break; + } + break; + } + return true; + } + + /** + * Method used to enter the cart. + * + * @param player the player. + */ + public void enterCart(final Player player) { + if (RandomFunction.random(3) == 1) { + player.lock(FAIL_ANIMATION.getDelay()); + player.animate(FAIL_ANIMATION); + player.getImpactHandler().manualHit(player, 2, HitsplatType.NORMAL); + player.getPacketDispatch().sendMessages("You fail to fit yourself into the cart in time before it starts its journey.", "You bang your head on the cart as you try to jump in."); + } else { + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.animate(JUMP_ANIMATION); + return true; + } + }); + ActivityManager.start(player, "mining cart", false, cart.getLocation().getX() == 3303 ? 0 : 1); + } + } + + /** + * The mining cart cutscene plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class MiningCartCutscene extends CutscenePlugin { + + /** + * The paths. + */ + private static final Location[][] PATHS = new Location[][]{{Location.create(3303, 9417, 0), Location.create(3316, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9430, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3303, 9417, 0)}}; + + /** + * The path index. + */ + private int index; + + /** + * Constructs a new {@code MiningCartCutscene} {@code Object}. + */ + public MiningCartCutscene() { + super("mining cart"); + } + + /** + * Constructs a new {@code MiningCartCutscene} {@code Object}. + * + * @param player the player. + */ + public MiningCartCutscene(final Player player) { + super("mining cart"); + this.player = player; + } + + @Override + public boolean start(final Player player, boolean login, Object... args) { + index = (int) args[0]; + return super.start(player, login, args); + } + + @Override + public void open() { + SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0))); + SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[getPath().length - 1].getLocalX(), getPath()[getPath().length - 1].getLocalY(), 0))); + player.getAppearance().setAnimations(Animation.create(211)); + player.getAppearance().setRidingMinecart(true); + player.getAppearance().sync(); + player.getWalkingQueue().reset(); + for (Location l : getPath()) { + Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); + player.getWalkingQueue().addPath(loc.getX(), loc.getY(), true); + } + GameWorld.getPulser().submit(new Pulse(22, player) { + @Override + public boolean pulse() { + player.setAttribute("real-end", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); + player.setAttribute("cutscene:original-loc", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); + MiningCartCutscene.this.stop(true); + return true; + } + }); + } + + @Override + public void end() { + super.end(); + player.getAppearance().setDefaultAnimations(); + player.getAppearance().setRidingMinecart(false); + player.getAppearance().sync(); + } + + @Override + public void fade() { + if (index == 0) { + player.getDialogueInterpreter().sendDialogue("You appear in a large open room with what looks like lots of miners", "working away. This is a very rough looking area, the miners look like", "they're on their last legs."); + } else { + player.getDialogueInterpreter().sendDialogue("You appear back in the barrel loading room. A nearby slave looks", "surprised to see you popping out of the cart."); + } + } + + @Override + public ActivityPlugin newInstance(Player p) { + return new MiningCartCutscene(p); + } + + @Override + public Location getSpawnLocation() { + return null; + } + + @Override + public Location getStartLocation() { + return base.transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0); + } + + @Override + public void configure() { + region = DynamicRegion.create(13203); + setRegionBase(); + registerRegion(region.getId()); + } + + /** + * Gets the path index. + * + * @return the location. + */ + public Location[] getPath() { + return PATHS[index]; + } + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("cart dialogue")}; + } + + } + + /** + * The winch cutscene plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class WinchCutscene extends CutscenePlugin { + + /** + * Constructs a new {@code WinchCutscene} {@code Object}. + */ + public WinchCutscene() { + super("winch cutscene"); + } + + /** + * Constructs a new {@code WinchCutscene} {@code Object}. + * + * @param player the player. + */ + public WinchCutscene(final Player player) { + super("winch cutscene"); + this.player = player; + } + + @Override + public ActivityPlugin newInstance(Player p) { + return new WinchCutscene(p); + } + + @Override + public void open() { + super.open(); + player.getPacketDispatch().sendMessage("You try to operate the winch."); + player.faceLocation(base.transform(15, 9, 0)); + player.animate(Animation.create(5054)); + GameWorld.getPulser().submit(new Pulse(AnimationDefinition.forId(5054).getDurationTicks(), player) { + @Override + public boolean pulse() { + TouristTrap.addConfig(player, 2048 + (1 << 4)); + WinchCutscene.this.stop(true); + player.getDialogueInterpreter().open(822, true, true); + return true; + } + }); + } + + @Override + public Location getSpawnLocation() { + return null; + } + + @Override + public Location getStartLocation() { + return base.transform(16, 10, 0); + } + + @Override + public void configure() { + region = DynamicRegion.create(13103); + setRegionBase(); + registerRegion(region.getId()); + } + + } + + /** + * The use with handler on the chest. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BedabinKeyHandler extends UseWithHandler { + + /** + * Constructs a new {@code BedabinKeyHandler} {@code Object}. + */ + public BedabinKeyHandler() { + super(TouristTrap.BEDABIN_KEY.getId()); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(2677, OBJECT_TYPE, this); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + player.getDialogueInterpreter().open(831, RegionManager.getNpc(player.getLocation(), 831, 16)); + return true; + } + + } + + /** + * The barrel dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BarrelDialogue extends DialoguePlugin { + + /** + * The scenery barrel. + */ + private Scenery barrel; + + /** + * The quest. + */ + private Quest quest; + + /** + * Constructs a new {@code BarrelDialogue} {@code Object}. + */ + public BarrelDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code BarrelDialogue} {@code Object}. + * + * @param player the player. + */ + public BarrelDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new BarrelDialogue(player); + } + + @Override + public boolean open(Object... args) { + barrel = (Scenery) args[0]; + quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if ((quest.getStage(player) == 70 || quest.getStage(player) == 72) && !player.hasItem(TouristTrap.ANNA_BARREL)) { + interpreter.sendDialogue("You search the barrels and find Ana."); + stage = 400; + return true; + } + if (player.getInventory().containsItem(TouristTrap.BARREL)) { + player.getPacketDispatch().sendMessage("You can only manage to have one of these at a time."); + end(); + return true; + } + interpreter.sendItemMessage(TouristTrap.BARREL, "This barrel is quite big. but you may be able to carry one. Would you like to take one?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 400:// finding anna. + interpreter.sendDialogues(823, null, "Let me out!"); + stage++; + break; + case 401: + if (!player.getInventory().hasSpaceFor(TouristTrap.ANNA_BARREL)) { + end(); + return true; + } + player.getPacketDispatch().sendMessage("You pick up Ana in a Barrel."); + player.getInventory().add(TouristTrap.ANNA_BARREL); + end(); + break; + case 402: + end(); + break; + case 0: + options("Yeah, cool!", "No thanks."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + interpreter.sendItemMessage(TouristTrap.BARREL, "You take the barrel, it's not heavy, just awkward."); + stage = 3; + break; + case 2: + end(); + break; + } + break; + case 3: + end(); + player.getInventory().add(TouristTrap.BARREL, player); + SceneryBuilder.remove(barrel); + GameWorld.getPulser().submit(new Pulse(40) { + @Override + public boolean pulse() { + SceneryBuilder.add(barrel); + return true; + } + }); + break; + + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("barrel dialogue")}; + } + + } + + /** + * The use with handler for the bedabin anvil. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BedabinAnvilHandler extends UseWithHandler { + + /** + * Constructs a new {@code BedabinAnvilHandler} {@code Object}. + */ + public BedabinAnvilHandler() { + super(2349); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(2672, OBJECT_TYPE, this); + ClassScanner.definePlugin(new PrototypeDartHandler()); + ClassScanner.definePlugin(new BedabinAnvilDialogue()); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if (quest.getStage(player) == 54 && player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { + player.getDialogueInterpreter().open("bedabin-anvil"); + return true; + } else { + player.getPacketDispatch().sendMessage("You need technical plans in order to do this."); + } + return true; + } + + /** + * The handler used to handle the anna barrel on the winch. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class AnnaWinchHandler extends UseWithHandler { + + /** + * Constructs a new {@code AnnaWinchHandler} {@code Object}. + */ + public AnnaWinchHandler() { + super(TouristTrap.ANNA_BARREL.getId()); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(18951, OBJECT_TYPE, this); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if (!event.getUsedWith().getLocation().equals(Location.create(3292, 9423, 0))) { + return false; + } + if (quest.getStage(player) == 70) { + player.getDialogueInterpreter().open("winch dialogue", true); + return true; + } + return false; + } + + } + + /** + * The prototype dart creation handler. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class PrototypeDartHandler extends UseWithHandler { + + /** + * Constructs a new {@code PrototypeDartHandler} {@code Object}. + */ + public PrototypeDartHandler() { + super(314); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(TouristTrap.PROTOTYPE_DART_TIP.getId(), ITEM_TYPE, this); + ClassScanner.definePlugin(new ProtoTypeDialogue()); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + player.getDialogueInterpreter().open("prototype dart"); + return true; + } + + /** + * The prototype dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class ProtoTypeDialogue extends DialoguePlugin { + + /** + * The feathers item. + */ + private static final Item FEATHERS = new Item(314, 10); + + /** + * Constructs a new {@code ProtoTypeDialogue} {@code Object}. + * + * @param player the player. + */ + public ProtoTypeDialogue(final Player player) { + super(player); + } + + /** + * Constructs a new {@code ProtoTypeDialogue} {@code Object}. + */ + public ProtoTypeDialogue() { + /** + * empty. + */ + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new ProtoTypeDialogue(player); + } + + @Override + public boolean open(Object... args) { + if (!player.getInventory().containsItem(FEATHERS)) { + interpreter.sendDialogue("You need 10 feathers in order to do this."); + stage = 10; + return false; + } + interpreter.sendItemMessage(314, "You try to attach feathers to the bronze dart tip."); + stage = 1; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 1: + interpreter.sendDialogue("Following the plans is tricky, but you persevere."); + stage++; + break; + case 2: + interpreter.sendItemMessage(TouristTrap.PROTOTYPE_DART, "You successfully attach the feathers to the dart tip."); + stage++; + break; + case 3: + player.getInventory().remove(FEATHERS, TouristTrap.PROTOTYPE_DART_TIP); + player.getInventory().add(TouristTrap.PROTOTYPE_DART); + end(); + break; + case 4: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("prototype dart")}; + } + + } + } + + /** + * The bedabin dialogue plugin handler. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BedabinAnvilDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. + */ + public BedabinAnvilDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. + * + * @param player the player. + */ + public BedabinAnvilDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new BedabinAnvilDialogue(player); + } + + @Override + public boolean open(Object... args) { + if (!player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { + player.getPacketDispatch().sendMessage("You need the plans to do this."); + return false; + } + player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "Do you want to follow the technical plans ?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + options("Yes. I'd like to try.", "No, not just yet."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + end(); + player.getPulseManager().run(new ProtoTypePulse(player)); + break; + case 2: + end(); + break; + } + break; + } + return true; + } + + /** + * The skill pulse used to make a prototype dart. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class ProtoTypePulse extends SkillPulse { + + /** + * The hammer item. + */ + private static final Item HAMMER = new Item(2347); + + /** + * The ticks passed. + */ + private int ticks; + + /** + * Constructs a new {@code ProtoTypePulse} {@code Object}. + * + * @param player the player. + */ + public ProtoTypePulse(Player player) { + super(player, null); + } + + @Override + public boolean checkRequirements() { + if (!player.getInventory().hasSpaceFor(TouristTrap.PROTOTYPE_DART_TIP)) { + player.getPacketDispatch().sendMessage("Not enough inventory space."); + return false; + } + if (!player.getInventory().containsItem(HAMMER)) { + player.getPacketDispatch().sendMessage("You need a hammer in order to work metal with."); + return false; + } + return player.getInventory().containsItem(Bar.BRONZE.getProduct()); + } + + @Override + public void animate() { + if (ticks % 4 == 0) { + player.animate(Animation.create(898)); + } + } + + @Override + public boolean reward() { + if (++ticks % 4 != 0) { + return false; + } + if (ticks == 4) { + player.getDialogueInterpreter().sendPlainMessage(true, "You begin experimenting in forging the weapon..."); + } else if (ticks == 8) { + player.getInventory().remove(Bar.BRONZE.getProduct()); + player.getInventory().add(TouristTrap.PROTOTYPE_DART_TIP); + player.getDialogueInterpreter().sendItemMessage(TouristTrap.PROTOTYPE_DART_TIP, "You follow the plans carefully, and after some careful", "work, you finally manage to forge a sharp, pointed...", "dart tip."); + return true; + } + return false; + } + + @Override + public void stop() { + super.stop(); + } + + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("bedabin-anvil")}; + } + + } + } } diff --git a/Server/src/main/content/region/fremennik/diary/FremennikAchievementDiary.kt b/Server/src/main/content/region/fremennik/diary/FremennikAchievementDiary.kt index 51d160974..3621ed8c6 100644 --- a/Server/src/main/content/region/fremennik/diary/FremennikAchievementDiary.kt +++ b/Server/src/main/content/region/fremennik/diary/FremennikAchievementDiary.kt @@ -167,7 +167,7 @@ class FremennikAchievementDiary : DiaryEventHookBase(DiaryType.FREMENNIK) { } override fun onResourceProduced(player: Player, event: ResourceProducedEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10553 -> if (event.source.id in FISHING_SPOTS) { finishTask( player, @@ -204,7 +204,7 @@ class FremennikAchievementDiary : DiaryEventHookBase(DiaryType.FREMENNIK) { } override fun onNpcKilled(player: Player, event: NPCKillEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10042, 10554 -> if (event.npc.id in ROCK_CRABS) { progressIncrementalTask( player, @@ -260,7 +260,7 @@ class FremennikAchievementDiary : DiaryEventHookBase(DiaryType.FREMENNIK) { } override fun onPickedUp(player: Player, event: PickUpEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10810 -> if (event.itemId == Items.SEAWEED_401) { progressIncrementalTask( player, @@ -284,7 +284,7 @@ class FremennikAchievementDiary : DiaryEventHookBase(DiaryType.FREMENNIK) { } override fun onSummoningPointsRecharged(player: Player, event: SummoningPointsRechargeEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10552 -> if (event.obelisk.id == Scenery.SMALL_OBELISK_29944) { finishTask( player, @@ -296,7 +296,7 @@ class FremennikAchievementDiary : DiaryEventHookBase(DiaryType.FREMENNIK) { } override fun onInteracted(player: Player, event: InteractionEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10811 -> if (event.target.id == Scenery.COLLAPSED_TRAP_19233 && inBorders(player, RELLEKKA_HUNTING_AREA) && event.option == "dismantle") { finishTask( player, diff --git a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt index e7b48f9d3..95d4b1827 100644 --- a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt +++ b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt @@ -8,8 +8,6 @@ import core.game.node.entity.player.Player import core.game.node.entity.player.link.diary.DiaryType import core.game.node.entity.player.link.music.MusicEntry import core.game.node.entity.skill.Skills -import content.global.skill.gather.woodcutting.WoodcuttingSkillPulse -import core.game.node.scenery.Scenery import core.game.system.task.Pulse import core.game.world.map.Location import core.game.world.map.RegionManager @@ -23,6 +21,7 @@ import core.game.system.config.ItemConfigParser import core.game.world.GameWorld.Pulser import content.data.Quests import core.game.interaction.QueueStrength +import core.game.node.Node class TFTInteractionListeners : InteractionListener { @@ -74,7 +73,7 @@ class TFTInteractionListeners : InteractionListener { removeItem(player,LOW_ALC_KEG) setAttribute(player,"/save:fremtrials:keg-mixed", true) sendMessage(player,"The cherry bomb in the pipe goes off.") - RegionManager.getLocalEntitys(player).stream().forEach { e -> e.sendChat("What was THAT??") } + RegionManager.getLocalNPCs(player.location).stream().forEach { e -> e.sendChat("What was THAT??") } sendMessage(player,"You mix the kegs together.") } else { player.dialogueInterpreter?.sendDialogue("I can't do this right now. I should create","a distraction.") @@ -204,7 +203,7 @@ class TFTInteractionListeners : InteractionListener { setAttribute(player,"/save:fremtrials:maze-complete",true) DestRoom(2662, 10034, 2668, 10039).getCenter() } - else -> getRandomLocation(player) + else -> getRandomLocation(player, portal) } return@on true } @@ -280,17 +279,15 @@ class TFTInteractionListeners : InteractionListener { return Location((swx + nex) / 2, (swy + ney) / 2).transform(1,0,0) } - fun getRandomLocation(player: Player?): Location{ - var obj: Scenery? = null - - while(obj?.id != 5138) { - val objects = player?.viewport?.chunks?.random()?.random()?.objects - obj = objects?.random()?.random() - if(obj == null || obj.location?.equals(Location(0,0,0))!!){ - continue + fun getRandomLocation(player: Player, portal: Node): Location { + val objects = player.location.region.assembleObjectList(player.location.z) + objects.shuffle() + for (o in objects) { + if (o.id == 5138) { + return o.location } } - return obj.location + return portal.location } fun hasEquippableItems(player: Player?): Boolean { diff --git a/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java b/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java index 65f5d4e43..7a30ca024 100644 --- a/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java +++ b/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java @@ -10,6 +10,7 @@ import core.game.node.entity.npc.AbstractNPC; import core.game.node.entity.player.Player; import core.game.world.map.Location; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.tools.RandomFunction; /** @@ -70,7 +71,7 @@ public final class DagannothKingNPC extends AbstractNPC { state.setEstimatedHit(RandomFunction.random(type.getMaxHit() - 5, type.getMaxHit())); } if (type != DagType.REX && RandomFunction.random(5) <= 2) { - List players = RegionManager.getLocalPlayers(this, 9); + List players = RegionManager.getLocalPlayers(location, 9); if (players.size() <= 1) { return; } diff --git a/Server/src/main/content/region/fremennik/waterbirth/handlers/WaterBirthDungeonZone.java b/Server/src/main/content/region/fremennik/waterbirth/handlers/WaterBirthDungeonZone.java index 1a5a35235..6fa067f6a 100644 --- a/Server/src/main/content/region/fremennik/waterbirth/handlers/WaterBirthDungeonZone.java +++ b/Server/src/main/content/region/fremennik/waterbirth/handlers/WaterBirthDungeonZone.java @@ -17,6 +17,7 @@ import core.game.node.entity.combat.CombatStyle; import core.game.node.entity.npc.AbstractNPC; import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; +import core.game.node.item.GroundItemManager; import core.game.node.scenery.SceneryBuilder; import core.game.system.task.Pulse; import core.game.world.GameWorld; @@ -71,7 +72,7 @@ public final class WaterBirthDungeonZone extends MapZone implements Plugin npcs = RegionManager.getLocalNpcs(location, 0); + List npcs = RegionManager.getLocalNPCs(location, 0); NPC npc = null; if (npcs.size() != 0) { npc = npcs.get(0); @@ -243,10 +244,10 @@ public final class WaterBirthDungeonZone extends MapZone implements Plugin 0) { + if (!RegionManager.getLocalPlayers(location, 0).isEmpty()) { return true; } - if (RegionManager.getRegionPlane(location).getItem(Items.PET_ROCK_3695,location,player) != null) { + if (GroundItemManager.get(Items.PET_ROCK_3695, location, player) != null) { return true; } return false; @@ -411,9 +412,9 @@ public final class WaterBirthDungeonZone extends MapZone implements Plugin System.currentTimeMillis()) { end(); - for (NPC npc : RegionManager.getLocalNpcs(player.getLocation(), 8)) { + for (NPC npc : RegionManager.getLocalNPCs(player.getLocation(), 8)) { if (!npc.getProperties().getCombatPulse().isAttacking() && npc.getId() == 32) { npc.sendChat("Hey! Get your hands off there!"); npc.getProperties().getCombatPulse().attack(player); diff --git a/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt b/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt index e6c54d22a..9997bb2b1 100644 --- a/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt +++ b/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt @@ -8,6 +8,7 @@ import core.game.dialogue.* 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.RegionManager import core.plugin.Initializable import core.tools.END_DIALOGUE import org.rs09.consts.* @@ -130,12 +131,9 @@ class AlomoneDialogue(player: Player? = null) : DialoguePlugin(player) { // active dialogue or speaking to alomone, and just dealing with the fact that their hazeel is not on the map. relogging and restarting // the dialogue would get these players a new hazeel. private fun Player.findNpcInViewport(npcId: Int): NPC? { - val viewport = viewport ?: return null - for (plane in viewport.viewingPlanes) { - for (npc in plane.npcs) { - if (npc.id == npcId) { - return npc - } + for (npc in RegionManager.getLocalNPCs(location)) { + if (npc.id == npcId) { + return npc } } return null diff --git a/Server/src/main/content/region/kandarin/ardougne/quest/plaguecity/dialogue/mourners/MournerKidnapDialogue.kt b/Server/src/main/content/region/kandarin/ardougne/quest/plaguecity/dialogue/mourners/MournerKidnapDialogue.kt index 671b7d38b..a75ae7827 100644 --- a/Server/src/main/content/region/kandarin/ardougne/quest/plaguecity/dialogue/mourners/MournerKidnapDialogue.kt +++ b/Server/src/main/content/region/kandarin/ardougne/quest/plaguecity/dialogue/mourners/MournerKidnapDialogue.kt @@ -56,7 +56,7 @@ class MournerKidnapDialogueFile : DialogueFile(){ // Figure out who we are. It needs to be this since we can enter this dialogue from a door // Do this for the first time regardless of where we are if (stage == 0) { - RegionManager.getLocalNpcs(player!!, 2).forEach { + RegionManager.getLocalNPCs(player!!.location, 2).forEach { if (it.id == NPCs.MOURNER_3216) { closeMourner = it resetFace(closeMourner!!) @@ -78,7 +78,7 @@ class MournerKidnapDialogueFile : DialogueFile(){ 2 -> npcl(FacialExpression.HALF_WORRIED, " This is highly irregular. Please wait...").also { stage++ } 3 -> { // Look further for the other one - RegionManager.getLocalNpcs(player!!, 10).forEach { + RegionManager.getLocalNPCs(player!!.location, 10).forEach { if (it.id == NPCs.MOURNER_3216 && it != closeMourner){ farMourner = it resetFace(farMourner!!) diff --git a/Server/src/main/content/region/kandarin/feldip/quest/chompybird/BloatedToadNPC.kt b/Server/src/main/content/region/kandarin/feldip/quest/chompybird/BloatedToadNPC.kt index 49a074680..36d328445 100644 --- a/Server/src/main/content/region/kandarin/feldip/quest/chompybird/BloatedToadNPC.kt +++ b/Server/src/main/content/region/kandarin/feldip/quest/chompybird/BloatedToadNPC.kt @@ -43,7 +43,7 @@ class BloatedToadNPC : AbstractNPC { super.handleTickActions() if (ticksToLive-- <= 0) { - val toDamage = RegionManager.getLocalEntitys(this.location, 2) + val toDamage = RegionManager.getLocalEntities(this.location, 2) for (entity in toDamage) { if (entity == this) continue diff --git a/Server/src/main/content/region/kandarin/quest/dwarfcannon/dmc/DMCHandler.java b/Server/src/main/content/region/kandarin/quest/dwarfcannon/dmc/DMCHandler.java index 9b7d2363c..d66f0b062 100644 --- a/Server/src/main/content/region/kandarin/quest/dwarfcannon/dmc/DMCHandler.java +++ b/Server/src/main/content/region/kandarin/quest/dwarfcannon/dmc/DMCHandler.java @@ -6,7 +6,6 @@ import core.game.node.entity.combat.ImpactHandler.HitsplatType; import core.game.node.entity.impl.Projectile; import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.audio.Audio; import core.game.node.entity.skill.Skills; import core.game.node.item.Item; import core.game.node.scenery.Scenery; @@ -51,10 +50,10 @@ public final class DMCHandler implements LogoutListener { */ private DMCRevolution direction = DMCRevolution.NORTH; - private CannonTimer timer; + private CannonTimer timer; public DMCHandler() { - this.player = null; + this.player = null; } /** @@ -78,7 +77,7 @@ public final class DMCHandler implements LogoutListener { Location l = cannon.getLocation().transform(1, 1, 0); playGlobalAudio(l, Sounds.MCANNON_TURN_2877); direction = DMCRevolution.values()[(direction.ordinal() + 1) % DMCRevolution.values().length]; - for (NPC npc : RegionManager.getLocalNpcs(l, 10)) { + for (NPC npc : RegionManager.getLocalNPCs(l, 10)) { if (direction.isInSight(npc.getLocation().getX() - l.getX(), npc.getLocation().getY() - l.getY()) && npc.isAttackable(player, CombatStyle.RANGE, false) && CombatSwingHandler.isProjectileClipped(npc, l, false)) { int speed = (int) (25 + (l.getDistance(npc.getLocation()) * 10)); Projectile.create(l, npc.getLocation(), 53, 40, 36, 20, speed, 0, 128).send(); @@ -106,8 +105,8 @@ public final class DMCHandler implements LogoutListener { return; } if (timer.isFiring()) { - timer.setFiring(false); - return; + timer.setFiring(false); + return; } if (cannonballs < 1) { int amount = player.getInventory().getAmount(new Item(2)); @@ -127,7 +126,7 @@ public final class DMCHandler implements LogoutListener { player.sendMessage("Your cannon is already fully loaded."); } } - timer.setFiring(true); + timer.setFiring(true); } /** @@ -138,7 +137,7 @@ public final class DMCHandler implements LogoutListener { return; } player.sendMessage("Your cannon has " + (decay ? "decayed" : "been destroyed") + "!"); - for (Player p : RegionManager.getLocalPlayers(player)) { + for (Player p : RegionManager.getLocalPlayers(player.getLocation())) { p.getPacketDispatch().sendPositionedGraphic(189, 0, 1, cannon.getLocation()); } clear(false); @@ -194,15 +193,15 @@ public final class DMCHandler implements LogoutListener { player.getPacketDispatch().sendMessage("You add the furnace."); SceneryBuilder.remove(object); handler.configure(SceneryBuilder.add(object = object.transform(6))); - handler.timer = (CannonTimer) spawnTimer ("dmc:timer", handler); - registerTimer (player, handler.timer); + handler.timer = (CannonTimer) spawnTimer ("dmc:timer", handler); + registerTimer (player, handler.timer); return true; } playGlobalAudio(player.getLocation(), Sounds.MCANNON_SETUP_2876); - if(count != 0) { - SceneryBuilder.remove(object); - SceneryBuilder.add(object = object.transform(object.getId() + 1)); - } + if(count != 0) { + SceneryBuilder.remove(object); + SceneryBuilder.add(object = object.transform(object.getId() + 1)); + } return ++count == 4; } }); diff --git a/Server/src/main/content/region/kandarin/seers/diary/SeersVillageAchievementDiary.kt b/Server/src/main/content/region/kandarin/seers/diary/SeersVillageAchievementDiary.kt index bd9e90188..1581baeac 100644 --- a/Server/src/main/content/region/kandarin/seers/diary/SeersVillageAchievementDiary.kt +++ b/Server/src/main/content/region/kandarin/seers/diary/SeersVillageAchievementDiary.kt @@ -109,7 +109,7 @@ class SeersVillageAchievementDiary : DiaryEventHookBase(DiaryType.SEERS_VILLAGE) ) } - when (player.viewport.region.id) { + when (player.location.regionId) { 10805 -> if (event.itemId == Items.FLAX_1779) { progressIncrementalTask( player, @@ -192,7 +192,7 @@ class SeersVillageAchievementDiary : DiaryEventHookBase(DiaryType.SEERS_VILLAGE) } override fun onNpcKilled(player: Player, event: NPCKillEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10906 -> if (event.npc.id in WORKSHOP_ELEMENTALS) { progressFlaggedTask( player, @@ -316,7 +316,7 @@ class SeersVillageAchievementDiary : DiaryEventHookBase(DiaryType.SEERS_VILLAGE) } override fun onItemPurchasedFromShop(player: Player, event: ItemShopPurchaseEvent) { - if (event.itemId == Items.CANDLE_36 && player.viewport.region.id == 11061) { + if (event.itemId == Items.CANDLE_36 && player.location.regionId == 11061) { finishTask( player, DiaryLevel.EASY, @@ -344,7 +344,7 @@ class SeersVillageAchievementDiary : DiaryEventHookBase(DiaryType.SEERS_VILLAGE) } override fun onPrayerPointsRecharged(player: Player, event: PrayerPointsRechargeEvent) { - if (player.viewport.region.id == 10806) { + if (player.location.regionId == 10806) { if (event.altar.id == Scenery.ALTAR_409 || event.altar.id == Scenery.ALTAR_19145) { finishTask( player, diff --git a/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java b/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java index 5589a4d69..b8e504953 100644 --- a/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java +++ b/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java @@ -45,1168 +45,1168 @@ import static core.api.ContentAPIKt.*; @Initializable public final class RangingGuildPlugin extends OptionHandler { - @Override - public Plugin newInstance(Object arg) throws Throwable { - SceneryDefinition.forId(2514).getHandlers().put("option:open", this); - SceneryDefinition.forId(2511).getHandlers().put("option:climb-up", this); - SceneryDefinition.forId(2512).getHandlers().put("option:climb-down", this); - SceneryDefinition.forId(2513).getHandlers().put("option:fire-at", this); - new RangingGuildDoorman().init(); - new GuardDialogue().init(); - new LeatherWorkerDialogue().init(); - new ArmourSalesman().init(); - new TribalWeaponSalesman().init(); - new BowArrowSalesman().init(); - new WarningInterface().newInstance(arg); - new CompetitionJudge().init(); - ClassScanner.definePlugin(new TowerArcher()); - return this; - } - - @Override - public boolean handle(Player player, Node node, String option) { - final int id = node instanceof Scenery ? ((Scenery) node).getId() : 0; - switch (option) { - case "fire-at": - if (player.getArcheryTargets() <= 0) { - player.getDialogueInterpreter().sendDialogues(693, null, "Sorry, you may only use the targets for the", "competition, not for practicing."); - return true; - } - if (!player.getEquipment().containsItem(new Item(882)) - || player.getEquipment().get(EquipmentContainer.SLOT_WEAPON) == null - || (!player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("shortbow") - && !player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("longbow"))) { - player.sendMessage("You must have bronze arrows and a bow equipped."); - return true; - } - player.getPulseManager().run(new ArcheryCompetitionPulse(player, (Scenery) node)); - break; - case "open": - switch (id) { - case 2514: - if (player.getLocation().getY() >= 3438) { - if (player.getSkills().getStaticLevel(Skills.RANGE) < 40) { - player.getDialogueInterpreter().sendDialogue("You need a Ranging level of 40 to enter here."); - return true; - } - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node, player.getLocation().getY() >= 3438 ? Location.create(2659, 3437, 0) : Location.create(2657, 3439, 0)); - break; - } - break; - case "climb-up": - switch (id) { - case 2511: - player.setAttribute("ladder", node); - player.getInterfaceManager().open(new Component(564)); - break; - } - break; - case "climb-down": - switch (id) { - case 2512: - ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 0)); - break; - } - break; - } - return true; - } - - @Override - public Location getDestination(Node node, Node n) { - if (n instanceof Scenery) { - if (((Scenery) n).getDefinition().hasAction("open")) { - if (((Scenery) n).getId() == 2514) { - if (node.getLocation().getY() >= 3438) { - return Location.create(2657, 3439, 0); - } else { - return Location.create(2659, 3437, 0); - } - } - return DoorActionHandler.getDestination((Player) node, (Scenery) n); - } - if (((Scenery) n).getId() == 2513) - return Location.create(2673, 3420, 0); - } - return null; - } - - /** - * Represents the dialogue used for the ranging guild door man. - * - * @author 'Vexia - * @version 1.0 - */ - public class RangingGuildDoorman extends DialoguePlugin { - - /** - * Constructs a new {@code RangingGuildDoorman} {@code Object}. - */ - public RangingGuildDoorman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code RangingGuildDoorman} {@code Object}. - * - * @param player the player. - */ - public RangingGuildDoorman(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new RangingGuildDoorman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello there."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Greetings. If you are an experienced archer, you may", "want to visit the guild here..."); - stage = 1; - break; - case 1: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{679}; - } - } - - /** - * Represents the tribal weapon salseman dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class TribalWeaponSalesman extends DialoguePlugin { - - /** - * Constructs a new {@code TribalWeaponSalesman} {@code Object}. - */ - public TribalWeaponSalesman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code TribalWeaponSalesman} {@code Object}. - * - * @param player the player. - */ - public TribalWeaponSalesman(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new TribalWeaponSalesman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - player("Hello there."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("Greetings, traveller. Are you interested in any throwing", "weapons?"); - stage = 1; - break; - case 1: - options("Yes I am.", "Not really."); - stage = 2; - break; - case 2: - switch (buttonId) { - case 1: - player("Yes I am."); - stage = 10; - break; - case 2: - player("Not really."); - stage = 20; - break; - } - break; - case 10: - npc("That is a good thing."); - stage = 11; - break; - case 11: - end(); - npc.openShop(player); - break; - case 20: - npc("No bother to me."); - stage = 21; - break; - case 21: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{692}; - } - - } - - /** - * Represents the guard dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class GuardDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code GuardDialogue} {@code Object}. - */ - public GuardDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code GuardDialogue} {@code Object}. - * - * @param player the player. - */ - public GuardDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new GuardDialogue(player); - } - - @Override - public boolean open(Object... args) { - player("Hello there."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("Greetings, traveller. Enjoy the time at the Ranging", "Guild."); - stage = 1; - break; - case 1: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{678}; - } - - } - - /** - * Represents the leather workers dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class LeatherWorkerDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. - */ - public LeatherWorkerDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. - * - * @param player the player. - */ - public LeatherWorkerDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new LeatherWorkerDialogue(player); - } - - @Override - public boolean open(Object... args) { - player("Hello."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("Can I help you?"); - stage = 1; - break; - case 1: - options("What do you do here?", "No thanks."); - stage = 2; - break; - case 2: - switch (buttonId) { - case 1: - player("What do you do here?"); - stage = 10; - break; - case 2: - player("No thanks."); - stage = 20; - break; - } - break; - case 10: - npc("Well, I can cure plain cowhides into pieces of leather", "ready for crafting."); - stage = 11; - break; - case 11: - npc("I work with ordinary, hard or dragonhide leather and", "also snakeskin."); - stage = 12; - break; - case 12: - end(); - TanningProduct.open(player, 680); - break; - case 20: - npc("Suit yourself."); - stage = 21; - break; - case 21: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{680}; - } - - } - - /** - * Represents the armour salesman dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class ArmourSalesman extends DialoguePlugin { - - /** - * Constructs a new {@code ArmourSalesman} {@code Object}. - */ - public ArmourSalesman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code ArmourSalesman} {@code Object}. - * - * @param player the player. - */ - public ArmourSalesman(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new ArmourSalesman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - player("Good day to you."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("And to you. Can I help you?"); - stage = 1; - break; - case 1: - if (Skillcape.isMaster(player, Skills.RANGE)) { - options("What do you do here?", "I'd like to see what you sell.", "Can I buy a Skillcape of Range?", "I've seen enough, thanks."); - stage = 100; - } else { - options("What do you do here?", "I'd like to see what you sell.", "I've seen enough, thanks."); - stage = 2; - } - break; - case 2: - switch (buttonId) { - case 1: - player("What do you do here?"); - stage = 10; - break; - case 2: - player("I'd like to see what you sell."); - stage = 20; - break; - case 3: - player("I've seen enough, thanks."); - stage = 30; - break; - } - break; - case 10: - npc("I am a supplier of leather armours and accessories. Ask", "and I will tell you what I know."); - stage = 11; - break; - case 11: - options("Tell me about your armours.", "Tell me about your accessories.", "I've seen enough, thanks."); - stage = 12; - break; - case 12: - switch (buttonId) { - case 1: - player("Tell me about your armours."); - stage = 13; - break; - case 2: - player("Tell me about your accessories."); - stage = 15; - break; - case 3: - player("I've seen enough, thanks."); - stage = 30; - break; - } - break; - case 13: - npc("I have normal, studded and hard types."); - stage = 14; - break; - case 14: - case 31: - case 105: - end(); - break; - case 15: - npc("Ah yes we have a new range of accessories in stock.", "Essential items for an archer like you."); - stage = 14; - break; - case 20: - npc("Indeed, cast your eyes on my wares, adventurer."); - stage = 21; - break; - case 21: - end(); - npc.openShop(player); - break; - case 30: - npc("Very good, adventurer."); - stage = 31; - break; - case 100: - switch (buttonId) { - case 1: - player("What do you do here?"); - stage = 10; - break; - case 2: - player("I'd like to see what you sell."); - stage = 20; - break; - case 3: - player("Can I buy a Skillcape of Range?"); - stage = 101; - break; - case 4: - player("I've seen enough, thanks."); - stage = 30; - break; - } - break; - case 101: - npc("Certainly! Right when you give me 99000 coins."); - stage = 102; - break; - case 102: - options("Okay, here you go.", "No, thanks."); - stage = 103; - break; - case 103: - switch (buttonId) { - case 1: - player("Okay, here you go."); - stage = 104; - break; - case 2: - end(); - break; - } - break; - case 104: - if (Skillcape.purchase(player, Skills.RANGE)) { - npc("There you go! Enjoy."); - } - stage = 105; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{682}; - } - - } - - /** - * Represents the dialogue plugin used for the bow and arrow salesman. - * - * @author 'Vexia - * @version 1.0 - */ - public final class BowArrowSalesman extends DialoguePlugin { - - /** - * Constructs a new {@code BowArrowSalesman} {@code Object}. - */ - public BowArrowSalesman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code BowArrowSalesman} {@code Object}. - * - * @param player the player. - */ - public BowArrowSalesman(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new BowArrowSalesman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - player("Hello."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("A fair day, traveller. Would you like to see my wares?"); - stage = 1; - break; - case 1: - options("Yes please.", "No thanks."); - stage = 2; - break; - case 2: - switch (buttonId) { - case 1: - end(); - npc.openShop(player); - - break; - case 2: - end(); - break; - } - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{683}; - } - - } - - /** - * Represents the waring interface used in the guild. - * - * @author 'Vexia - * @version 1.0 - */ - public final class WarningInterface extends ComponentPlugin { - - @Override - public Plugin newInstance(Object arg) throws Throwable { - ComponentDefinition.forId(564).setPlugin(this); - return this; - } - - @Override - public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) { - switch (button) { - case 17: - ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 2)); - player.getInterfaceManager().close(); - List npcs = RegionManager.getLocalNpcs(Location.create(2668, 3427, 2)); - String dir = ""; - for (NPC n : npcs) { - if (n.getId() >= 684 && n.getId() <= 687) { - switch (n.getId()) { - case 684: - dir = "north"; - break; - case 685: - dir = "east"; - break; - case 686: - dir = "south"; - break; - case 687: - dir = "west"; - break; - } - n.sendChat("The " + dir + " tower is occupied, get them!"); - } - } - break; - case 18: - player.getInterfaceManager().close(); - break; - } - return true; - } - - } - - /** - * Represents the competition judge. - * - * @author afaroutdude - */ - public final class CompetitionJudge extends DialoguePlugin { - - /** - * Constructs a new {@code CompetitionJudge} {@code Object}. - * - * @param player the player. - */ - public CompetitionJudge(final Player player) { - super(player); - } - - /** - * Constructs a new {@code CompetitionJudge} {@code Object}. - */ - public CompetitionJudge() { - /** - * empty. - */ - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new CompetitionJudge(player); - } - - @Override - public boolean open(Object... args) { - if (player.getInventory().getAmount(1464) >= 1000 - && !player.getAchievementDiaryManager().hasCompletedTask(DiaryType.SEERS_VILLAGE, 1, 7)) { - npc("Wow! I see that you've got yourself a whole load of ", "archery tickets. Well done!"); - player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 7); - stage = -1; - } else if (player.getArcheryTargets() > 0) { - npc("Hello again, do you need reminding of the rules?"); - stage = 20; - } else if (player.getArcheryTotal() == 0) { - npc("Hello there, would you like to take part in the", - "archery competition? It only costs 200 coins to", - "enter."); - stage = 0; - } else { - int reward = player.getArcheryTotal() / 10; - npc("Well done. Your score is: " + player.getArcheryTotal() + ".", - "For that score you will receive " + reward + " Archery tickets."); - player.setArcheryTargets(-1); - player.setArcheryTotal(0); - if (!player.getInventory().add(new Item(1464, reward))) { - player.getBank().add(new Item(1464, reward)); - player.sendMessage("Your reward was sent to your bank."); - } - stage = 999; - } - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 999: - end(); - break; - case -1: - if (player.getArcheryTargets() > 0) { - npc("Hello again, do you need reminding of the rules?"); - stage = 20; - } else if (player.getArcheryTotal() == 0) { - npc("Hello there, would you like to take part in the", - "archery competition? It only costs 200 coins to", - "enter."); - stage = 0; - } else { - int reward = player.getArcheryTotal() / 10; - npc("Well done. Your score is: " + player.getArcheryTotal() + ".", - "For that score you will receive " + reward + " Archery tickets."); - if (!player.getInventory().add(new Item(1464, reward))) { - player.getBank().add(new Item(1464, reward)); - player.sendMessage("Your reward was sent to your bank."); - } - stage = 999; - } - break; - case 0: - options("Sure, I'll give it a go.", "What are the rules?", "No thanks."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - player("Sure, I'll give it a go."); - stage = 2; - break; - case 2: - player("What are the rules?"); - stage = 5; - break; - case 3: - player("No thanks."); - stage = 999; - break; - } - break; - case 2: - npc("Great! That will be 200 coins then please."); - stage++; - break; - case 3: - if (player.getInventory().getAmount(995) < 200) { - player("Oops, I don't have enough coins on me..."); - stage++; - } else { - end(); - player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); - player.getInventory().remove(new Item(995, 200)); - player.getInventory().add(new Item(882, 10)); - player.setArcheryTargets(10); - player.setArcheryTotal(0); - } - break; - case 4: - npc("Never mind, come back when you've got enough."); - stage = 999; - break; - case 5: - case 22: - npc("The rules are very simple:"); - stage++; - break; - case 6: - case 23: - npc("You're given 10 shots at the targets, for each hit", "you will receive points. At the end you'll be", "rewarded 1 ticket for every 10 points."); - stage++; - break; - case 7: - npc("The tickets can be exchanged for goods from our stores.", "Do you want to give it a go? Only 200 coins."); - stage++; - break; - case 8: - options("Sure, I'll give it a go.", "No thanks."); - stage++; - break; - case 9: - switch (buttonId) { - case 1: - player("Sure, I'll give it a go."); - stage = 2; - break; - case 3: - player("No thanks."); - stage = 999; - break; - } - break; - case 20: - int arrows = player.getInventory().getAmount(Items.BRONZE_ARROW_882) - + player.getEquipment().getAmount(Items.BRONZE_ARROW_882); - if (arrows < 1) { - player("Well, I actually don't have any more arrows. Could I", "get some more?"); - stage = 25; - } else { - options("Yes please.", "No thanks, I've got it.", "How am I doing so far?"); - stage++; - } - break; - case 21: - switch (buttonId) { - case 1: - player("Yes please."); - stage++; - break; - case 2: - player("No thanks, I've got it."); - stage = 30; - break; - case 3: - player("How am I doing so far?"); - stage = 40; - break; - } - break; - case 24: - npc("The tickets can be exchanged for goods from our stores.", "Good Luck!"); - stage = 999; - break; - case 25: - npc("Ok, but it'll cost you 100 coins."); - stage++; - break; - case 26: - options("Sure, I'll take some.", "No thanks."); - stage++; - break; - case 27: - switch (buttonId) { - case 1: - player("Sure, I'll take some."); - stage++; - break; - case 2: - player("No thanks."); - stage = 999; - break; - } - break; - case 28: - if (player.getInventory().getAmount(995) < 100) { - player("Oops, I don't have enough coins on me..."); - stage++; - } else { - end(); - player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); - player.getInventory().remove(new Item(995, 100)); - player.getInventory().add(new Item(882, 10)); - } - break; - case 30: - npc("Glad to hear it, good luck!"); - stage = 999; - break; - case 40: - String msg; - if (player.getArcheryTotal() <= 0) { - msg = "You haven't started yet."; - } else if (player.getArcheryTotal() <= 80) { - msg = "Not bad, keep going."; - } else { - msg = "You're pretty good, keep it up."; - } - npc("So far your score is: " + player.getArcheryTotal(), msg); - stage = 999; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{693}; - } - - } - - /** - * Represents the tower advisors. - * - * @author afaroutdude - */ - public final class TowerAdvisor extends DialoguePlugin { - - /** - * Constructs a new {@code TowerAdvisor} {@code Object}. - * - * @param player the player. - */ - public TowerAdvisor(final Player player) { - super(player); - } - - /** - * Constructs a new {@code TowerAdvisor} {@code Object}. - */ - public TowerAdvisor() { - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new TowerAdvisor(player); - } - - @Override - public boolean open(Object... args) { - player("Hello there, what do you do here?"); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 999: - end(); - case 0: - npc("Hi. We are in charge of this practice area."); - stage++; - break; - case 1: - player("This is a practice area?"); - break; - case 2: - npc("Surrounding us are four towers. Each tower contains", - "trained archers of a different level. You'll notice", - "it's quite a distance, so you'll need a longbow."); - stage++; - break; - case 3: - int rangeLevel = player.getSkills().getLevel(Skills.RANGE); - if (rangeLevel < 50) { // north - npc("As you're not very skilled, I advise you to practice", - "on the north tower. That'll provide the best", - "challenge for you."); - } else if (rangeLevel < 60) { // east - npc("You appear to be somewhat skilled with a bow, so I", - "advise you to practice on the south tower. That'll", - "provide the best challenge for you."); - } else if (rangeLevel < 70) { // south - npc("You appear to be fairly skilled with a bow, so I", - "advise you to practice on the south tower. That'll", - "provide the best challenge for you."); - } else { // west - npc("Looks like you're very skilled, so I advise you to", - "practice on the west tower. That'll provide the best", - "challenge for you."); - } - stage = 999; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{684, 685, 686, 687}; - } - - } - - - /** - * Represents all the tower archers - * - * @author afaroutdude - */ - public final class TowerArcher extends AbstractNPC { - - public TowerArcher() { - super(-1, null); - } - public TowerArcher(int id, Location location) { - super(id, location); - } - - - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new TowerArcher(id, location); - } - - @Override - public int[] getIds() { - return new int[]{688, 689, 690, 691}; - } - } - - /** - * Represents the archery target pulse. - * - * @author Jamix77 - */ - public static final class ArcheryCompetitionPulse extends Pulse { - - /** - * Represents the player instance. - */ - private final Player player; - - /** - * Represents the scenery. - */ - private final Scenery object; - - /** - * Constructs a new {@code ArcheryCompetitionPulse} {@code Object}. - * - * @param player the player. - * @param object the object. - */ - public ArcheryCompetitionPulse(final Player player, final Scenery object) { - super(1, player, object); - this.player = player; - this.object = object; - } - - private void showInterface(int points, int arrowsLeft, int target, String msg) { - player.getInterfaceManager().openComponent(325); - setVarp(player, 156, 11 - arrowsLeft); - setVarp(player, 157, points); - setVarp(player, 158, target); - player.getPacketDispatch().sendString(msg, 325, 32); - } - - @Override - public boolean pulse() { - if (player.getArcheryTargets() <= 0) { - return true; - } - if (getDelay() == 1) { - setDelay(player.getProperties().getAttackSpeed()); - } - if (player.getEquipment().remove(new Item(Items.BRONZE_ARROW_882, 1))) { - Projectile p = Ammunition.get(Items.BRONZE_ARROW_882).getProjectile().transform(player, object.getLocation()); - p.setEndLocation(object.getLocation()); - p.setEndHeight(25); - p.send(); - player.animate(new Animation(426)); - player.lock(getDelay()); - - int level = player.getSkills().getLevel(Skills.RANGE); - int bonus = player.getProperties().getBonuses()[14]; - double prayer = 1.0; - prayer += player.getPrayer().getSkillBonus(Skills.RANGE); - double cumulativeStr = Math.floor(level * prayer); - /*if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_RANGE_ACCURATE) { - cumulativeStr += 3; - } else if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_LONG_RANGE) { - cumulativeStr += 1; - }*/ - cumulativeStr *= 1.0; - int hit = (int) ((14 + cumulativeStr + (bonus / 8) + ((cumulativeStr * bonus) * 0.016865))) / 10 + 1; - hit = hit + RandomFunction.randomSign(RandomFunction.random(3)); - - int target = Math.max(0, 13 - hit); - int points = 0; - String msg = ""; - switch (target) { - case 0: - points = 100; - msg = "Bulls-Eye!"; - break; - case 1: - points = 50; - msg = "Hit Yellow!"; - break; - case 2: - case 3: - case 4: - points = 30; - msg = "Hit Red!"; - break; - case 5: - case 6: - case 7: - case 8: - points = 20; - msg = "Hit Blue!"; - break; - case 9: - case 10: - points = 10; - msg = "Hit Black!"; - break; - case 11: - case 12: - case 13: - points = 0; - msg = "Missed!"; - break; - } - int xp = points / 2; - - player.getSkills().addExperience(Skills.RANGE, xp, true); - player.setArcheryTotal(player.getArcheryTotal() + points); - player.setArcheryTargets(player.getArcheryTargets() - 1); - player.debug("Hit: " + hit); - player.debug("You have " + player.getArcheryTargets() + " targets left."); - player.debug("You have " + player.getArcheryTotal() + " score."); - - showInterface(player.getArcheryTotal(), player.getArcheryTargets(), target, msg); - - return true; //player.getArcheryTargets() <= 0; - } else { - return true; - } - } - - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + SceneryDefinition.forId(2514).getHandlers().put("option:open", this); + SceneryDefinition.forId(2511).getHandlers().put("option:climb-up", this); + SceneryDefinition.forId(2512).getHandlers().put("option:climb-down", this); + SceneryDefinition.forId(2513).getHandlers().put("option:fire-at", this); + new RangingGuildDoorman().init(); + new GuardDialogue().init(); + new LeatherWorkerDialogue().init(); + new ArmourSalesman().init(); + new TribalWeaponSalesman().init(); + new BowArrowSalesman().init(); + new WarningInterface().newInstance(arg); + new CompetitionJudge().init(); + ClassScanner.definePlugin(new TowerArcher()); + return this; + } + + @Override + public boolean handle(Player player, Node node, String option) { + final int id = node instanceof Scenery ? ((Scenery) node).getId() : 0; + switch (option) { + case "fire-at": + if (player.getArcheryTargets() <= 0) { + player.getDialogueInterpreter().sendDialogues(693, null, "Sorry, you may only use the targets for the", "competition, not for practicing."); + return true; + } + if (!player.getEquipment().containsItem(new Item(882)) + || player.getEquipment().get(EquipmentContainer.SLOT_WEAPON) == null + || (!player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("shortbow") + && !player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("longbow"))) { + player.sendMessage("You must have bronze arrows and a bow equipped."); + return true; + } + player.getPulseManager().run(new ArcheryCompetitionPulse(player, (Scenery) node)); + break; + case "open": + switch (id) { + case 2514: + if (player.getLocation().getY() >= 3438) { + if (player.getSkills().getStaticLevel(Skills.RANGE) < 40) { + player.getDialogueInterpreter().sendDialogue("You need a Ranging level of 40 to enter here."); + return true; + } + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node, player.getLocation().getY() >= 3438 ? Location.create(2659, 3437, 0) : Location.create(2657, 3439, 0)); + break; + } + break; + case "climb-up": + switch (id) { + case 2511: + player.setAttribute("ladder", node); + player.getInterfaceManager().open(new Component(564)); + break; + } + break; + case "climb-down": + switch (id) { + case 2512: + ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 0)); + break; + } + break; + } + return true; + } + + @Override + public Location getDestination(Node node, Node n) { + if (n instanceof Scenery) { + if (((Scenery) n).getDefinition().hasAction("open")) { + if (((Scenery) n).getId() == 2514) { + if (node.getLocation().getY() >= 3438) { + return Location.create(2657, 3439, 0); + } else { + return Location.create(2659, 3437, 0); + } + } + return DoorActionHandler.getDestination((Player) node, (Scenery) n); + } + if (((Scenery) n).getId() == 2513) + return Location.create(2673, 3420, 0); + } + return null; + } + + /** + * Represents the dialogue used for the ranging guild door man. + * + * @author 'Vexia + * @version 1.0 + */ + public class RangingGuildDoorman extends DialoguePlugin { + + /** + * Constructs a new {@code RangingGuildDoorman} {@code Object}. + */ + public RangingGuildDoorman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code RangingGuildDoorman} {@code Object}. + * + * @param player the player. + */ + public RangingGuildDoorman(Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new RangingGuildDoorman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello there."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Greetings. If you are an experienced archer, you may", "want to visit the guild here..."); + stage = 1; + break; + case 1: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{679}; + } + } + + /** + * Represents the tribal weapon salseman dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class TribalWeaponSalesman extends DialoguePlugin { + + /** + * Constructs a new {@code TribalWeaponSalesman} {@code Object}. + */ + public TribalWeaponSalesman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code TribalWeaponSalesman} {@code Object}. + * + * @param player the player. + */ + public TribalWeaponSalesman(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new TribalWeaponSalesman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + player("Hello there."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("Greetings, traveller. Are you interested in any throwing", "weapons?"); + stage = 1; + break; + case 1: + options("Yes I am.", "Not really."); + stage = 2; + break; + case 2: + switch (buttonId) { + case 1: + player("Yes I am."); + stage = 10; + break; + case 2: + player("Not really."); + stage = 20; + break; + } + break; + case 10: + npc("That is a good thing."); + stage = 11; + break; + case 11: + end(); + npc.openShop(player); + break; + case 20: + npc("No bother to me."); + stage = 21; + break; + case 21: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{692}; + } + + } + + /** + * Represents the guard dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class GuardDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code GuardDialogue} {@code Object}. + */ + public GuardDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code GuardDialogue} {@code Object}. + * + * @param player the player. + */ + public GuardDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new GuardDialogue(player); + } + + @Override + public boolean open(Object... args) { + player("Hello there."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("Greetings, traveller. Enjoy the time at the Ranging", "Guild."); + stage = 1; + break; + case 1: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{678}; + } + + } + + /** + * Represents the leather workers dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class LeatherWorkerDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. + */ + public LeatherWorkerDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. + * + * @param player the player. + */ + public LeatherWorkerDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new LeatherWorkerDialogue(player); + } + + @Override + public boolean open(Object... args) { + player("Hello."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("Can I help you?"); + stage = 1; + break; + case 1: + options("What do you do here?", "No thanks."); + stage = 2; + break; + case 2: + switch (buttonId) { + case 1: + player("What do you do here?"); + stage = 10; + break; + case 2: + player("No thanks."); + stage = 20; + break; + } + break; + case 10: + npc("Well, I can cure plain cowhides into pieces of leather", "ready for crafting."); + stage = 11; + break; + case 11: + npc("I work with ordinary, hard or dragonhide leather and", "also snakeskin."); + stage = 12; + break; + case 12: + end(); + TanningProduct.open(player, 680); + break; + case 20: + npc("Suit yourself."); + stage = 21; + break; + case 21: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{680}; + } + + } + + /** + * Represents the armour salesman dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class ArmourSalesman extends DialoguePlugin { + + /** + * Constructs a new {@code ArmourSalesman} {@code Object}. + */ + public ArmourSalesman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code ArmourSalesman} {@code Object}. + * + * @param player the player. + */ + public ArmourSalesman(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new ArmourSalesman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + player("Good day to you."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("And to you. Can I help you?"); + stage = 1; + break; + case 1: + if (Skillcape.isMaster(player, Skills.RANGE)) { + options("What do you do here?", "I'd like to see what you sell.", "Can I buy a Skillcape of Range?", "I've seen enough, thanks."); + stage = 100; + } else { + options("What do you do here?", "I'd like to see what you sell.", "I've seen enough, thanks."); + stage = 2; + } + break; + case 2: + switch (buttonId) { + case 1: + player("What do you do here?"); + stage = 10; + break; + case 2: + player("I'd like to see what you sell."); + stage = 20; + break; + case 3: + player("I've seen enough, thanks."); + stage = 30; + break; + } + break; + case 10: + npc("I am a supplier of leather armours and accessories. Ask", "and I will tell you what I know."); + stage = 11; + break; + case 11: + options("Tell me about your armours.", "Tell me about your accessories.", "I've seen enough, thanks."); + stage = 12; + break; + case 12: + switch (buttonId) { + case 1: + player("Tell me about your armours."); + stage = 13; + break; + case 2: + player("Tell me about your accessories."); + stage = 15; + break; + case 3: + player("I've seen enough, thanks."); + stage = 30; + break; + } + break; + case 13: + npc("I have normal, studded and hard types."); + stage = 14; + break; + case 14: + case 31: + case 105: + end(); + break; + case 15: + npc("Ah yes we have a new range of accessories in stock.", "Essential items for an archer like you."); + stage = 14; + break; + case 20: + npc("Indeed, cast your eyes on my wares, adventurer."); + stage = 21; + break; + case 21: + end(); + npc.openShop(player); + break; + case 30: + npc("Very good, adventurer."); + stage = 31; + break; + case 100: + switch (buttonId) { + case 1: + player("What do you do here?"); + stage = 10; + break; + case 2: + player("I'd like to see what you sell."); + stage = 20; + break; + case 3: + player("Can I buy a Skillcape of Range?"); + stage = 101; + break; + case 4: + player("I've seen enough, thanks."); + stage = 30; + break; + } + break; + case 101: + npc("Certainly! Right when you give me 99000 coins."); + stage = 102; + break; + case 102: + options("Okay, here you go.", "No, thanks."); + stage = 103; + break; + case 103: + switch (buttonId) { + case 1: + player("Okay, here you go."); + stage = 104; + break; + case 2: + end(); + break; + } + break; + case 104: + if (Skillcape.purchase(player, Skills.RANGE)) { + npc("There you go! Enjoy."); + } + stage = 105; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{682}; + } + + } + + /** + * Represents the dialogue plugin used for the bow and arrow salesman. + * + * @author 'Vexia + * @version 1.0 + */ + public final class BowArrowSalesman extends DialoguePlugin { + + /** + * Constructs a new {@code BowArrowSalesman} {@code Object}. + */ + public BowArrowSalesman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code BowArrowSalesman} {@code Object}. + * + * @param player the player. + */ + public BowArrowSalesman(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new BowArrowSalesman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + player("Hello."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("A fair day, traveller. Would you like to see my wares?"); + stage = 1; + break; + case 1: + options("Yes please.", "No thanks."); + stage = 2; + break; + case 2: + switch (buttonId) { + case 1: + end(); + npc.openShop(player); + + break; + case 2: + end(); + break; + } + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{683}; + } + + } + + /** + * Represents the waring interface used in the guild. + * + * @author 'Vexia + * @version 1.0 + */ + public final class WarningInterface extends ComponentPlugin { + + @Override + public Plugin newInstance(Object arg) throws Throwable { + ComponentDefinition.forId(564).setPlugin(this); + return this; + } + + @Override + public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) { + switch (button) { + case 17: + ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 2)); + player.getInterfaceManager().close(); + List npcs = RegionManager.getLocalNPCs(Location.create(2668, 3427, 2)); + String dir = ""; + for (NPC n : npcs) { + if (n.getId() >= 684 && n.getId() <= 687) { + switch (n.getId()) { + case 684: + dir = "north"; + break; + case 685: + dir = "east"; + break; + case 686: + dir = "south"; + break; + case 687: + dir = "west"; + break; + } + n.sendChat("The " + dir + " tower is occupied, get them!"); + } + } + break; + case 18: + player.getInterfaceManager().close(); + break; + } + return true; + } + + } + + /** + * Represents the competition judge. + * + * @author afaroutdude + */ + public final class CompetitionJudge extends DialoguePlugin { + + /** + * Constructs a new {@code CompetitionJudge} {@code Object}. + * + * @param player the player. + */ + public CompetitionJudge(final Player player) { + super(player); + } + + /** + * Constructs a new {@code CompetitionJudge} {@code Object}. + */ + public CompetitionJudge() { + /** + * empty. + */ + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new CompetitionJudge(player); + } + + @Override + public boolean open(Object... args) { + if (player.getInventory().getAmount(1464) >= 1000 + && !player.getAchievementDiaryManager().hasCompletedTask(DiaryType.SEERS_VILLAGE, 1, 7)) { + npc("Wow! I see that you've got yourself a whole load of ", "archery tickets. Well done!"); + player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 7); + stage = -1; + } else if (player.getArcheryTargets() > 0) { + npc("Hello again, do you need reminding of the rules?"); + stage = 20; + } else if (player.getArcheryTotal() == 0) { + npc("Hello there, would you like to take part in the", + "archery competition? It only costs 200 coins to", + "enter."); + stage = 0; + } else { + int reward = player.getArcheryTotal() / 10; + npc("Well done. Your score is: " + player.getArcheryTotal() + ".", + "For that score you will receive " + reward + " Archery tickets."); + player.setArcheryTargets(-1); + player.setArcheryTotal(0); + if (!player.getInventory().add(new Item(1464, reward))) { + player.getBank().add(new Item(1464, reward)); + player.sendMessage("Your reward was sent to your bank."); + } + stage = 999; + } + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 999: + end(); + break; + case -1: + if (player.getArcheryTargets() > 0) { + npc("Hello again, do you need reminding of the rules?"); + stage = 20; + } else if (player.getArcheryTotal() == 0) { + npc("Hello there, would you like to take part in the", + "archery competition? It only costs 200 coins to", + "enter."); + stage = 0; + } else { + int reward = player.getArcheryTotal() / 10; + npc("Well done. Your score is: " + player.getArcheryTotal() + ".", + "For that score you will receive " + reward + " Archery tickets."); + if (!player.getInventory().add(new Item(1464, reward))) { + player.getBank().add(new Item(1464, reward)); + player.sendMessage("Your reward was sent to your bank."); + } + stage = 999; + } + break; + case 0: + options("Sure, I'll give it a go.", "What are the rules?", "No thanks."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + player("Sure, I'll give it a go."); + stage = 2; + break; + case 2: + player("What are the rules?"); + stage = 5; + break; + case 3: + player("No thanks."); + stage = 999; + break; + } + break; + case 2: + npc("Great! That will be 200 coins then please."); + stage++; + break; + case 3: + if (player.getInventory().getAmount(995) < 200) { + player("Oops, I don't have enough coins on me..."); + stage++; + } else { + end(); + player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); + player.getInventory().remove(new Item(995, 200)); + player.getInventory().add(new Item(882, 10)); + player.setArcheryTargets(10); + player.setArcheryTotal(0); + } + break; + case 4: + npc("Never mind, come back when you've got enough."); + stage = 999; + break; + case 5: + case 22: + npc("The rules are very simple:"); + stage++; + break; + case 6: + case 23: + npc("You're given 10 shots at the targets, for each hit", "you will receive points. At the end you'll be", "rewarded 1 ticket for every 10 points."); + stage++; + break; + case 7: + npc("The tickets can be exchanged for goods from our stores.", "Do you want to give it a go? Only 200 coins."); + stage++; + break; + case 8: + options("Sure, I'll give it a go.", "No thanks."); + stage++; + break; + case 9: + switch (buttonId) { + case 1: + player("Sure, I'll give it a go."); + stage = 2; + break; + case 3: + player("No thanks."); + stage = 999; + break; + } + break; + case 20: + int arrows = player.getInventory().getAmount(Items.BRONZE_ARROW_882) + + player.getEquipment().getAmount(Items.BRONZE_ARROW_882); + if (arrows < 1) { + player("Well, I actually don't have any more arrows. Could I", "get some more?"); + stage = 25; + } else { + options("Yes please.", "No thanks, I've got it.", "How am I doing so far?"); + stage++; + } + break; + case 21: + switch (buttonId) { + case 1: + player("Yes please."); + stage++; + break; + case 2: + player("No thanks, I've got it."); + stage = 30; + break; + case 3: + player("How am I doing so far?"); + stage = 40; + break; + } + break; + case 24: + npc("The tickets can be exchanged for goods from our stores.", "Good Luck!"); + stage = 999; + break; + case 25: + npc("Ok, but it'll cost you 100 coins."); + stage++; + break; + case 26: + options("Sure, I'll take some.", "No thanks."); + stage++; + break; + case 27: + switch (buttonId) { + case 1: + player("Sure, I'll take some."); + stage++; + break; + case 2: + player("No thanks."); + stage = 999; + break; + } + break; + case 28: + if (player.getInventory().getAmount(995) < 100) { + player("Oops, I don't have enough coins on me..."); + stage++; + } else { + end(); + player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); + player.getInventory().remove(new Item(995, 100)); + player.getInventory().add(new Item(882, 10)); + } + break; + case 30: + npc("Glad to hear it, good luck!"); + stage = 999; + break; + case 40: + String msg; + if (player.getArcheryTotal() <= 0) { + msg = "You haven't started yet."; + } else if (player.getArcheryTotal() <= 80) { + msg = "Not bad, keep going."; + } else { + msg = "You're pretty good, keep it up."; + } + npc("So far your score is: " + player.getArcheryTotal(), msg); + stage = 999; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{693}; + } + + } + + /** + * Represents the tower advisors. + * + * @author afaroutdude + */ + public final class TowerAdvisor extends DialoguePlugin { + + /** + * Constructs a new {@code TowerAdvisor} {@code Object}. + * + * @param player the player. + */ + public TowerAdvisor(final Player player) { + super(player); + } + + /** + * Constructs a new {@code TowerAdvisor} {@code Object}. + */ + public TowerAdvisor() { + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new TowerAdvisor(player); + } + + @Override + public boolean open(Object... args) { + player("Hello there, what do you do here?"); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 999: + end(); + case 0: + npc("Hi. We are in charge of this practice area."); + stage++; + break; + case 1: + player("This is a practice area?"); + break; + case 2: + npc("Surrounding us are four towers. Each tower contains", + "trained archers of a different level. You'll notice", + "it's quite a distance, so you'll need a longbow."); + stage++; + break; + case 3: + int rangeLevel = player.getSkills().getLevel(Skills.RANGE); + if (rangeLevel < 50) { // north + npc("As you're not very skilled, I advise you to practice", + "on the north tower. That'll provide the best", + "challenge for you."); + } else if (rangeLevel < 60) { // east + npc("You appear to be somewhat skilled with a bow, so I", + "advise you to practice on the south tower. That'll", + "provide the best challenge for you."); + } else if (rangeLevel < 70) { // south + npc("You appear to be fairly skilled with a bow, so I", + "advise you to practice on the south tower. That'll", + "provide the best challenge for you."); + } else { // west + npc("Looks like you're very skilled, so I advise you to", + "practice on the west tower. That'll provide the best", + "challenge for you."); + } + stage = 999; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{684, 685, 686, 687}; + } + + } + + + /** + * Represents all the tower archers + * + * @author afaroutdude + */ + public final class TowerArcher extends AbstractNPC { + + public TowerArcher() { + super(-1, null); + } + public TowerArcher(int id, Location location) { + super(id, location); + } + + + @Override + public AbstractNPC construct(int id, Location location, Object... objects) { + return new TowerArcher(id, location); + } + + @Override + public int[] getIds() { + return new int[]{688, 689, 690, 691}; + } + } + + /** + * Represents the archery target pulse. + * + * @author Jamix77 + */ + public static final class ArcheryCompetitionPulse extends Pulse { + + /** + * Represents the player instance. + */ + private final Player player; + + /** + * Represents the scenery. + */ + private final Scenery object; + + /** + * Constructs a new {@code ArcheryCompetitionPulse} {@code Object}. + * + * @param player the player. + * @param object the object. + */ + public ArcheryCompetitionPulse(final Player player, final Scenery object) { + super(1, player, object); + this.player = player; + this.object = object; + } + + private void showInterface(int points, int arrowsLeft, int target, String msg) { + player.getInterfaceManager().openComponent(325); + setVarp(player, 156, 11 - arrowsLeft); + setVarp(player, 157, points); + setVarp(player, 158, target); + player.getPacketDispatch().sendString(msg, 325, 32); + } + + @Override + public boolean pulse() { + if (player.getArcheryTargets() <= 0) { + return true; + } + if (getDelay() == 1) { + setDelay(player.getProperties().getAttackSpeed()); + } + if (player.getEquipment().remove(new Item(Items.BRONZE_ARROW_882, 1))) { + Projectile p = Ammunition.get(Items.BRONZE_ARROW_882).getProjectile().transform(player, object.getLocation()); + p.setEndLocation(object.getLocation()); + p.setEndHeight(25); + p.send(); + player.animate(new Animation(426)); + player.lock(getDelay()); + + int level = player.getSkills().getLevel(Skills.RANGE); + int bonus = player.getProperties().getBonuses()[14]; + double prayer = 1.0; + prayer += player.getPrayer().getSkillBonus(Skills.RANGE); + double cumulativeStr = Math.floor(level * prayer); + /*if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_RANGE_ACCURATE) { + cumulativeStr += 3; + } else if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_LONG_RANGE) { + cumulativeStr += 1; + }*/ + cumulativeStr *= 1.0; + int hit = (int) ((14 + cumulativeStr + (bonus / 8) + ((cumulativeStr * bonus) * 0.016865))) / 10 + 1; + hit = hit + RandomFunction.randomSign(RandomFunction.random(3)); + + int target = Math.max(0, 13 - hit); + int points = 0; + String msg = ""; + switch (target) { + case 0: + points = 100; + msg = "Bulls-Eye!"; + break; + case 1: + points = 50; + msg = "Hit Yellow!"; + break; + case 2: + case 3: + case 4: + points = 30; + msg = "Hit Red!"; + break; + case 5: + case 6: + case 7: + case 8: + points = 20; + msg = "Hit Blue!"; + break; + case 9: + case 10: + points = 10; + msg = "Hit Black!"; + break; + case 11: + case 12: + case 13: + points = 0; + msg = "Missed!"; + break; + } + int xp = points / 2; + + player.getSkills().addExperience(Skills.RANGE, xp, true); + player.setArcheryTotal(player.getArcheryTotal() + points); + player.setArcheryTargets(player.getArcheryTargets() - 1); + player.debug("Hit: " + hit); + player.debug("You have " + player.getArcheryTargets() + " targets left."); + player.debug("You have " + player.getArcheryTotal() + " score."); + + showInterface(player.getArcheryTotal(), player.getArcheryTargets(), target, msg); + + return true; //player.getArcheryTargets() <= 0; + } else { + return true; + } + } + + } } diff --git a/Server/src/main/content/region/karamja/diary/KaramjaAchievementDiary.kt b/Server/src/main/content/region/karamja/diary/KaramjaAchievementDiary.kt index cda31648c..927198ce5 100644 --- a/Server/src/main/content/region/karamja/diary/KaramjaAchievementDiary.kt +++ b/Server/src/main/content/region/karamja/diary/KaramjaAchievementDiary.kt @@ -83,7 +83,7 @@ class KaramjaAchievementDiary : DiaryEventHookBase(DiaryType.KARAMJA) { } override fun onResourceProduced(player: Player, event: ResourceProducedEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10802 -> if (event.itemId == Items.GOLD_ORE_444) { finishTask( player, @@ -148,7 +148,7 @@ class KaramjaAchievementDiary : DiaryEventHookBase(DiaryType.KARAMJA) { } override fun onNpcKilled(player: Player, event: NPCKillEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 10899, 10900 -> if (event.npc.id in METAL_DRAGONS) { finishTask( player, diff --git a/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java b/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java index 5070b76ef..ea8c0cd6b 100644 --- a/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java +++ b/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java @@ -8,6 +8,7 @@ import java.util.Random; import core.game.component.Component; import core.game.container.impl.EquipmentContainer; import core.game.activity.ActivityPlugin; +import core.game.world.map.RegionChunk; import core.plugin.Initializable; import core.game.dialogue.FacialExpression; import core.game.node.entity.skill.Skills; @@ -30,6 +31,7 @@ import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; import core.game.world.map.zone.ZoneRestriction; import core.tools.RandomFunction; +import org.rs09.consts.NPCs; import static core.api.ContentAPIKt.*; @@ -145,7 +147,15 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { lastVictor.getPacketDispatch().sendString("Current Champion: " + getChampionName(), INTERFACE_ID, 0); resetDamagePulse(lastVictor); } - RegionManager.forId(9552).getPlanes()[0].getNpcs().get(0).setAttribute("fp_champn", getChampionName()); + RegionChunk[][][] chunks = RegionManager.forId(9552).getChunks(); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + List npcs = chunks[x][y][0].getNpcs(); + for (NPC npc : npcs) { + npc.setAttribute("fp_champn", getChampionName()); + } + } + } } minutes = 0; } @@ -180,10 +190,15 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { * Resets the last victor. */ private void resetLastVictor() { - List npcs = new ArrayList<>(RegionManager.forId(9552).getPlanes()[0].getNpcs()); - for (NPC n : npcs) { - if (n.getId() == 2734 || n.getId() == 2739) { - n.clear(); + RegionChunk[][][] chunks = RegionManager.forId(9552).getChunks(); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + List npcs = chunks[x][y][0].getNpcs(); + for (NPC npc : npcs) { + if (npc.getId() == NPCs.TZ_KIH_2734 || npc.getId() == NPCs.TOK_XIL_2739) { + npc.clear(); + } + } } } if (lastVictor == null || !lastVictor.isActive()) { @@ -355,7 +370,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { } int size = (LOBBY_PLAYERS.size() + WAR_PLAYERS.size()) - 1; if (!WAR_PLAYERS.isEmpty()) { - setVarp(WAR_PLAYERS.get(0), 560, size); + setVarp(WAR_PLAYERS.get(0), 560, size); } for (Iterator it = LOBBY_PLAYERS.iterator(); it.hasNext();) { Player p = it.next(); @@ -367,7 +382,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { } p.getSkullManager().setSkullCheckDisabled(true); p.getSkullManager().setWilderness(true); - setVarp(p, 560, size); + setVarp(p, 560, size); p.getProperties().setTeleportLocation(getZoneDestination()); p.getInteraction().set(Option._P_ATTACK); tokkulAmount += p.getProperties().getCurrentCombatLevel(); @@ -449,7 +464,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { */ public static void sendPlayersRemaining(int value) { for (Player p : WAR_PLAYERS) { - setVarp(p, 560, value); + setVarp(p, 560, value); } } diff --git a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java index 13275ac76..4c485d7af 100644 --- a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java +++ b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java @@ -1,5 +1,6 @@ package content.region.misthalin.draynor.dialogue; +import content.region.misthalin.draynor.handlers.DBRCutscene; import core.game.activity.ActivityManager; import core.game.dialogue.DialoguePlugin; import core.game.dialogue.FacialExpression; @@ -55,7 +56,7 @@ public final class DraynorBankGuard extends DialoguePlugin { public boolean handle(int interfaceId, int buttonId) { switch (stage) { case 0: - if (!player.getSavedData().getGlobalData().isDraynorRecording()) { + if (!player.getAttribute("draynor-recording", false)) { interpreter.sendOptions("Select an option", "Can I deposit my stuff here?", "That wall doesn't look very good.", "Sorry, I don't want anything."); stage = 1; } else { @@ -325,7 +326,7 @@ public final class DraynorBankGuard extends DialoguePlugin { */ private void startRecording(Player player) { end(); - ActivityManager.start(player, "dbr cutscene", false); + new DBRCutscene(player).start(); } @Override diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.java b/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.java deleted file mode 100644 index 78c30fa3e..000000000 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.java +++ /dev/null @@ -1,896 +0,0 @@ -package content.region.misthalin.draynor.handlers; - -import core.game.component.Component; -import core.game.activity.ActivityPlugin; -import core.game.activity.CutscenePlugin; -import core.game.global.action.DoorActionHandler; -import core.plugin.Initializable; -import core.game.node.entity.skill.Skills; -import core.game.node.Node; -import core.game.node.entity.Entity; -import core.game.node.entity.combat.CombatStyle; -import core.game.node.entity.combat.ImpactHandler.HitsplatType; -import core.game.node.entity.impl.Projectile; -import core.game.node.entity.npc.AbstractNPC; -import core.game.node.entity.npc.NPC; -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.SpellBookManager; -import core.game.node.item.GroundItem; -import core.game.node.item.GroundItemManager; -import core.game.node.item.Item; -import core.game.node.item.ItemPlugin; -import core.game.node.scenery.Scenery; -import core.game.node.scenery.SceneryBuilder; -import core.game.system.task.Pulse; -import core.game.world.GameWorld; -import core.game.world.map.Direction; -import core.game.world.map.Location; -import core.game.world.map.RegionManager; -import core.game.world.map.build.DynamicRegion; -import core.game.world.map.path.Pathfinder; -import core.game.world.update.flag.context.Animation; -import core.game.world.update.flag.context.Graphics; -import core.net.packet.PacketRepository; -import core.net.packet.context.CameraContext; -import core.net.packet.context.CameraContext.CameraType; -import core.net.packet.out.CameraViewPacket; -import core.plugin.Plugin; -import core.plugin.ClassScanner; - -/** - * Represents the draynor bank robbery cutscene plugin. - * - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class DBRCutscenePlugin extends CutscenePlugin { - - /** - * Represents the cracked component. - */ - private static final Component CRACKED = new Component(385); - - /** - * Represents the stealing animation used for cool mom. - */ - private static final Animation STEAL_ANIMATION = new Animation(832); - - /** - * Represents the casting animation. - */ - private static final Animation CAST_ANIMATION = new Animation(1167); - - /** - * Represents the telekentic animation to use. - */ - private static final Animation TELEKENTIC_ANIMATION = new Animation(723); - - /** - * Represents the telekentic graphics. - */ - private static final Graphics TELEKENTIC_GRAPHIC = new Graphics(142, 96); - - /** - * Represents the casting animation. - */ - private static final Animation SECOND_CAST_ANIMATION = new Animation(1167); - - /** - * Represents the death animation to use. - */ - private static final Animation DEATH_ANIMATION = new Animation(2553); - - /** - * Represents the graphics to use. - */ - private static final Graphics SHOCK_GRAPHIC = new Graphics(432, 0, 0); - - /** - * Represents the teleport animation to use. - */ - private static final Animation TELEPORT_ANIMATION = new Animation(1816); - - /** - * Represents the graphics to use for teleother. - */ - private static final Graphics[] TELE_OTHERS = new Graphics[] { new Graphics(343), new Graphics(342) }; - - /** - * Represents the pick up animation to use. - */ - private static final Animation PICK_UP_ANIMATION = new Animation(827); - - /** - * Represents the hitting animation. - */ - private static final Animation HIT_ANIMATION = new Animation(401); - - /** - * Represents the blocking animation. - */ - private static final Animation BLOCK_ANIMATION = new Animation(425); - - /** - * Represents the thunder animation. - */ - private static final Animation THUNDER_ANIMATION = new Animation(811); - - /** - * Represents the purple graphics. - */ - private static final Graphics PURPLE_GRAPHIC = new Graphics(301, 100); - - /** - * Represents the thunder graphic. - */ - private static final Graphics THUNDER_GRAPHIC = new Graphics(76); - - /** - * Represents the animation to use for the wise old man. - */ - private static final Animation WISE_JUMP = new Animation(2555); - - /** - * Represents the market guard jump animation. - */ - private static final Animation GUARD_JUMP = new Animation(2556); - - /** - * Represents the stomp animation. - */ - private static final Animation STOMP_ANIM = new Animation(1820); - - /** - * Represents the ashes item. - */ - private static final Item ASHES = new Item(592); - - /** - * Represents the coins item. - */ - private static final Item COINS = new Item(995, 60); - - /** - * Represents the party hat item. - */ - private static final Item PARTY_HAT = new Item(2422); - - /** - * Represents the recording pulse. - */ - private final RecordingPulse recordingPulse = new RecordingPulse(); - - /** - * Represents the npcs to use in the cutscene. - */ - private static final NPC[] NPCS = new NPC[] { - /** cool mom */ - NPC.create(2579, Location.create(2120, 4916, 0), Direction.NORTH), - /** olivia */ - NPC.create(2572, Location.create(2117, 4913, 0), Direction.WEST), - /** market guard */ - NPC.create(2571, Location.create(13, 48, 0), Direction.WEST), - /** purepker */ - NPC.create(2575, new Location(2136, 4914, 0), Direction.WEST), - /** first banker */ - NPC.create(2568, new Location(2130, 4909, 0), Direction.EAST), - /** second last banker. */ - NPC.create(2569, new Location(2130, 4907, 0)), - /** last banker */ - NPC.create(2570, new Location(2130, 4906, 0)), - /** efinlocks */ - NPC.create(2578, new Location(2133, 4908, 0)), - /** 1337sp34kr */ - NPC.create(2577, new Location(2134, 4906, 0), Direction.WEST), - /** quitedoll */ - NPC.create(2576, new Location(2133, 4906, 0), Direction.EAST), - /** oldman */ - NPC.create(2566, new Location(2128, 4915, 0), Direction.SOUTH) }; - - /** - * Constructs a new {@code DBRCutscenePlugin} {@code Object}. - */ - public DBRCutscenePlugin() { - super("dbr cutscene"); - } - - /** - * Constructs a new {@code DBRCutscenePlugin} {@code Object}. - * - * @param player - * the player. - */ - public DBRCutscenePlugin(final Player player) { - super("dbr cutscene"); - this.player = player; - } - - @Override - public void open() { - setNpcs(); - GameWorld.getPulser().submit(recordingPulse); - player.lock(); - player.getLocks().lockMovement(10000000); - camera(27, 45, -14, 2, 700, 100); - } - - @Override - public ActivityPlugin newInstance(Player p) throws Throwable { - return new DBRCutscenePlugin(p); - } - - @Override - public void register() { - super.register(); - try { - new DBRecordingNPC().newInstance(null); - } catch (Throwable e) { - e.printStackTrace(); - } - ClassScanner.definePlugin(new BluePhatItem()); - } - - @Override - public Location getSpawnLocation() { - return null; - } - - @Override - public Location getStartLocation() { - return base.transform(17, 51, 0); - } - - @Override - public void configure() { - region = DynamicRegion.create(8524); - setRegionBase(); - registerRegion(region.getId()); - player.getDialogueInterpreter().sendPlainMessage(true, "You close your eyes and watch the recording..."); - } - - @Override - public void end() { - super.end(); - clearNpcs(); - player.getSavedData().getGlobalData().setDraynorRecording(true); - player.getDialogueInterpreter().sendDialogue("End of recording."); - } - - /** - * Gets the cool mom npc. - * - * @return the cool mom npc. - */ - public NPC getCoolMom() { - return getNpc(2579); - } - - /** - * Gets the olivia npc. - * - * @return the olivia npc. - */ - public NPC getOlivia() { - return getNpc(2572); - } - - /** - * Gets the market guard npc. - * - * @return the market guard. - */ - public NPC getMarketGuard() { - return getNpc(2571); - } - - /** - * Gets the pure pker npc. - * - * @return the pure pker npc. - */ - public NPC getPurePker() { - return getNpc(2575); - } - - /** - * Gets the elfinlocks npc. - * - * @return the elfinocks npc. - */ - public NPC getElfinocks() { - return getNpc(2578); - } - - /** - * Gets the 1337sp34kr npc. - * - * @return the 1337sp34kr npc. - */ - public NPC get1337() { - return getNpc(2577); - } - - /** - * Gets the quitedoll npc. - * - * @return the quitedoll npc. - */ - public NPC getQuiteDoll() { - return getNpc(2576); - } - - /** - * Gets the wise old man npc. - * - * @return the wise old man npc. - */ - public NPC getWiseOldMan() { - int size = region.getPlanes()[0].getNpcs().size(); - return region.getPlanes()[0].getNpcs().get(size - 1); - } - - /** - * Gets the first banker. - * - * @return the first banker. - */ - public NPC getFirstBanker() { - return getNpc(2568); - } - - /** - * Gets the second banker. - * - * @return the second banker. - */ - public NPC getSecondBanker() { - return getNpc(2569); - } - - /** - * Gets the last banker. - * - * @return the last banker. - */ - public NPC getLastBanker() { - return getNpc(2570); - } - - /** - * Method used to walk an npc. - * - * @param npc - * the npc. - * @param location - * the location. - */ - private void walk(NPC npc, final Location location) { - Pathfinder.find(npc, location, true, Pathfinder.DUMB).walk(npc); - } - - /** - * Method used to kill an npc. - * - * @param npc - * the npc. - */ - private void die(NPC npc) { - npc.getAnimator().reset(); - npc.animate(DEATH_ANIMATION); - npc.graphics(SHOCK_GRAPHIC); - npc.getImpactHandler().manualHit(npc, npc.getSkills().getLifepoints(), HitsplatType.NORMAL); - } - - /** - * Method used to cast a shock. - * - * @param target - * the target. - */ - private void castShock(Node target) { - getWiseOldMan().animate(CAST_ANIMATION); - getWiseOldMan().graphics(new Graphics(433)); - if (target instanceof Entity) { - Projectile.create(getWiseOldMan(), (Entity) target, 434).send(); - } else { - Projectile projectile = Projectile.create(getWiseOldMan(), null, 434, 30, 30, 41, 140, 0, 0); - projectile.setEndLocation((Location) target); - projectile.send(); - } - } - - /** - * Method used to cast the telekinetic grab spell. - */ - private void castTelekinetic() { - getWiseOldMan().animate(TELEKENTIC_ANIMATION); - getWiseOldMan().graphics(TELEKENTIC_GRAPHIC); - getWiseOldMan().getSkills().setStaticLevel(Skills.MAGIC, 99); - getWiseOldMan().getSkills().setLevel(Skills.MAGIC, 99); - SpellBookManager.SpellBook.MODERN.getSpell(19).cast(getWiseOldMan(), GroundItemManager.get(PARTY_HAT.getId(), base.transform(20, 44, 0), player)); - } - - /** - * Method used to cast the thunder shock. - */ - private void castThunderShock() { - getWiseOldMan().animate(THUNDER_ANIMATION); - getWiseOldMan().graphics(PURPLE_GRAPHIC); - } - - /** - * Method used to handle the camera. - * - * @param x - * the x offset. - * @param y - * the y offset. - * @param xRot - * the xRotation. - * @param yRot - * the yRotation. - * @Param height the height. - */ - private void camera(int x, int y, int xRot, int yRot, int height, int speed) { - Location loc = base.transform(x, y, 0); - PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.POSITION, loc.getX(), loc.getY(), height, 1, speed)); - PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.ROTATION, loc.getX() + xRot, loc.getY() + yRot, height, 1, speed)); - } - - /** - * Method used to set npcs and their locations. - */ - private void setNpcs() { - for (NPC n : NPCS) { - n = NPC.create(n.getId(), n.getLocation(), n.getDirection()); - n.setLocation(base.transform(n.getLocation().getLocalX(), n.getLocation().getLocalY(), 0)); - n.setRespawn(false); - n.init(); - if (n.getName().equals("Banker")) { - n.getSkills().setStaticLevel(Skills.HITPOINTS, 15); - n.getSkills().setLevel(Skills.HITPOINTS, 15); - } - n.setWalks(false); - } - } - - /** - * Method used to clear all the npcs. - */ - private void clearNpcs() { - GameWorld.getPulser().submit(new Pulse(5) { - @Override - public boolean pulse() { - for (NPC n : region.getPlanes()[0].getNpcs()) { - n.clear(); - } - return true; - } - - }); - } - - /** - * Gets the npc. - * - * @param id - * the id. - * @return the npc. - */ - private NPC getNpc(int id) { - for (NPC n : region.getPlanes()[0].getNpcs()) { - if (n.getId() == id) { - return n; - } - } - return null; - } - - /** - * Represents the pulse used during recording. - * - * @author 'Vexia - * @version 1.0 - */ - public final class RecordingPulse extends Pulse { - - /** - * Represents the counter. - */ - private int counter; - - /** - * Constructs a new {@code FightPulse} {@code Object}. - */ - public RecordingPulse() { - super(1, player); - } - - @Override - public boolean pulse() { - switch (counter++) { - case 1: - getCoolMom().animate(STEAL_ANIMATION); - getMarketGuard().getSkills().setStaticLevel(Skills.HITPOINTS, 99); - getMarketGuard().getSkills().setLifepoints(99); - getMarketGuard().sendChat("Hey! Get your hands off there!"); - getCoolMom().getLocks().lockMovement(1000); - getMarketGuard().getProperties().getCombatPulse().attack(getCoolMom()); - break; - case 8: - walk(getPurePker(), base.transform(20, 45, 0)); - break; - case 10: - camera(27, 43, -37, -3, 600, 5); - break; - case 12: - getQuiteDoll().sendChat("Thx"); - break; - case 14: - walk(getQuiteDoll(), base.transform(20, 42, 0)); - get1337().sendChat("Yw"); - getPurePker().faceLocation(base.getLocation().transform(19, 45, 0)); - break; - case 16: - getElfinocks().sendChat("Buying 2k nats - no noob offers"); - break; - case 20: - get1337().sendChat("I h4ve n4ts"); - break; - case 22: - getElfinocks().sendChat("You sell?"); - break; - case 25: - get1337().sendChat("Tr4de"); - get1337().faceTemporary(getElfinocks(), 5); - walk(get1337(), base.transform(21, 43, 0)); - break; - case 26: - camera(23, 49, -37, 0, 500, 3); - break; - case 28: - walk(getQuiteDoll(), base.transform(20, 49, 0)); - walk(getPurePker(), base.transform(16, 49, 0)); - break; - case 29: - walk(getOlivia(), base.transform(12, 48, 0)); - break; - case 36: - DoorActionHandler.handleAutowalkDoor(getWiseOldMan(), RegionManager.getObject(base.transform(16, 51, 0))); - break; - case 37: - getQuiteDoll().sendChat("Huh?"); - getQuiteDoll().faceTemporary(getWiseOldMan(), 2); - getWiseOldMan().sendChat("Please don't block my line of fire!"); - castShock(getPurePker()); - break; - case 38: - die(getPurePker()); - break; - case 39: - getOlivia().sendChat("Hey, what are you doing?"); - getWiseOldMan().faceTemporary(getOlivia(), 2); - GroundItemManager.create(ASHES, base.transform(16, 49, 0), player); - GroundItemManager.create(COINS, base.transform(16, 49, 0), player); - break; - case 42: - getWiseOldMan().sendChat("Olivia - Please go away!"); - getWiseOldMan().animate(SECOND_CAST_ANIMATION); - getWiseOldMan().graphics(TELE_OTHERS[0]); - break; - case 43: - getOlivia().animate(TELEPORT_ANIMATION); - getOlivia().graphics(TELE_OTHERS[1]); - getOlivia().sendChat("Eeeek!"); - GroundItemManager.destroy(GroundItemManager.get(ASHES.getId(), base.transform(16, 49, 0), player)); - break; - case 45: - getOlivia().setInvisible(true); - break; - case 48: - getWiseOldMan().sendChat("Ah, now I can get on with it..."); - getWiseOldMan().faceLocation(base.transform(16, 49, 0)); - break; - case 49: - getWiseOldMan().animate(PICK_UP_ANIMATION); - break; - case 50: - GroundItemManager.destroy(GroundItemManager.get(COINS.getId(), base.transform(16, 49, 0), player)); - break; - case 53: - castShock(base.transform(16, 46, 0)); - break; - case 55: - Scenery wall = RegionManager.getObject(base.transform(16, 46, 0)); - if(wall != null) - SceneryBuilder.replace(wall, wall.transform(9151, 0, 10)); - if(getWiseOldMan() != null) { - getWiseOldMan().getWalkingQueue().reset(); - getWiseOldMan().getWalkingQueue().addPath(base.getX() + 16, base.getY() + 46); - getWiseOldMan().getWalkingQueue().addPath(base.getX() + 17, base.getY() + 46); - } - break; - case 58: - camera(21, 38, -36, 43, 495, 99); - break; - case 59: - getWiseOldMan().sendChat("Could everyone please not move?"); - break; - case 62: - getFirstBanker().sendChat("Hey - you can't come in here!"); - walk(getFirstBanker(), base.transform(18, 46, 0)); - getFirstBanker().faceTemporary(getWiseOldMan(), 2); - getWiseOldMan().faceTemporary(getFirstBanker(), 2); - break; - case 64: - getWiseOldMan().animate(HIT_ANIMATION); - getFirstBanker().animate(BLOCK_ANIMATION); - getFirstBanker().getImpactHandler().manualHit(getWiseOldMan(), getFirstBanker().getSkills().getLifepoints(), HitsplatType.NORMAL); - getSecondBanker().sendChat("Oi!"); - getLastBanker().sendChat("Uh-oh!"); - getSecondBanker().getWalkingQueue().reset(); - getSecondBanker().getWalkingQueue().addPath(base.getX() + 17, base.getY() + 43); - getSecondBanker().getWalkingQueue().addPath(base.getX() + 16, base.getY() + 43); - getSecondBanker().getWalkingQueue().addPath(base.getX() + 16, base.getY() + 46); - break; - case 70: - walk(getLastBanker(), base.transform(18, 40, 0)); - getSecondBanker().faceTemporary(getWiseOldMan(), 2); - getSecondBanker().animate(new Animation(422)); - getWiseOldMan().animate(new Animation(403)); - getWiseOldMan().faceTemporary(getSecondBanker(), 2); - break; - case 73: - getWiseOldMan().animate(new Animation(401)); - getSecondBanker().animate(new Animation(435)); - getSecondBanker().getImpactHandler().manualHit(getWiseOldMan(), 11, HitsplatType.NORMAL); - break; - case 75: - getSecondBanker().animate(new Animation(422)); - NPC npc = getWiseOldMan(); - if (npc != null) { - getWiseOldMan().sendChat("I do wish you'd just stop it!"); - getWiseOldMan().animate(new Animation(403)); - } - break; - case 78: - getWiseOldMan().animate(new Animation(401)); - walk(getLastBanker(), base.transform(16, 40, 0)); - walk(getElfinocks(), base.transform(20, 44, 0)); - break; - case 80: - getWiseOldMan().faceLocation(base.transform(17, 43, 0)); - getLastBanker().faceTemporary(getWiseOldMan(), 1); - getSecondBanker().getImpactHandler().manualHit(getWiseOldMan(), getSecondBanker().getSkills().getLifepoints(), HitsplatType.NORMAL); - break; - case 85: - getWiseOldMan().faceLocation(base.transform(17, 43, 0)); - getElfinocks().sendChat("Hey - how'd he get in there?"); - break; - case 86: - camera(26, 40, -35, 13, 545, 32); - getLastBanker().sendChat("Help! Help!"); - get1337().sendChat("Hax!"); - get1337().faceLocation(base.transform(20, 43, 0)); - break; - case 90: - getWiseOldMan().sendChat("My sincerest regrets, dear lady..."); - break; - case 92: - getWiseOldMan().faceTemporary(getElfinocks(), 1); - castShock(getElfinocks()); - break; - case 94: - die(getElfinocks()); - break; - case 96: - GroundItemManager.create(ASHES, base.transform(20, 44, 0), player); - GroundItemManager.create(PARTY_HAT, base.transform(20, 44, 0), player); - break; - case 99: - getWiseOldMan().sendChat("And also you, sir..."); - GroundItemManager.destroy(GroundItemManager.get(ASHES.getId(), base.transform(20, 44, 0), player)); - break; - case 101: - castShock(get1337()); - walk(getQuiteDoll(), base.transform(21, 44, 0)); - break; - case 103: - getQuiteDoll().faceTemporary(getWiseOldMan(), 1); - break; - case 104: - getQuiteDoll().sendChat("How you do that?"); - die(get1337()); - break; - case 107: - GroundItemManager.create(ASHES, base.transform(21, 43, 0), player); - break; - case 109: - getWiseOldMan().sendChat("Oh dear - another one..."); - walk(getWiseOldMan(), base.transform(18, 46, 0)); - getWiseOldMan().faceTemporary(getQuiteDoll(), 1); - GroundItemManager.destroy(GroundItemManager.get(ASHES.getId(), base.transform(21, 43, 0), player)); - break; - case 110: - GroundItemManager.destroy(GroundItemManager.get(ASHES.getId(), base.transform(21, 43, 0), player)); - break; - case 111: - castShock(getQuiteDoll()); - break; - case 114: - die(getQuiteDoll()); - break; - case 115: - GroundItemManager.create(ASHES, base.transform(21, 44, 0), player); - getWiseOldMan().sendChat("Ooh - a party hat?"); - getWiseOldMan().faceLocation(base.transform(20, 44, 0)); - break; - case 116: - GroundItemManager.destroy(GroundItemManager.get(ASHES.getId(), base.transform(21, 44, 0), player)); - castTelekinetic(); - break; - case 118: - getWiseOldMan().transform(2567); - if (getOlivia().isActive()) { - getOlivia().getImpactHandler().manualHit(getMarketGuard(), getOlivia().getSkills().getLifepoints(), HitsplatType.NORMAL); - } - getMarketGuard().setInvisible(true); - break; - case 120: - getWiseOldMan().sendChat("Now, my dear..."); - walk(getWiseOldMan(), base.transform(18, 42, 0)); - break; - case 121: - getLastBanker().sendChat("Eeek!"); - break; - case 124: - getWiseOldMan().sendChat("Just give me the money, please."); - break; - case 126: - getMarketGuard().setInvisible(false); - getMarketGuard().getProperties().setTeleportLocation(base.transform(18, 46, 0)); - break; - case 127: - camera(25, 42, -20, 0, 400, 4); - getMarketGuard().sendChat("Old man, you're for da cage!"); - walk(getMarketGuard(), base.transform(18, 43, 0)); - break; - case 128: - getWiseOldMan().faceTemporary(getMarketGuard(), 1); - break; - case 129: - getWiseOldMan().sendChat("Oh, am I?"); - break; - case 131: - getWiseOldMan().sendChat("Ahh!"); - break; - case 133: - castThunderShock(); - break; - case 136: - getMarketGuard().graphics(THUNDER_GRAPHIC); - getMarketGuard().getImpactHandler().manualHit(getWiseOldMan(), 40, HitsplatType.NORMAL); - getMarketGuard().sendChat("Aaargh!"); - break; - case 138: - getWiseOldMan().sendChat("Yah!"); - getWiseOldMan().animate(WISE_JUMP); - break; - case 139: - getMarketGuard().animate(GUARD_JUMP); - break; - case 142: - getMarketGuard().clear(); - camera(24, 42, -20, 0, 400, 4); - break; - case 143: - getWiseOldMan().sendChat("And YOU can stop spying on me!"); - getWiseOldMan().faceLocation(base.transform(24, 42, 0)); - break; - case 145: - getWiseOldMan().animate(STOMP_ANIM); - Projectile projectile = Projectile.create(getWiseOldMan(), null, 434, 50, 130, 41, 140, 0, 0); - projectile.setEndLocation((Location) base.transform(24, 42, 0)); - projectile.send(); - break; - case 148: - player.getInterfaceManager().open(CRACKED); - break; - case 150: - DBRCutscenePlugin.this.stop(true); - return true; - } - return !player.isActive(); - } - - @Override - public void stop() { - super.stop(); - clearNpcs(); - } - - /** - * Gets the counter. - * - * @return the counter. - */ - public int getCounter() { - return counter; - } - } - - /** - * Represents an npc during the draynor bank recording cutscene. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class DBRecordingNPC extends AbstractNPC { - - /** - * Represents the ids to use. - */ - private static final int[] IDS = new int[] { 2579 }; - - /** - * Constructs a new {@code DBRecordingNPC} {@code Object}. - */ - public DBRecordingNPC() { - super(0, null, false); - } - - /** - * Constructs a new {@code DBRecordingNPC} {@code Object}. - * - * @param id - * the id. - * @param location - * the locastion. - */ - private DBRecordingNPC(int id, Location location) { - super(id, location); - } - - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new DBRecordingNPC(id, location); - } - - @Override - public void init() { - super.init(); - getSkills().setLevel(Skills.ATTACK, 1); - getSkills().setStaticLevel(Skills.ATTACK, 1); - getSkills().setLevel(Skills.DEFENCE, 2); - getSkills().setStaticLevel(Skills.DEFENCE, 2); - } - - @Override - public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { - return true; - } - - @Override - public int[] getIds() { - return IDS; - } - } - - public static final class BluePhatItem extends ItemPlugin { - - @Override - public Plugin newInstance(Object arg) throws Throwable { - register(PARTY_HAT.getId()); - return this; - } - - @Override - public boolean canPickUp(Player player, GroundItem item, int type) { - if (type == 1) { - player.sendMessage("Nice try ;)"); - } - return false; - } - } -} diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt b/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt new file mode 100644 index 000000000..ace7b3646 --- /dev/null +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt @@ -0,0 +1,564 @@ +package content.region.misthalin.draynor.handlers + +import core.api.* +import core.game.activity.Cutscene +import core.game.component.Component +import core.game.global.action.DoorActionHandler +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.Entity +import core.game.node.entity.combat.ImpactHandler +import core.game.node.entity.impl.Projectile +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.node.entity.player.link.SpellBookManager +import core.game.node.entity.skill.Skills +import core.game.node.item.GroundItemManager +import core.game.node.item.Item +import core.game.node.scenery.SceneryBuilder +import core.game.world.map.Direction +import core.game.world.map.Location +import core.game.world.update.flag.context.Animation +import core.game.world.update.flag.context.Graphics +import core.net.packet.PacketRepository +import core.net.packet.context.CameraContext +import core.net.packet.context.CameraContext.CameraType +import core.net.packet.out.CameraViewPacket +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +class DBRCutscene(player: Player) : Cutscene(player) { + companion object { + // Animations + private val STEAL_ANIMATION = Animation(832) + private val CAST_ANIMATION = Animation(1167) + private val TELEKINETIC_ANIMATION = Animation(723) + private val DEATH_ANIMATION = Animation(2553) + private val TELEPORT_ANIMATION = Animation(1816) + private val PICK_UP_ANIMATION = Animation(827) + private val HIT_ANIMATION = Animation(401) + private val BLOCK_ANIMATION = Animation(425) + private val THUNDER_ANIMATION = Animation(811) + private val WISE_JUMP = Animation(2555) + private val GUARD_JUMP = Animation(2556) + private val STOMP_ANIM = Animation(1820) + + // Graphics + private val TELEKINETIC_GRAPHIC = Graphics(142, 96) + private val SHOCK_GRAPHIC = Graphics(432, 0, 0) + private val TELE_OTHER_CAST = Graphics(343) + private val TELE_OTHER_TARGET = Graphics(342) + private val PURPLE_GRAPHIC = Graphics(301, 100) + private val THUNDER_GRAPHIC = Graphics(76) + + // Components + private val CRACKED = Component(385) + } + + override fun setup() { + setExit(player.location) + loadRegion(8524) + + // Add all NPCs with their initial positions + addNPC(NPCs.COOL_MOM227_2579, 8, 52, Direction.NORTH) + addNPC(NPCs.OLIVIA_2572, 5, 49, Direction.WEST) + addNPC(NPCs.MARKET_GUARD_2571, 13, 48, Direction.WEST) + addNPC(NPCs.PUREPKER895_2575, 24, 50, Direction.WEST) + addNPC(NPCs.BANKER_2568, 18, 45, Direction.EAST) + addNPC(NPCs.BANKER_2569, 18, 43, Direction.NORTH) + addNPC(NPCs.BANKER_2570, 18, 42, Direction.NORTH) + addNPC(NPCs.ELFINLOCKS_2578, 21, 44, Direction.NORTH) + addNPC(NPCs.SP34KR_1337_2577, 22, 42, Direction.WEST) + addNPC(NPCs.QUTIEDOLL_2576, 21, 42, Direction.EAST) + addNPC(NPCs.WISE_OLD_MAN_2566, 16, 51, Direction.SOUTH) + + // Set banker HP + getNPC(NPCs.BANKER_2568)?.skills?.setStaticLevel(Skills.HITPOINTS, 15) + getNPC(NPCs.BANKER_2568)?.skills?.setLevel(Skills.HITPOINTS, 15) + getNPC(NPCs.BANKER_2569)?.skills?.setStaticLevel(Skills.HITPOINTS, 15) + getNPC(NPCs.BANKER_2569)?.skills?.setLevel(Skills.HITPOINTS, 15) + getNPC(NPCs.BANKER_2570)?.skills?.setStaticLevel(Skills.HITPOINTS, 15) + getNPC(NPCs.BANKER_2570)?.skills?.setLevel(Skills.HITPOINTS, 15) + } + + private fun camera(x: Int, y: Int, xRot: Int, yRot: Int, height: Int, speed: Int) { + val loc = base.transform(x, y, 0) + PacketRepository.send( + CameraViewPacket::class.java, + CameraContext(player, CameraType.POSITION, loc.x, loc.y, height, 1, speed) + ) + PacketRepository.send( + CameraViewPacket::class.java, + CameraContext(player, CameraType.ROTATION, loc.x + xRot, loc.y + yRot, height, 1, speed) + ) + } + + private fun castShock(target: Entity) { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(CAST_ANIMATION) + wiseOldMan.graphics(Graphics(433)) + val projectile = Projectile.create(wiseOldMan, target, 434) + projectile.send() + } + + private fun castShock(loc: Location) { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(CAST_ANIMATION) + wiseOldMan.graphics(Graphics(433)) + val projectile = Projectile.create(wiseOldMan, null, 434, 30, 30, 41, 140, 0, 0) + projectile.endLocation = loc + projectile.send() + } + + private fun castTelekinetic() { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(TELEKINETIC_ANIMATION) + wiseOldMan.graphics(TELEKINETIC_GRAPHIC) + wiseOldMan.skills.setStaticLevel(Skills.MAGIC, 99) + wiseOldMan.skills.setLevel(Skills.MAGIC, 99) + SpellBookManager.SpellBook.MODERN.getSpell(19).cast(wiseOldMan, GroundItemManager.get(Item(Items.BLUE_PARTYHAT_2422).id, base.transform(20, 44, 0), player)) + } + + private fun castThunderShock() { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(THUNDER_ANIMATION) + wiseOldMan.graphics(PURPLE_GRAPHIC) + } + + private fun die(npc: NPC) { + npc.animator.reset() + npc.animate(DEATH_ANIMATION) + npc.graphics(SHOCK_GRAPHIC) + npc.impactHandler.manualHit(npc, npc.skills.lifepoints, ImpactHandler.HitsplatType.NORMAL) + } + + override fun runStage(stage: Int) { + when (stage) { + 0 -> { + player.lock() + player.locks.lockMovement(10000000) + sendDialogue(player, "You close your eyes and watch the recording...") + fadeToBlack() + timedUpdate(3) + } + 1 -> { + fadeFromBlack() + player.isInvisible = true + teleport(player, 17, 51) + camera(27, 45, -14, 2, 700, 100) + timedUpdate(3) + } + 2 -> { + val coolMom = getNPC(NPCs.COOL_MOM227_2579)!! + val marketGuard = getNPC(NPCs.MARKET_GUARD_2571)!! + coolMom.animate(STEAL_ANIMATION) + marketGuard.skills.setStaticLevel(Skills.HITPOINTS, 99) + marketGuard.skills.setLifepoints(99) + sendChat(marketGuard, "Hey! Get your hands off there!") + coolMom.locks.lockMovement(1000) + marketGuard.properties.combatPulse.attack(coolMom) + timedUpdate(7) + } + 3 -> { + move(getNPC(NPCs.PUREPKER895_2575)!!, 20, 45) + timedUpdate(2) + } + 4 -> { + camera(27, 43, -37, -3, 600, 5) + timedUpdate(2) + } + 5 -> { + sendChat(getNPC(NPCs.QUTIEDOLL_2576)!!, "Thx") + timedUpdate(2) + } + 6 -> { + move(getNPC(NPCs.QUTIEDOLL_2576)!!, 20, 42) + sendChat(getNPC(NPCs.SP34KR_1337_2577)!!, "Yw") + getNPC(NPCs.PUREPKER895_2575)!!.faceLocation(base.transform(19, 45, 0)) + timedUpdate(2) + } + 7 -> { + sendChat(getNPC(NPCs.ELFINLOCKS_2578)!!, "Buying 2k nats - no noob offers") + timedUpdate(4) + } + 8 -> { + sendChat(getNPC(NPCs.SP34KR_1337_2577)!!, "I h4ve n4ts") + timedUpdate(2) + } + 9 -> { + sendChat(getNPC(NPCs.ELFINLOCKS_2578)!!, "You sell?") + timedUpdate(3) + } + 10 -> { + sendChat(getNPC(NPCs.SP34KR_1337_2577)!!, "Tr4de") + getNPC(NPCs.SP34KR_1337_2577)!!.faceTemporary(getNPC(NPCs.ELFINLOCKS_2578)!!, 5) + move(getNPC(NPCs.SP34KR_1337_2577)!!, 21, 43) + timedUpdate(1) + } + 11 -> { + camera(23, 49, -37, 0, 500, 3) + timedUpdate(2) + } + 12 -> { + move(getNPC(NPCs.QUTIEDOLL_2576)!!, 20, 49) + move(getNPC(NPCs.PUREPKER895_2575)!!, 16, 49) + timedUpdate(1) + } + 13 -> { + move(getNPC(NPCs.OLIVIA_2572)!!, 12, 48) + timedUpdate(7) + } + 14 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + DoorActionHandler.handleAutowalkDoor(wiseOldMan, getObject(16, 51)) + timedUpdate(1) + } + 15 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + val qutieDoll = getNPC(NPCs.QUTIEDOLL_2576)!! + val purePker = getNPC(NPCs.PUREPKER895_2575)!! + sendChat(qutieDoll, "Huh?") + qutieDoll.faceTemporary(wiseOldMan, 2) + sendChat(wiseOldMan, "Please don't block my line of fire!") + castShock(purePker) + timedUpdate(1) + } + 16 -> { + die(getNPC(NPCs.PUREPKER895_2575)!!) + timedUpdate(1) + } + 17 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + val olivia = getNPC(NPCs.OLIVIA_2572)!! + sendChat(olivia, "Hey, what are you doing?") + wiseOldMan.faceTemporary(olivia, 2) + GroundItemManager.create(Item(Items.ASHES_592), base.transform(16, 49, 0), player) + GroundItemManager.create(Item(Items.COINS_995, 60), base.transform(16, 49, 0), player) + timedUpdate(3) + } + 18 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(wiseOldMan, "Olivia - please go away!") + wiseOldMan.animate(CAST_ANIMATION) + wiseOldMan.graphics(TELE_OTHER_CAST) + timedUpdate(1) + } + 19 -> { + val olivia = getNPC(NPCs.OLIVIA_2572)!! + olivia.animate(TELEPORT_ANIMATION) + olivia.graphics(TELE_OTHER_TARGET) + sendChat(olivia, "Eeeek!") + GroundItemManager.destroy(GroundItemManager.get(Item(Items.ASHES_592).id, base.transform(16, 49, 0), player)) + timedUpdate(2) + } + 20 -> { + getNPC(NPCs.OLIVIA_2572)!!.isInvisible = true + timedUpdate(3) + } + 21 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(wiseOldMan, "Ah, now I can get on with it...") + wiseOldMan.faceLocation(base.transform(16, 49, 0)) + timedUpdate(1) + } + 22 -> { + getNPC(NPCs.WISE_OLD_MAN_2566)!!.animate(PICK_UP_ANIMATION) + timedUpdate(1) + } + 23 -> { + GroundItemManager.destroy(GroundItemManager.get(Item(Items.COINS_995, 60).id, base.transform(16, 49, 0), player)) + timedUpdate(3) + } + 24 -> { + castShock(base.transform(16, 46, 0)) + timedUpdate(2) + } + 25 -> { + val wall = getObject(16, 46) + if (wall != null) { + SceneryBuilder.replace(wall, wall.transform(9151, 0, 10)) + } + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566) + if (wiseOldMan != null) { + wiseOldMan.walkingQueue.reset() + wiseOldMan.walkingQueue.addPath(base.x + 16, base.y + 46) + wiseOldMan.walkingQueue.addPath(base.x + 17, base.y + 46) + } + timedUpdate(3) + } + 26 -> { + camera(21, 38, -36, 43, 495, 99) + timedUpdate(1) + } + 27 -> { + sendChat(getNPC(NPCs.WISE_OLD_MAN_2566)!!, "Could everyone please not move?") + timedUpdate(3) + } + 28 -> { + val firstBanker = getNPC(NPCs.BANKER_2568)!! + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(firstBanker, "Hey - you can't come in here!") + move(firstBanker, 18, 46) + firstBanker.faceTemporary(wiseOldMan, 2) + wiseOldMan.faceTemporary(firstBanker, 2) + timedUpdate(2) + } + 29 -> { + val firstBanker = getNPC(NPCs.BANKER_2568)!! + val secondBanker = getNPC(NPCs.BANKER_2569)!! + val lastBanker = getNPC(NPCs.BANKER_2570)!! + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(HIT_ANIMATION) + firstBanker.animate(BLOCK_ANIMATION) + firstBanker.impactHandler.manualHit(wiseOldMan, firstBanker.skills.lifepoints, ImpactHandler.HitsplatType.NORMAL) + sendChat(secondBanker, "Oi!") + sendChat(lastBanker, "Uh-oh!") + secondBanker.walkingQueue.reset() + secondBanker.walkingQueue.addPath(base.x + 17, base.y + 43) + secondBanker.walkingQueue.addPath(base.x + 16, base.y + 43) + secondBanker.walkingQueue.addPath(base.x + 16, base.y + 46) + timedUpdate(6) + } + 30 -> { + move(getNPC(NPCs.BANKER_2570)!!, 18, 40) + val secondBanker = getNPC(NPCs.BANKER_2569)!! + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + secondBanker.faceTemporary(wiseOldMan, 2) + secondBanker.animate(Animation(422)) + wiseOldMan.animate(Animation(403)) + wiseOldMan.faceTemporary(secondBanker, 2) + timedUpdate(3) + } + 31 -> { + val secondBanker = getNPC(NPCs.BANKER_2569)!! + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(Animation(401)) + secondBanker.animate(Animation(435)) + secondBanker.impactHandler.manualHit(wiseOldMan, 11, ImpactHandler.HitsplatType.NORMAL) + timedUpdate(2) + } + 32 -> { + val secondBanker = getNPC(NPCs.BANKER_2569)!! + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + secondBanker.animate(Animation(422)) + sendChat(wiseOldMan, "I do wish you'd just stop it!") + wiseOldMan.animate(Animation(403)) + timedUpdate(3) + } + 33 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(Animation(401)) + move(getNPC(NPCs.BANKER_2570)!!, 16, 40) + move(getNPC(NPCs.ELFINLOCKS_2578)!!, 20, 44) + timedUpdate(2) + } + 34 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + val lastBanker = getNPC(NPCs.BANKER_2570)!! + val secondBanker = getNPC(NPCs.BANKER_2569)!! + wiseOldMan.faceLocation(base.transform(17, 43, 0)) + lastBanker.faceLocation(wiseOldMan.location) + secondBanker.impactHandler.manualHit(wiseOldMan, secondBanker.skills.lifepoints, ImpactHandler.HitsplatType.NORMAL) + timedUpdate(5) + } + 35 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.faceLocation(base.transform(17, 43, 0)) + sendChat(getNPC(NPCs.ELFINLOCKS_2578)!!, "Hey - how'd he get in there?") + timedUpdate(1) + } + 36 -> { + camera(26, 40, -35, 13, 545, 32) + sendChat(getNPC(NPCs.BANKER_2570)!!, "Help! Help!") + sendChat(getNPC(NPCs.SP34KR_1337_2577)!!, "Hax!") + getNPC(NPCs.SP34KR_1337_2577)!!.faceLocation(base.transform(20, 43, 0)) + timedUpdate(4) + } + 37 -> { + sendChat(getNPC(NPCs.WISE_OLD_MAN_2566)!!, "My sincerest regrets, dear lady...") + timedUpdate(2) + } + 38 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.faceTemporary(getNPC(NPCs.ELFINLOCKS_2578)!!, 1) + castShock(getNPC(NPCs.ELFINLOCKS_2578)!!) + timedUpdate(2) + } + 39 -> { + die(getNPC(NPCs.ELFINLOCKS_2578)!!) + timedUpdate(2) + } + 40 -> { + GroundItemManager.create(Item(Items.ASHES_592), base.transform(20, 44, 0), player) + GroundItemManager.create(Item(Items.BLUE_PARTYHAT_2422), base.transform(20, 44, 0), player) + timedUpdate(3) + } + 41 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(wiseOldMan, "And also you, sir...") + GroundItemManager.destroy(GroundItemManager.get(Item(Items.ASHES_592).id, base.transform(20, 44, 0), player)) + timedUpdate(2) + } + 42 -> { + castShock(getNPC(NPCs.SP34KR_1337_2577)!!) + move(getNPC(NPCs.QUTIEDOLL_2576)!!, 21, 44) + timedUpdate(2) + } + 43 -> { + getNPC(NPCs.QUTIEDOLL_2576)!!.faceTemporary(getNPC(NPCs.WISE_OLD_MAN_2566)!!, 1) + timedUpdate(1) + } + 44 -> { + sendChat(getNPC(NPCs.QUTIEDOLL_2576)!!, "How you do that?") + die(getNPC(NPCs.SP34KR_1337_2577)!!) + timedUpdate(3) + } + 45 -> { + GroundItemManager.create(Item(Items.ASHES_592), base.transform(21, 43, 0), player) + timedUpdate(2) + } + 46 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(wiseOldMan, "Oh dear - another one...") + move(wiseOldMan, 18, 46) + wiseOldMan.faceLocation(getNPC(NPCs.QUTIEDOLL_2576)!!.location) + GroundItemManager.destroy(GroundItemManager.get(Item(Items.ASHES_592).id, base.transform(21, 43, 0), player)) + timedUpdate(1) + } + 47 -> { + GroundItemManager.destroy(GroundItemManager.get(Item(Items.ASHES_592).id, base.transform(21, 43, 0), player)) + timedUpdate(1) + } + 48 -> { + castShock(getNPC(NPCs.QUTIEDOLL_2576)!!) + timedUpdate(3) + } + 49 -> { + die(getNPC(NPCs.QUTIEDOLL_2576)!!) + timedUpdate(1) + } + 50 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + GroundItemManager.create(Item(Items.ASHES_592), base.transform(21, 44, 0), player) + sendChat(wiseOldMan, "Ooh - a party hat?") + wiseOldMan.faceLocation(base.transform(20, 44, 0)) + timedUpdate(1) + } + 51 -> { + GroundItemManager.destroy(GroundItemManager.get(Item(Items.ASHES_592).id, base.transform(21, 44, 0), player)) + castTelekinetic() + timedUpdate(2) + } + 52 -> { + GroundItemManager.destroy(GroundItemManager.get(Item(Items.BLUE_PARTYHAT_2422).id, base.transform(20, 44, 0), player)) + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + val olivia = getNPC(NPCs.OLIVIA_2572)!! + val marketGuard = getNPC(NPCs.MARKET_GUARD_2571)!! + wiseOldMan.transform(NPCs.WISE_OLD_MAN_2567) + if (olivia.isActive) { + olivia.impactHandler.manualHit(marketGuard, olivia.skills.lifepoints, ImpactHandler.HitsplatType.NORMAL) + } + marketGuard.isInvisible = true + timedUpdate(2) + } + 53 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(wiseOldMan, "Now, my dear...") + move(wiseOldMan, 18, 42) + timedUpdate(1) + } + 54 -> { + sendChat(getNPC(NPCs.BANKER_2570)!!, "Eeek!") + timedUpdate(3) + } + 55 -> { + sendChat(getNPC(NPCs.WISE_OLD_MAN_2566)!!, "Just give me the money, please.") + timedUpdate(2) + } + 56 -> { + val marketGuard = getNPC(NPCs.MARKET_GUARD_2571)!! + marketGuard.isInvisible = false + marketGuard.properties.teleportLocation = base.transform(18, 46, 0) + timedUpdate(1) + } + 57 -> { + camera(25, 42, -20, 0, 400, 4) + val marketGuard = getNPC(NPCs.MARKET_GUARD_2571)!! + sendChat(marketGuard, "Old man, you're for da cage!") + move(marketGuard, 18, 43) + timedUpdate(1) + } + 58 -> { + getNPC(NPCs.WISE_OLD_MAN_2566)!!.faceTemporary(getNPC(NPCs.MARKET_GUARD_2571), 1) + timedUpdate(1) + } + 59 -> { + sendChat(getNPC(NPCs.WISE_OLD_MAN_2566)!!, "Oh, am I?") + timedUpdate(2) + } + 60 -> { + sendChat(getNPC(NPCs.WISE_OLD_MAN_2566)!!, "Ahh!") + timedUpdate(2) + } + 61 -> { + castThunderShock() + timedUpdate(3) + } + 62 -> { + val marketGuard = getNPC(NPCs.MARKET_GUARD_2571)!! + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + marketGuard.graphics(THUNDER_GRAPHIC) + marketGuard.impactHandler.manualHit(wiseOldMan, 40, ImpactHandler.HitsplatType.NORMAL) + sendChat(marketGuard, "Aaargh!") + timedUpdate(2) + } + 63 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(wiseOldMan, "Yah!") + wiseOldMan.animate(WISE_JUMP) + timedUpdate(1) + } + 64 -> { + getNPC(NPCs.MARKET_GUARD_2571)!!.animate(GUARD_JUMP) + timedUpdate(3) + } + 65 -> { + getNPC(NPCs.MARKET_GUARD_2571)!!.clear() + camera(24, 42, -20, 0, 400, 4) + timedUpdate(1) + } + 66 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + sendChat(wiseOldMan, "And YOU can stop spying on me!") + wiseOldMan.faceLocation(base.transform(24, 42, 0)) + timedUpdate(2) + } + 67 -> { + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(STOMP_ANIM) + val projectile = Projectile.create(wiseOldMan, null, 434, 50, 130, 41, 140, 0, 0) + projectile.endLocation = base.transform(24, 42, 0) + projectile.send() + timedUpdate(3) + } + 68 -> { + player.interfaceManager.openOverlay(CRACKED) + timedUpdate(2) + } + 69 -> end { + player.isInvisible = false + setAttribute(player, "/save:draynor-recording", true) + sendDialogue(player, "End of recording.") + } + } + } +} + +class DBRCutsceneListeners : InteractionListener { + override fun defineListeners() { + on(Items.BLUE_PARTYHAT_2422, IntType.GROUNDITEM, "take") { player, _ -> + sendMessage(player, "Nice try ;)") + return@on true + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt index 423e57dec..8a3227c11 100644 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt @@ -9,6 +9,7 @@ import core.game.node.entity.player.Player import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.map.path.Pathfinder +import core.game.world.repository.Repository import core.plugin.Initializable /** @@ -78,7 +79,7 @@ class DraynorManorChairNPC(id: Int = DRAYNOR_MANOR_CHAIR_NPC_ID, location: Locat * @return The Player object representing the closest player, or null if there are no players nearby. */ fun findClosestPlayer(): Player? { - val players = RegionManager.getLocalPlayers(this, FOLLOWING_DISTANCE) + val players = RegionManager.getLocalPlayers(location, FOLLOWING_DISTANCE) if (players.isEmpty()) { return null } diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorHouseZone.kt b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorHouseZone.kt index 529b497a6..89e30c54a 100644 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorHouseZone.kt +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorHouseZone.kt @@ -2,7 +2,7 @@ package content.region.misthalin.draynor.handlers import core.game.node.entity.Entity import core.game.world.map.Location -import core.game.world.map.RegionManager.getLocalNpcs +import core.game.world.map.RegionManager.getLocalNPCs import core.game.world.map.path.Pathfinder import core.game.world.map.zone.MapZone import core.game.world.map.zone.ZoneBorders @@ -24,7 +24,7 @@ class DraynorManorHouseZone : MapZone("Draynor Manor House", true), Plugin } override fun move(e: Entity, loc: Location?, destination: Location): Boolean { - for (n in getLocalNpcs(e, 5)) { + for (n in getLocalNPCs(e.location, 5)) { if (n.isInvisible() || n === e) { continue } diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java index 2bc5f6852..84c7d95f6 100644 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java @@ -9,6 +9,7 @@ import core.game.node.entity.player.Player; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; import core.tools.RandomFunction; @@ -63,8 +64,8 @@ public final class DraynorTreeNPC extends AbstractNPC { @Override public void tick() { - final List players = RegionManager.getLocalPlayers(this, 1); - if (players.size() != 0) { + final List players = RegionManager.getLocalPlayers(location, 1); + if (!players.isEmpty()) { if (attackDelay < GameWorld.getTicks()) { for (Player p : players) { faceTemporary(p, 2); diff --git a/Server/src/main/content/region/misthalin/lumbridge/diary/LumbridgeAchivementDiary.kt b/Server/src/main/content/region/misthalin/lumbridge/diary/LumbridgeAchivementDiary.kt index 965dcb157..1240d0d4f 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/diary/LumbridgeAchivementDiary.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/diary/LumbridgeAchivementDiary.kt @@ -120,7 +120,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { ) override fun onResourceProduced(player: Player, event: ResourceProducedEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12596 -> if (event.itemId == Items.CLAY_434) { finishTask( player, @@ -248,7 +248,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { } override fun onNpcKilled(player: Player, event: NPCKillEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12593, 12849 -> if (event.npc.id == NPCs.GIANT_RAT_86) { finishTask( player, @@ -280,7 +280,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { } override fun onFireLit(player: Player, event: LitFireEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12593, 12849 -> if (event.logId == Items.LOGS_1511) { finishTask( player, @@ -302,7 +302,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { } override fun onInteracted(player: Player, event: InteractionEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12337 -> if (event.target.id == Scenery.RAILING_37668 && event.option == "taunt-through" ) { @@ -364,7 +364,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { override fun onPickedUp(player: Player, event: PickUpEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12850, 12851 -> { if (event.itemId == Items.COWHIDE_1739) { if (inBorders(player, COW_PEN_AREA_1) @@ -382,7 +382,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { } override fun onInterfaceOpened(player: Player, event: InterfaceOpenEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12338 -> if (event.component.id == Components.BANK_V2_MAIN_762) { finishTask( player, @@ -412,7 +412,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { } override fun onJobAssigned(player: Player, event: JobAssignmentEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12849 -> if (event.employerNpc.id == NPCs.FISHING_TUTOR_4901) { finishTask( player, @@ -424,7 +424,7 @@ class LumbridgeAchivementDiary : DiaryEventHookBase(DiaryType.LUMBRIDGE) { } override fun onUsedWith(player: Player, event: UseWithEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12595 -> if (event.used == Items.EMPTY_POT_1931 && event.with == Scenery.FLOUR_BIN_36878) { finishTask( player, diff --git a/Server/src/main/content/region/misthalin/varrock/diary/VarrockAchivementDiary.kt b/Server/src/main/content/region/misthalin/varrock/diary/VarrockAchivementDiary.kt index f49899210..fc103a4ea 100644 --- a/Server/src/main/content/region/misthalin/varrock/diary/VarrockAchivementDiary.kt +++ b/Server/src/main/content/region/misthalin/varrock/diary/VarrockAchivementDiary.kt @@ -120,7 +120,7 @@ class VarrockAchivementDiary : DiaryEventHookBase(DiaryType.VARROCK) { ) override fun onResourceProduced(player: Player, event: ResourceProducedEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12341 -> if (event.itemId == Items.RAW_TROUT_335) { finishTask( player, @@ -172,7 +172,7 @@ class VarrockAchivementDiary : DiaryEventHookBase(DiaryType.VARROCK) { } override fun onInteracted(player: Player, event: InteractionEvent) { - when (player.viewport.region.id) { + when (player.location.regionId) { 12342 -> if (event.target.id == 26934) { finishTask( player, @@ -217,8 +217,8 @@ class VarrockAchivementDiary : DiaryEventHookBase(DiaryType.VARROCK) { override fun onButtonClicked(player: Player, event: ButtonClickEvent) { /* This gets fired even on the login screen, and we don't have a region there, so... */ - player.viewport.region?.let { - when (it.id) { + player.location.regionId.let { + when (it) { 12342 -> { if (event.iface == CanoeListener.CANOE_SHAPING_INTERFACE && event.buttonId == CanoeListener.CANOE_SHAPING_BUTTONS[CanoeListener.Companion.Canoes.WAKA.ordinal]) { diff --git a/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java b/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java index e2ce0867e..1d8530d2a 100644 --- a/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java +++ b/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java @@ -12,6 +12,7 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.path.Pathfinder; import core.game.world.map.zone.impl.BankZone; +import core.game.world.repository.Repository; import core.plugin.Initializable; import core.tools.RandomFunction; @@ -69,9 +70,9 @@ public class StrayDogNPC extends AbstractNPC { if (delay < System.currentTimeMillis() && RandomFunction.random(1, 16) == 2) { getPulseManager().clear(); target = null; - players = RegionManager.getLocalPlayers(this, 7); + players = RegionManager.getLocalPlayers(location, 7); if (players.size() != 0) { - target = players.get(RandomFunction.random(players.size())); + Player target = players.get(RandomFunction.random(players.size())); getPulseManager().run(getFollowPulse(target), PulseType.STANDARD); delay = System.currentTimeMillis() + 150000; } diff --git a/Server/src/main/content/region/misthalin/varrock/quest/dragonslayer/DragonSlayerPlugin.java b/Server/src/main/content/region/misthalin/varrock/quest/dragonslayer/DragonSlayerPlugin.java index f16658df0..3d901c408 100644 --- a/Server/src/main/content/region/misthalin/varrock/quest/dragonslayer/DragonSlayerPlugin.java +++ b/Server/src/main/content/region/misthalin/varrock/quest/dragonslayer/DragonSlayerPlugin.java @@ -36,10 +36,10 @@ import content.data.Quests; */ public final class DragonSlayerPlugin extends OptionHandler { - /** - * Represents the hammer animation. - */ - private static final Animation HAMMER_ANIM = new Animation(3676); + /** + * Represents the hammer animation. + */ + private static final Animation HAMMER_ANIM = new Animation(3676); @Override public Plugin newInstance(Object arg) throws Throwable { @@ -150,7 +150,7 @@ public final class DragonSlayerPlugin extends OptionHandler { ForceMovement movement = new ForceMovement(player, player.getLocation(), player.getLocation().transform(player.getLocation().getX() == 2845 ? 2 : -2, 0, 0), new Animation(839)); movement.run(player, 10); if (player.getLocation().getX() <= 2845) { - List npcs = RegionManager.getLocalNpcs(player); + List npcs = RegionManager.getLocalNPCs(player.getLocation()); for (NPC n : npcs) { if (n.getId() == 742) { n.getProperties().getCombatPulse().attack(player); @@ -165,18 +165,18 @@ public final class DragonSlayerPlugin extends OptionHandler { player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 2); break; case 2606: - if (player.getLocation().getY() < 9600 && !player.getSavedData().getQuestData().getDragonSlayerAttribute("memorized") && player.getQuestRepository().getQuest(Quests.DRAGON_SLAYER).getStage(player) != 100) { - player.getPacketDispatch().sendMessage("The door is securely locked."); - } else { - if (!player.getSavedData().getQuestData().getDragonSlayerAttribute("memorized")) { - player.getPacketDispatch().sendMessage("You found a secret door."); - player.getPacketDispatch().sendMessage("You remember where the secret door is for future reference."); - } - player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 1); - player.getSavedData().getQuestData().setDragonSlayerAttribute("memorized", true); - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - } - break; + if (player.getLocation().getY() < 9600 && !player.getSavedData().getQuestData().getDragonSlayerAttribute("memorized") && player.getQuestRepository().getQuest(Quests.DRAGON_SLAYER).getStage(player) != 100) { + player.getPacketDispatch().sendMessage("The door is securely locked."); + } else { + if (!player.getSavedData().getQuestData().getDragonSlayerAttribute("memorized")) { + player.getPacketDispatch().sendMessage("You found a secret door."); + player.getPacketDispatch().sendMessage("You remember where the secret door is for future reference."); + } + player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 1); + player.getSavedData().getQuestData().setDragonSlayerAttribute("memorized", true); + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + } + break; case 25154: ClimbActionHandler.climb(player, new Animation(828), new Location(2833, 9658, 0)); break; @@ -206,7 +206,7 @@ public final class DragonSlayerPlugin extends OptionHandler { player.getDialogueInterpreter().sendDialogue("You nail a plank over the hole, but you still need more planks to", "close the hole completely."); } else { player.getSavedData().getQuestData().setDragonSlayerAttribute("repaired", true); - setVarp(player, 177, 1967876); + setVarp(player, 177, 1967876); player.getDialogueInterpreter().sendDialogue("You nail a final plank over the hole. You have successfully patched", "the hole in the ship."); } } diff --git a/Server/src/main/content/region/misthalin/varrock/quest/familycrest/ChronozonCaveZone.kt b/Server/src/main/content/region/misthalin/varrock/quest/familycrest/ChronozonCaveZone.kt index 1ca3002f0..8abc190ea 100644 --- a/Server/src/main/content/region/misthalin/varrock/quest/familycrest/ChronozonCaveZone.kt +++ b/Server/src/main/content/region/misthalin/varrock/quest/familycrest/ChronozonCaveZone.kt @@ -40,7 +40,7 @@ class ChronozonCaveZone: MapZone("FC ChronozoneZone", true), Plugin { ){ // Chronozon is allowed to spawn (quest stage right and the player doesn't have the crest part) // Now check there is not one already - if(!RegionManager.getLocalNpcs(spawnLoc, 5).contains(chronozon)){ + if(!RegionManager.getLocalNPCs(spawnLoc, 5).contains(chronozon)){ chronozon.setPlayer(e) chronozon.isRespawn = false chronozon.location = spawnLoc diff --git a/Server/src/main/content/region/misthalin/varrock/quest/shieldofarrav/ShieldArravPlugin.java b/Server/src/main/content/region/misthalin/varrock/quest/shieldofarrav/ShieldArravPlugin.java index 80a581a22..7c26a2368 100644 --- a/Server/src/main/content/region/misthalin/varrock/quest/shieldofarrav/ShieldArravPlugin.java +++ b/Server/src/main/content/region/misthalin/varrock/quest/shieldofarrav/ShieldArravPlugin.java @@ -106,7 +106,7 @@ public final class ShieldArravPlugin extends OptionHandler { } break; case 767: - List npcs = RegionManager.getLocalNpcs(player); + List npcs = RegionManager.getLocalNPCs(player.getLocation()); NPC master = null; for (NPC n : npcs) { if (n.getId() == 643) { diff --git a/Server/src/main/content/region/misthalin/wiztower/handlers/rcguild/RuneCraftingGuildObjects.java b/Server/src/main/content/region/misthalin/wiztower/handlers/rcguild/RuneCraftingGuildObjects.java deleted file mode 100644 index 600525b1a..000000000 --- a/Server/src/main/content/region/misthalin/wiztower/handlers/rcguild/RuneCraftingGuildObjects.java +++ /dev/null @@ -1,44 +0,0 @@ -package content.region.misthalin.wiztower.handlers.rcguild; - -import core.cache.def.impl.SceneryDefinition; -import core.game.interaction.OptionHandler; -import core.game.node.Node; -import core.game.node.entity.player.Player; -import core.game.node.scenery.Scenery; -import core.game.world.map.Location; -import core.plugin.Initializable; -import core.plugin.Plugin; - -/** - * Created for 2009Scape - * User: Ethan Kyle Millard - * Date: March 25, 2020 - * Time: 7:19 PM - */ -@Initializable -public class RuneCraftingGuildObjects extends OptionHandler { - - - @Override - public boolean handle(Player player, Node node, String option) { - Scenery object = ((Scenery) node); - - switch(object.getId()) { - case 38279: - if (player.getViewport().getRegion().getRegionId() == 12337) { - player.teleport(Location.create(1696, 5460, 2)); - } else { - player.teleport(Location.create(3106, 3160, 1)); - } - break; - } - - return true; - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - SceneryDefinition.forId(38279).getHandlers().put("option:enter", this); - return this; - } -} diff --git a/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt b/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt index cb80df540..bd94c1de3 100644 --- a/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt +++ b/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.launch import org.rs09.consts.Items import org.rs09.consts.NPCs import content.region.morytania.quest.naturespirit.NSUtils +import core.game.world.repository.Repository import org.rs09.consts.Sounds @Initializable @@ -36,7 +37,9 @@ class MortMyreGhastNPC : AbstractNPC { override fun handleTickActions() { super.handleTickActions() if(id == ids[0] && RandomFunction.roll(35)){ - val players = RegionManager.getLocalPlayers(this, 5).filter { !it.inCombat() } + val players = RegionManager.getLocalPlayers(location, 5).filter { + return@filter it.inCombat() + } if(players.isNotEmpty()){ val player = players.random() submitIndividualPulse(this, object : MovementPulse(this, player){ diff --git a/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java b/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java index 0b71e76e6..8330ce597 100644 --- a/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java @@ -15,6 +15,7 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; @@ -126,7 +127,7 @@ public final class CorporealBeastNPC extends NPCBehavior { public int swing(Entity entity, Entity victim, BattleState state) { // If we're below the right HP threshold, roll a chance to spawn the dark core CorporealBeastNPC corp = (CorporealBeastNPC) ((NPC) entity).behavior; - double thresh = entity.getSkills().getMaximumLifepoints() * (0.3 + (entity.getViewport().getCurrentPlane().getPlayers().size() * 0.05)); + double thresh = entity.getSkills().getMaximumLifepoints() * (0.3 + (RegionManager.getLocalPlayers(entity.getLocation()).size() * 0.05)); if (corp.forceCoreRoll || entity.getSkills().getLifepoints() < thresh) { rollDarkCore(entity, corp, victim); corp.forceCoreRoll = false; @@ -189,7 +190,7 @@ public final class CorporealBeastNPC extends NPCBehavior { int ticks = 1 + (int) Math.ceil(entity.getLocation().getDistance(location) * 0.5); GameWorld.getPulser().submit(new Pulse(ticks) { boolean secondStage = false; - List players = RegionManager.getLocalPlayers(entity); + List players = RegionManager.getLocalPlayers(entity.getLocation()); Location[] locations = null; @Override @@ -245,7 +246,7 @@ public final class CorporealBeastNPC extends NPCBehavior { public boolean doStompAttack(Entity entity) { Location l = entity.getLocation(); List stompTargets = null; - for (Player player : RegionManager.getLocalPlayers(entity, 5)) { + for (Player player : RegionManager.getLocalPlayers(entity.getLocation(), 5)) { Location p = player.getLocation(); if (p.getX() >= l.getX() && p.getY() >= l.getY() && p.getX() < l.getX() + entity.size() && p.getY() < l.getY() + entity.size()) { if (stompTargets == null) { diff --git a/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java b/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java index 0695955ba..c0768ea8d 100644 --- a/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java @@ -9,8 +9,10 @@ import core.game.node.entity.player.Player; import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; +import core.game.world.map.RegionManager; import core.game.world.map.path.Path; import core.game.world.map.path.Pathfinder; +import core.game.world.repository.Repository; import core.plugin.Initializable; import core.tools.RandomFunction; @@ -82,7 +84,7 @@ public final class DarkEnergyCoreNPC extends AbstractNPC { } if (ticks % 2 == 0) { boolean jump = true; - for (Player p : getViewport().getCurrentPlane().getPlayers()) { + for (Player p : RegionManager.getLocalPlayers(location)) { if (p.getLocation().withinDistance(getLocation(), 1)) { jump = false; int hit = 5 + RandomFunction.random(6); @@ -93,7 +95,7 @@ public final class DarkEnergyCoreNPC extends AbstractNPC { } if (jump) { Entity victim = master.getProperties().getCombatPulse().getVictim(); - if (++fails >= 3 && victim != null && victim.getViewport().getCurrentPlane() == getViewport().getCurrentPlane()) { + if (++fails >= 3 && victim != null && getLocation().withinDistance(victim.getLocation(), 8)) { Path path = Pathfinder.find(getLocation(), victim.getLocation(), 1); if (path.isSuccessful() || !path.isMoveNear()) { jump(victim.getLocation()); diff --git a/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java b/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java index 267a5b8cb..6e70c538d 100644 --- a/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java +++ b/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java @@ -47,12 +47,12 @@ public final class WildernessObeliskPlugin extends OptionHandler { if (stationObelisk == null) { return false; } - if (player.getSkullManager().isDeepWilderness()) { - if (player.getProperties().getCombatPulse().isInCombat()) { - player.sendMessage("You can't use this while in combat."); - return false; - } - } + if (player.getSkullManager().isDeepWilderness()) { + if (player.getProperties().getCombatPulse().isInCombat()) { + player.sendMessage("You can't use this while in combat."); + return false; + } + } for (int i = 0; i < 4; i++) { int x = stationObelisk.getLocation().getX(); int y = stationObelisk.getLocation().getY(); @@ -106,7 +106,7 @@ public final class WildernessObeliskPlugin extends OptionHandler { int index = RandomFunction.random(0, newObelisks.length - 1); //cutting out the last one that is now duplicated Obelisk newObelisk = newObelisks[index]; // Teleport players standing within a 3-by-3 bounding box - for (Player player : RegionManager.getLocalPlayersBoundingBox(center, 1, 1)) { + for (Player player : RegionManager.getLocalPlayersBoundingBox(center, 0)) { if (player.timers.getTimer("teleblock") == null) { player.getPacketDispatch().sendMessage("Ancient magic teleports you somewhere in the wilderness."); int xOffset = player.getLocation().getX() - center.getX(); diff --git a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java index 6e0d0e6fb..ef7fdf722 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java @@ -13,6 +13,7 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; import core.game.world.map.zone.impl.WildernessZone; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; import core.tools.RandomFunction; @@ -117,7 +118,7 @@ public class RevenantNPC extends AbstractNPC { public void tick() { skills.pulse(); getWalkingQueue().update(); - if (this.getViewport().getRegion().isActive()) { + if (this.getLocation().getRegion().isActive()) { getUpdateMasks().prepare(this); } if (!DeathTask.isDead(this)) { @@ -128,7 +129,7 @@ public class RevenantNPC extends AbstractNPC { lock(3); getProperties().getCombatPulse().delayNextAttack(3); getSkills().heal(maxhp / 6); - for (Player p : RegionManager.getLocalPlayers(this)) { + for (Player p : RegionManager.getLocalPlayers(location)) { playAudio(p, Sounds.EAT_2393); } setAttribute("eat-delay", GameWorld.getTicks() + 6); diff --git a/Server/src/main/core/ServerConstants.kt b/Server/src/main/core/ServerConstants.kt index 8c5f493a4..178604188 100644 --- a/Server/src/main/core/ServerConstants.kt +++ b/Server/src/main/core/ServerConstants.kt @@ -108,7 +108,7 @@ class ServerConstants { //the location where new players are placed on login. @JvmField - var START_LOCATION: Location? = null + var START_LOCATION: Location = Location(2524, 5002, 0) //Location for all home teleports/respawn location @JvmField diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 7423518a7..6e905d67a 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -652,7 +652,7 @@ fun addScenery (scenery: Scenery) { * Remove a scenery from the world * @param scenery the Scenery object to remove. */ -fun removeScenery (scenery: Scenery) { +fun removeScenery(scenery: Scenery) { SceneryBuilder.remove(scenery) } @@ -1017,8 +1017,7 @@ fun playAudio(player: Player, id: Int, delay: Int = 0, loops: Int = 1, location: */ @JvmOverloads fun playGlobalAudio(location: Location, id: Int, delay: Int = 0, loops: Int = 1, radius: Int = Audio.defaultAudioRadius) { - val nearbyPlayers = RegionManager.getLocalPlayers(location, radius) - for (player in nearbyPlayers) { + for (player in RegionManager.getLocalPlayers(location, radius)) { PacketRepository.send(AudioPacket::class.java, DefaultContext(player, Audio(id, delay, loops, radius), location)) } } @@ -1106,7 +1105,7 @@ fun findNPC(refLoc: Location, id: Int): NPC? { * @returns an NPC matching the given ID or null if none is found */ fun findLocalNPC(entity: Entity, id: Int): NPC? { - return RegionManager.getLocalNpcs(entity).firstOrNull { it.id == id } + return RegionManager.getLocalNPCs(entity.location).firstOrNull { it.id == id } } /** @@ -1115,8 +1114,8 @@ fun findLocalNPC(entity: Entity, id: Int): NPC? { * @param distance The maximum distance to the entity. * @returns an NPC matching the given ID or null if none is found */ -fun findLocalNPCs(location: Location, distance: Int): MutableList { - return RegionManager.getLocalNpcs(location, distance) +fun findLocalNPCs(location: Location, distance: Int): List { + return RegionManager.getLocalNPCs(location, distance) } @@ -1126,7 +1125,7 @@ fun findLocalNPCs(location: Location, distance: Int): MutableList { * @param ids the IDs of the NPCs to look for */ fun findLocalNPCs(entity: Entity, ids: IntArray): List { - return RegionManager.getLocalNpcs(entity).filter { it.id in ids }.toList() + return RegionManager.getLocalNPCs(entity.location).filter { it.id in ids }.toList() } /** @@ -1136,7 +1135,7 @@ fun findLocalNPCs(entity: Entity, ids: IntArray): List { * @param distance The maximum distance to the entity. */ fun findLocalNPCs(entity: Entity, ids: IntArray, distance: Int): List { - return RegionManager.getLocalNpcs(entity, distance).filter { it.id in ids }.toList() + return RegionManager.getLocalNPCs(entity.location, distance).filter { it.id in ids }.toList() } /** diff --git a/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt b/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt index a26d33b92..3218207bb 100644 --- a/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt +++ b/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt @@ -1,6 +1,6 @@ package core.api.regionspec.contracts -import core.game.world.map.BuildRegionChunk +import core.game.world.map.Location import core.game.world.map.Region import core.game.world.map.RegionChunk import core.game.world.map.build.DynamicRegion @@ -19,6 +19,7 @@ open class FillChunkContract(var chunk: RegionChunk? = null) : ChunkSpecContract for(y in 0 until 8) if(replaceCondition.invoke(x,y,plane)) { val chunk = getChunk(x,y,plane,dyn) + if (chunk==null) continue dyn.replaceChunk( plane, x, @@ -31,11 +32,11 @@ open class FillChunkContract(var chunk: RegionChunk? = null) : ChunkSpecContract } } - open fun getChunk(x: Int, y: Int, plane: Int, dyn: DynamicRegion) : BuildRegionChunk? { - return chunkDelegate.invoke(x, y, plane, sourceRegion)?.copy(dyn.planes[plane]) + open fun getChunk(x: Int, y: Int, plane: Int, dyn: DynamicRegion) : RegionChunk? { + return chunkDelegate.invoke(x, y, plane, sourceRegion)?.copy() } - open fun afterSetting(chunk: BuildRegionChunk?, x: Int, y: Int, plane: Int, dyn: DynamicRegion) {} + open fun afterSetting(chunk: RegionChunk?, x: Int, y: Int, plane: Int, dyn: DynamicRegion) {} fun from(region: Region): FillChunkContract { this.sourceRegion = region diff --git a/Server/src/main/core/game/activity/ActivityPlugin.java b/Server/src/main/core/game/activity/ActivityPlugin.java index 50ea847f5..b6d7eb5a7 100644 --- a/Server/src/main/core/game/activity/ActivityPlugin.java +++ b/Server/src/main/core/game/activity/ActivityPlugin.java @@ -4,7 +4,6 @@ import core.ServerConstants; import core.game.node.entity.Entity; import core.game.node.entity.player.Player; import core.game.world.map.Location; -import core.game.world.map.Region; import core.game.world.map.build.DynamicRegion; import core.game.world.map.zone.*; import core.game.world.map.zone.impl.MultiwayCombatZone; @@ -108,7 +107,7 @@ public abstract class ActivityPlugin extends MapZone implements Plugin { l = r.getBaseLocation(); } } - ZoneBorders borders = new ZoneBorders(region.getX() << 6, region.getY() << 6, l.getX() + Region.SIZE, l.getY() + Region.SIZE); + ZoneBorders borders = new ZoneBorders(region.getX() << 6, region.getY() << 6, l.getX() + 64, l.getY() + 64); RegionZone multiZone = multicombat ? new RegionZone(MultiwayCombatZone.getInstance(), borders) : null; RegionZone zone = new RegionZone(this, borders); for (DynamicRegion r : regions) { diff --git a/Server/src/main/core/game/activity/CutscenePlugin.java b/Server/src/main/core/game/activity/CutscenePlugin.java index 043b7c179..71bce7d2b 100644 --- a/Server/src/main/core/game/activity/CutscenePlugin.java +++ b/Server/src/main/core/game/activity/CutscenePlugin.java @@ -129,12 +129,9 @@ public abstract class CutscenePlugin extends ActivityPlugin { */ public void end() { if (region != null) { - for (int i = 0; i < region.getPlanes().length; i++) { - for (NPC n : region.getPlanes()[i].getNpcs()) { - if (n == null) { - continue; - } - n.clear(); + for (int z = 0; z < 4; z++) { + for (NPC npc : region.assembleNpcList(z)) { + npc.clear(); } } } diff --git a/Server/src/main/core/game/bots/AIPlayer.java b/Server/src/main/core/game/bots/AIPlayer.java index e54fe732a..4788417ad 100644 --- a/Server/src/main/core/game/bots/AIPlayer.java +++ b/Server/src/main/core/game/bots/AIPlayer.java @@ -34,7 +34,6 @@ import java.util.*; * @author Emperor */ public class AIPlayer extends Player { - /** * The current UID. */ @@ -318,7 +317,7 @@ public class AIPlayer extends Player { int meX = this.getLocation().getX(); int meY = this.getLocation().getY(); ArrayList nodes = new ArrayList(); - for (NPC npc : RegionManager.getLocalNpcs(this, range)) { + for (NPC npc : RegionManager.getLocalNPCs(location, range)) { if (npc.getId() == entry) nodes.add(npc); } @@ -351,7 +350,7 @@ public class AIPlayer extends Player { //int meX2 = this.getLocation().getX(); ArrayList nodes = new ArrayList(); - for (NPC npc : RegionManager.getLocalNpcs(this, range)) { + for (NPC npc : RegionManager.getLocalNPCs(location, range)) { if (entrys.contains(npc.getId())) nodes.add(npc); } @@ -411,7 +410,7 @@ public class AIPlayer extends Player { public Node getClosesCreature(int radius) { int distance = radius + 1; Node npcReturn = null; - for (NPC npc : RegionManager.getLocalNpcs(this, radius)) { + for (NPC npc : RegionManager.getLocalNPCs(location, radius)) { double distanceToNpc = npc.getLocation().getDistance(this.getLocation()); if ((distanceToNpc) < distance) { distance = (int) distanceToNpc; @@ -424,7 +423,7 @@ public class AIPlayer extends Player { public Node getClosesCreature(int radius, int entry) { int distance = radius + 1; Node npcReturn = null; - for (NPC npc : RegionManager.getLocalNpcs(this, radius)) { + for (NPC npc : RegionManager.getLocalNPCs(location, radius)) { double distanceToNpc = npc.getLocation().getDistance(this.getLocation()); if (npc.getId() == entry) { if ((distanceToNpc) < distance) { @@ -439,7 +438,7 @@ public class AIPlayer extends Player { public Node getClosesCreature(int radius, ArrayList entrys) { int distance = radius + 1; Node npcReturn = null; - for (NPC npc : RegionManager.getLocalNpcs(this, radius)) { + for (NPC npc : RegionManager.getLocalNPCs(location, radius)) { double distanceToNpc = npc.getLocation().getDistance(this.getLocation()); if (entrys.contains(npc.getId())) { if ((distanceToNpc) < distance) { @@ -575,4 +574,4 @@ public class AIPlayer extends Player { public void interact(Node n) { // InteractionPacket.handleObjectInteraction(this, 0, n.getLocation(), n.getId()); } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/bots/PvMBots.java b/Server/src/main/core/game/bots/PvMBots.java index 6aef6e01e..8aeef372c 100644 --- a/Server/src/main/core/game/bots/PvMBots.java +++ b/Server/src/main/core/game/bots/PvMBots.java @@ -5,8 +5,6 @@ import java.util.List; import core.game.consumable.Consumable; import content.data.consumables.Consumables; -import core.game.consumable.Food; -import content.data.consumables.effects.HealingEffect; import core.game.node.entity.skill.Skills; import core.game.node.entity.Entity; import core.game.node.entity.npc.NPC; @@ -19,96 +17,96 @@ import core.tools.RandomFunction; public class PvMBots extends AIPlayer { - //Used so the bot doesn't spam actions - private int tick = 0; + //Used so the bot doesn't spam actions + private int tick = 0; - public PvMBots(Location l) { - super(l); - } + public PvMBots(Location l) { + super(l); + } - public PvMBots(String copyFromFile, Location l) { - super(copyFromFile, l); - } + public PvMBots(String copyFromFile, Location l) { + super(copyFromFile, l); + } - public List FindTargets(Entity entity, int radius) { - List targets = new ArrayList<>(20); - Object[] localNPCs = RegionManager.getLocalNpcs(entity,radius).toArray(); - int length = localNPCs.length; - if(length > 5){length = 5;} - for (int i = 0; i < length; i++) { - NPC npc = (NPC) localNPCs[i]; - { - if (checkValidTargets(npc)) - targets.add(npc); - } - } - if (targets.size() == 0) - return null; - return targets; - } + public List FindTargets(Entity entity, int radius) { + List targets = new ArrayList<>(20); + Object[] localNPCs = RegionManager.getLocalNPCs(entity.getLocation(), radius).toArray(); + int length = localNPCs.length; + if(length > 5){length = 5;} + for (int i = 0; i < length; i++) { + NPC npc = (NPC) localNPCs[i]; + { + if (checkValidTargets(npc)) + targets.add(npc); + } + } + if (targets.size() == 0) + return null; + return targets; + } - public boolean checkValidTargets(NPC target) { - if (!target.isActive()) { - return false; - } - if (!target.getProperties().isMultiZone() && target.inCombat()) { - return false; - } - if (!target.getDefinition().hasAction("attack")) { - return false; - } - return true; - } + public boolean checkValidTargets(NPC target) { + if (!target.isActive()) { + return false; + } + if (!target.getProperties().isMultiZone() && target.inCombat()) { + return false; + } + if (!target.getDefinition().hasAction("attack")) { + return false; + } + return true; + } - public boolean AttackNpcsInRadius(int radius) - { - return AttackNpcsInRadius(this, radius); - } + public boolean AttackNpcsInRadius(int radius) + { + return AttackNpcsInRadius(this, radius); + } - /** - * Attacks NPCs in radius of bot - * @param bot - * @param radius - * @return true if bot will be fighting - */ - public boolean AttackNpcsInRadius(Player bot, int radius) { - if (bot.inCombat()) - return true; - List creatures = FindTargets(bot, radius); - if (creatures == null) { - return false; - } - bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); - if (!creatures.isEmpty()) { - return true; - } else { - creatures = FindTargets(bot, radius); - if (!creatures.isEmpty()) - { - bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); - return true; - } - return false; - } - } + /** + * Attacks NPCs in radius of bot + * @param bot + * @param radius + * @return true if bot will be fighting + */ + public boolean AttackNpcsInRadius(Player bot, int radius) { + if (bot.inCombat()) + return true; + List creatures = FindTargets(bot, radius); + if (creatures == null) { + return false; + } + bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); + if (!creatures.isEmpty()) { + return true; + } else { + creatures = FindTargets(bot, radius); + if (!creatures.isEmpty()) + { + bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); + return true; + } + return false; + } + } - @Override - public void tick() { + @Override + public void tick() { super.tick(); this.tick++; - //Despawn - if (this.getSkills().getLifepoints() <= 5){ - //TODO: Just respawn a new bot (not sure how you'd do that :L) - // Maybe make all PvMBots know what to do if they aren't in right area? I.e. pest control bots teleport to PC - //this.teleport(new Location(500, 500)); - //Despawning not being delayed causes 3 errors in the console - this.getSkills().setLifepoints(20); - } + //Despawn + if (this.getSkills().getLifepoints() <= 5){ + //TODO: Just respawn a new bot (not sure how you'd do that :L) + // Maybe make all PvMBots know what to do if they aren't in right area? I.e. pest control bots teleport to PC + //this.teleport(new Location(500, 500)); + //Despawning not being delayed causes 3 errors in the console + this.getSkills().setLifepoints(20); + } - //Npc Combat + //Npc Combat /*if (this.tick % 10 == 0) { if (!this.inCombat()) AttackNpcsInRadius(this, 5); @@ -116,34 +114,34 @@ public class PvMBots extends AIPlayer { if (this.tick == 100) this.tick = 0; - //this.eat(); - //this.getPrayer().toggle() - } + //this.eat(); + //this.getPrayer().toggle() + } - public void CheckPrayer(PrayerType type[]) { - for (int i = 0; i < type.length; i++) - this.getPrayer().toggle(type[i]); - } + public void CheckPrayer(PrayerType type[]) { + for (int i = 0; i < type.length; i++) + this.getPrayer().toggle(type[i]); + } - public void eat(int foodId) { - Item foodItem = new Item(foodId); + public void eat(int foodId) { + Item foodItem = new Item(foodId); - if ((this.getSkills().getStaticLevel(Skills.HITPOINTS) >= this.getSkills().getLifepoints() * 3) && this.getInventory().containsItem(foodItem)) { - this.lock(3); - //this.animate(new Animation(829)); - Item food = this.getInventory().getItem(foodItem); + if ((this.getSkills().getStaticLevel(Skills.HITPOINTS) >= this.getSkills().getLifepoints() * 3) && this.getInventory().containsItem(foodItem)) { + this.lock(3); + //this.animate(new Animation(829)); + Item food = this.getInventory().getItem(foodItem); - Consumable consumable = Consumables.getConsumableById(food.getId()).getConsumable(); + Consumable consumable = Consumables.getConsumableById(food.getId()).getConsumable(); - if (consumable == null) { - return; - } + if (consumable == null) { + return; + } - consumable.consume(food, this); - this.getProperties().getCombatPulse().delayNextAttack(3); - } - if (this.checkVictimIsPlayer() == false) - if (!(this.getInventory().contains(foodId, 1))) - this.getInventory().add(new Item(foodId, 5)); //Add Food to Inventory - } + consumable.consume(food, this); + this.getProperties().getCombatPulse().delayNextAttack(3); + } + if (this.checkVictimIsPlayer() == false) + if (!(this.getInventory().contains(foodId, 1))) + this.getInventory().add(new Item(foodId, 5)); //Add Food to Inventory + } } diff --git a/Server/src/main/core/game/bots/ScriptAPI.kt b/Server/src/main/core/game/bots/ScriptAPI.kt index c2ac69649..14ed085ac 100644 --- a/Server/src/main/core/game/bots/ScriptAPI.kt +++ b/Server/src/main/core/game/bots/ScriptAPI.kt @@ -41,7 +41,6 @@ import core.game.ge.GrandExchange import core.game.ge.GrandExchangeOffer import core.game.interaction.IntType import core.game.interaction.InteractionListeners -import core.tools.SystemLogger import core.game.system.config.ItemConfigParser import core.game.world.GameWorld import core.game.world.repository.Repository @@ -134,24 +133,22 @@ class ScriptAPI(private val bot: Player) { * @author Ceikry */ fun getNearestNodeFromList(acceptedNames: List, isObject: Boolean): Node? { - if (isObject) - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].objectList, acceptedName = acceptedNames) - else - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedName = acceptedNames) + val region = RegionManager.forId(bot.location.regionId) + val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleEntityList(bot.location.z) + return processEvaluationList(list, acceptedName = acceptedNames) } /** * Gets the nearest node with matching id. * @param id the id to look for - * @param object whether or not the node we are looking for is an object. + * @param object whether the node we are looking for is an object. * @return the closest node with matching id or null. * @author Ceikry */ fun getNearestNode(id: Int, isObject: Boolean): Node? { - if (isObject) - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].objectList, acceptedId = id) - else - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedId = id) + val region = RegionManager.forId(bot.location.regionId) + val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleEntityList(bot.location.z) + return processEvaluationList(list, acceptedId = id) } /** @@ -161,25 +158,28 @@ class ScriptAPI(private val bot: Player) { * @author Ceikry */ fun getNearestNode(entityName: String): Node? { - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedName = listOf(entityName)) + val region = RegionManager.forId(bot.location.regionId) + val list = region.assembleEntityList(bot.location.z) + return processEvaluationList(list, acceptedName = listOf(entityName)) } /** * Gets the nearest node with a matching name. * @param name the name to look for. - * @param object whether or not the node we are looking for is an object. + * @param object whether the node we are looking for is an object. * @return the nearest matching node or null. * @author Ceikry */ fun getNearestNode(name: String, isObject: Boolean): Node? { - if (isObject) - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].objectList, acceptedName = listOf(name)) - else - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedName = listOf(name)) + val region = RegionManager.forId(bot.location.regionId) + val list = region.assembleEntityList(bot.location.z) + return processEvaluationList(list, acceptedName = listOf(name)) } fun getNearestObjectByPredicate(predicate: (Node?) -> Boolean): Node? { - return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].objectList, acceptedPredicate = predicate) + val region = RegionManager.forId(bot.location.regionId) + val list = region.assembleObjectList(bot.location.z) + return processEvaluationList(list, acceptedPredicate = predicate) } fun evaluateViability (e: Node?, minDistance: Double, maxDistance: Double, acceptedNames: List? = null, acceptedId: Int = -1, acceptedPredicate: ((Node?) -> Boolean)? = null): Boolean { @@ -268,12 +268,10 @@ class ScriptAPI(private val bot: Player) { fun getNearestGameObject(loc: Location, objectId: Int): Scenery? { var nearestObject: Scenery? = null val minDistance = Double.MAX_VALUE - for (o in RegionManager.forId(loc.regionId).planes[0].objects) { - for (obj in o) { - if (obj != null) { - if (distance(loc, obj) < minDistance && obj.id == objectId) { - nearestObject = obj - } + for (obj in RegionManager.forId(loc.regionId).assembleObjectList(loc.z)) { + if (obj != null) { + if (distance(loc, obj) < minDistance && obj.id == objectId) { + nearestObject = obj } } } @@ -290,7 +288,7 @@ class ScriptAPI(private val bot: Player) { */ private fun findTargets(entity: Entity, radius: Int, name: String? = null): List? { val targets: MutableList = ArrayList() - val localNPCs: Array = RegionManager.getLocalNpcs(entity, radius).toTypedArray() + val localNPCs: Array = RegionManager.getLocalNPCs(entity.location, radius).toTypedArray() var length = localNPCs.size if (length > 5) { length = 5 diff --git a/Server/src/main/core/game/global/action/DoorActionHandler.java b/Server/src/main/core/game/global/action/DoorActionHandler.java index 02234e136..26df139c5 100644 --- a/Server/src/main/core/game/global/action/DoorActionHandler.java +++ b/Server/src/main/core/game/global/action/DoorActionHandler.java @@ -137,7 +137,7 @@ public final class DoorActionHandler { return Unit.INSTANCE; }); } - GameWorld.getPulser().submit(new Pulse(1) { + GameWorld.getPulser().submit(new Pulse(1) { boolean opened = false; @Override public boolean pulse() { @@ -161,7 +161,7 @@ public final class DoorActionHandler { } // pass the al kharid gate - if (object.getId() == 35549 || object.getId() == 35551 && player.getViewport().getRegion().getId() == 13106) { + if (object.getId() == 35549 || object.getId() == 35551 && player.getLocation().getRegionId() == 13106) { player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 4); } @@ -425,7 +425,7 @@ public final class DoorActionHandler { } object.setCharge(IN_USE_CHARGE); second.setCharge(IN_USE_CHARGE); - GameWorld.getPulser().submit(new Pulse(1) { + GameWorld.getPulser().submit(new Pulse(1) { boolean opened = false; @Override @@ -499,18 +499,17 @@ public final class DoorActionHandler { */ public static Scenery getSecondDoor(Scenery object, Entity entity) { Location l = object.getLocation(); - Player player = entity instanceof Player ? (Player) entity : null; Scenery o = null; - if ((o = RegionManager.getObject(l.transform(-1, 0, 0))) != null && o.getName().equals(object.getName())) { + if ((o = RegionManager.getObject(l.transform(-1, 0, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } - if ((o = RegionManager.getObject(l.transform(1, 0, 0))) != null && o.getName().equals(object.getName())) { + if ((o = RegionManager.getObject(l.transform(1, 0, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } - if ((o = RegionManager.getObject(l.transform(0, -1, 0))) != null && o.getName().equals(object.getName())) { + if ((o = RegionManager.getObject(l.transform(0, -1, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } - if ((o = RegionManager.getObject(l.transform(0, 1, 0))) != null && o.getName().equals(object.getName())) { + if ((o = RegionManager.getObject(l.transform(0, 1, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } return null; diff --git a/Server/src/main/core/game/interaction/MovementPulse.java b/Server/src/main/core/game/interaction/MovementPulse.java index b378a8a1f..b9acb88fd 100644 --- a/Server/src/main/core/game/interaction/MovementPulse.java +++ b/Server/src/main/core/game/interaction/MovementPulse.java @@ -7,7 +7,6 @@ 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.task.Pulse; -import core.game.world.GameWorld; import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.Point; @@ -19,11 +18,8 @@ import core.net.packet.context.PlayerContext; import core.net.packet.out.ClearMinimapFlag; import kotlin.jvm.functions.Function2; import kotlin.Pair; -import core.tools.SystemLogger; import core.api.utils.Vector; -import content.region.wilderness.handlers.revenants.RevenantNPC; - import static core.api.ContentAPIKt.*; import java.util.Deque; @@ -206,142 +202,148 @@ public abstract class MovementPulse extends Pulse { mover.scripts.removeNormalScripts(); } - @Override - public boolean update() { - if (!mover.getViewport().getRegion().isActive()) - return false; + @Override + public boolean update() { + if (!mover.getLocation().getRegion().isActive()) + return false; - if (!isRunning()) return true; + if (!isRunning()) return true; - if (!validate()) { - stop(); - return true; - } - - clearInferiorScripts(); - - mover.face(null); - if (canInteractWithoutMoving()) { - if (interactImmediately()) { - stop(); - return true; - } - } - updatePath(); - - if (tryInteract()) { - stop(); - return true; - } - - return false; - } - - private boolean tryInteract() { - Location ml = mover.getLocation(); - // Allow being within 1 square of moving entities to interact with them. - int radius = destination instanceof Entity && ((Entity)destination).getWalkingQueue().hasPath() ? 1 : 0; - if (interactLocation == null) - return false; - boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; - // Check if already in a valid interaction position for entity destinations - boolean canInteractFromCurrentPosition = false; - if (!atInteractLocation && destination instanceof Entity) { - Entity target = (Entity) destination; - Location dl = target.getLocation(); - boolean onSameTile = ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ(); - if (!onSameTile) { - canInteractFromCurrentPosition = Pathfinder.canInteract( - ml.getX(), ml.getY(), mover.size(), - dl.getX(), dl.getY(), target.size(), target.size(), - 0, // walkFlag - "can interact from any unblocked direction" - ml.getZ(), - RegionManager::getClippingFlag - ); - } - } - if (atInteractLocation || canInteractFromCurrentPosition) { - try { - if (near || pulse()) { - if (mover instanceof Player) { - if (near) { - ((Player) mover).getPacketDispatch().sendMessage("I can't reach that."); - } - PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); - } - stop(); - return true; - } - } catch (Exception e){ - e.printStackTrace(); - stop(); - } - } - return false; - } - - /** - * Checks if the mover can interact with an entity destination from their - * current position without needing to move. - * - * @return true if the mover can interact without moving - */ - private boolean canInteractWithoutMoving() { - if (!(destination instanceof Entity)) { - return false; - } - Entity target = (Entity) destination; - Location ml = mover.getLocation(); - Location dl = target.getLocation(); - if (ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ()) { - return false; - } - if (isInsideEntity(mover.getLocation())) { - return false; - } - if (target.getWalkingQueue().hasPath()) { // For moving entities, allow interaction from 1 tile away - int distance = Math.max( - Math.abs(ml.getX() - dl.getX()), - Math.abs(ml.getY() - dl.getY()) - ); - if (distance <= target.size()) { - return true; - } - } - return Pathfinder.canInteract( - ml.getX(), ml.getY(), mover.size(), - dl.getX(), dl.getY(), target.size(), target.size(), - 0, // walkFlag - "can interact from any unblocked direction" - ml.getZ(), - RegionManager::getClippingFlag - ); - } - - /** - * Immediately performs the interaction without pathfinding. - * Called when the player is already in a valid interaction position. - * - * @return true if interaction was successful and pulse should stop - */ - private boolean interactImmediately() { - if (destination instanceof Entity) { - mover.face((Entity) destination); - } - try { - if (pulse()) { - if (mover instanceof Player) { - PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); + if (!validate()) { + stop(); + return true; } - return true; - } - } catch (Exception e) { - e.printStackTrace(); + + clearInferiorScripts(); + + mover.face(null); + if (canInteractWithoutMoving()) { + if (interactImmediately()) { + stop(); + return true; + } + } + updatePath(); + + if (tryInteract()) { + stop(); + return true; + } + + return false; + } + + private boolean tryInteract() { + Location ml = mover.getLocation(); + if (ml == null) { + return false; + } + // Allow being within 1 square of moving entities to interact with them. + int radius = destination instanceof Entity && ((Entity) destination).getWalkingQueue().hasPath() ? 1 : 0; + if (interactLocation == null) + return false; + boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; + // Check if already in a valid interaction position for entity destinations + boolean canInteractFromCurrentPosition = false; + if (!atInteractLocation && destination instanceof Entity) { + Entity target = (Entity) destination; + Location dl = target.getLocation(); + if (dl == null) { + return false; + } + boolean onSameTile = ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ(); + if (!onSameTile) { + canInteractFromCurrentPosition = Pathfinder.canInteract( + ml.getX(), ml.getY(), mover.size(), + dl.getX(), dl.getY(), target.size(), target.size(), + 0, // walkFlag - "can interact from any unblocked direction" + ml.getZ(), + RegionManager::getClippingFlag); + } + } + if (atInteractLocation || canInteractFromCurrentPosition) { + try { + if (near || pulse()) { + if (mover instanceof Player) { + if (near) { + ((Player) mover).getPacketDispatch().sendMessage("I can't reach that."); + } + PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); + } + stop(); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + stop(); + } + } + return false; + } + + /** + * Checks if the mover can interact with an entity destination from their + * current position without needing to move. + * + * @return true if the mover can interact without moving + */ + private boolean canInteractWithoutMoving() { + if (!(destination instanceof Entity)) { + return false; + } + Entity target = (Entity) destination; + Location ml = mover.getLocation(); + Location dl = target.getLocation(); + if (ml == null || dl == null) { + return false; + } + if (ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ()) { + return false; + } + if (isInsideEntity(ml)) { + return false; + } + if (target.getWalkingQueue().hasPath()) { // For moving entities, allow interaction from 1 tile away + int distance = Math.max( + Math.abs(ml.getX() - dl.getX()), + Math.abs(ml.getY() - dl.getY())); + if (distance <= target.size()) { + return true; + } + } + return Pathfinder.canInteract( + ml.getX(), ml.getY(), mover.size(), + dl.getX(), dl.getY(), target.size(), target.size(), + 0, // walkFlag - "can interact from any unblocked direction" + ml.getZ(), + RegionManager::getClippingFlag); + } + + /** + * Immediately performs the interaction without pathfinding. + * Called when the player is already in a valid interaction position. + * + * @return true if interaction was successful and pulse should stop + */ + private boolean interactImmediately() { + if (destination instanceof Entity) { + mover.face((Entity) destination); + } + try { + if (pulse()) { + if (mover instanceof Player) { + PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); + } + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; } - return false; - } private boolean validate() { - if (mover == null || destination == null || mover.getViewport().getRegion() == null || hasInactiveNode()) { + if (mover == null || destination == null || mover.getLocation().getRegion() == null || hasInactiveNode()) { return false; } return isRunning(); @@ -595,6 +597,9 @@ public abstract class MovementPulse extends Pulse { * @return {@code True} if so. */ private boolean isInsideEntity(Location l) { + if (l == null) { + return false; + } if (!(destination instanceof Entity)) { return false; } @@ -602,6 +607,9 @@ public abstract class MovementPulse extends Pulse { return false; } Location loc = destination.getLocation(); + if (loc == null) { + return false; + } int size = destination.size(); return Pathfinder.isStandingIn(l.getX(), l.getY(), mover.size(), mover.size(), loc.getX(), loc.getY(), size, size); } diff --git a/Server/src/main/core/game/node/entity/Entity.java b/Server/src/main/core/game/node/entity/Entity.java index ffaa8f461..d4d1a8f2b 100644 --- a/Server/src/main/core/game/node/entity/Entity.java +++ b/Server/src/main/core/game/node/entity/Entity.java @@ -20,7 +20,6 @@ import core.game.world.map.zone.ZoneRestriction; import org.jetbrains.annotations.NotNull; import core.game.world.GameWorld; import core.game.world.map.Location; -import core.game.world.map.Viewport; import core.game.world.map.path.Path; import core.game.world.map.path.Pathfinder; import core.game.world.map.zone.ZoneMonitor; @@ -70,11 +69,6 @@ public abstract class Entity extends Node { */ private final GameAttributes attributes = new GameAttributes(); - /** - * The entity's viewport. - */ - private final Viewport viewport = new Viewport(); - /** * The pulse manager. */ @@ -114,7 +108,7 @@ public abstract class Entity extends Node { * The mapping of event types to event hooks */ private HashMap, ArrayList> hooks = new HashMap<>(); - public TimerManager timers = new TimerManager(this); + public TimerManager timers = new TimerManager(this); /** * If the entity is invisible. @@ -205,7 +199,7 @@ public abstract class Entity extends Node { */ public void init() { active = true; - TimerRegistry.addAutoTimers (this); + TimerRegistry.addAutoTimers (this); } /** @@ -218,7 +212,7 @@ public abstract class Entity extends Node { Location old = location != null ? location.transform(0, 0, 0) : Location.create(0,0,0); walkingQueue.update(); scripts.postMovement(!Objects.equals(location, old)); - timers.processTimers(); + timers.processTimers(); updateMasks.prepare(this); } @@ -242,7 +236,6 @@ public abstract class Entity extends Node { */ public void clear() { active = false; - viewport.remove(this); pulseManager.clear(); } @@ -259,8 +252,8 @@ public abstract class Entity extends Node { */ public void fullRestore() { skills.restore(); - timers.removeTimer("poison"); - timers.removeTimer("poison:immunity"); + timers.removeTimer("poison"); + timers.removeTimer("poison:immunity"); } /** @@ -309,12 +302,12 @@ public abstract class Entity extends Node { return false; } - /** - * Should this entity prevent the mover from moving through it? - */ - public boolean shouldPreventStacking(Entity mover) { - return false; - } + /** + * Should this entity prevent the mover from moving through it? + */ + public boolean shouldPreventStacking(Entity mover) { + return false; + } /** * Checks an impact before receiving it. @@ -440,7 +433,7 @@ public abstract class Entity extends Node { * Checks if this entity is attackable by the attacking entity. * @param entity The attacking entity. * @param style The combat style used. - * @param message Whether to send the player a message indicating why the entity isn't attackable. + * @param message Whether to send the player a message indicating why the entity isn't attackable. * @return {@code True} if the attacking entity can attack this entity. */ public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { @@ -651,15 +644,15 @@ public abstract class Entity extends Node { * @return {@code True} if succesful. */ public boolean face(Entity entity) { - if (entity == null) { - int ordinal = EntityFlags.getOrdinal(EFlagType.of(this), EntityFlag.FaceEntity); - if (getUpdateMasks().unregisterSynced(ordinal)) { - return getUpdateMasks().register(EntityFlag.FaceEntity, null); - } - return true; - } - return getUpdateMasks().register(EntityFlag.FaceEntity, entity, true); - } + if (entity == null) { + int ordinal = EntityFlags.getOrdinal(EFlagType.of(this), EntityFlag.FaceEntity); + if (getUpdateMasks().unregisterSynced(ordinal)) { + return getUpdateMasks().register(EntityFlag.FaceEntity, null); + } + return true; + } + return getUpdateMasks().register(EntityFlag.FaceEntity, entity, true); + } /** * Registers a new face location update flag to the update masks. @@ -667,13 +660,13 @@ public abstract class Entity extends Node { * @return {@code True} if succesful. */ public boolean faceLocation(Location location) { - if (location == null) { - int ordinal = EntityFlags.getOrdinal(EFlagType.of(this), EntityFlag.FaceLocation); - getUpdateMasks().unregisterSynced(ordinal); - return true; - } - return getUpdateMasks().register(EntityFlag.FaceLocation, location, true); - } + if (location == null) { + int ordinal = EntityFlags.getOrdinal(EFlagType.of(this), EntityFlag.FaceLocation); + getUpdateMasks().unregisterSynced(ordinal); + return true; + } + return getUpdateMasks().register(EntityFlag.FaceLocation, location, true); + } /** * Registers a new force chat update flag to the update masks. @@ -681,8 +674,8 @@ public abstract class Entity extends Node { * @return {@code True} if successful. */ public boolean sendChat(String string) { - return getUpdateMasks().register(EntityFlag.ForceChat, string); - } + return getUpdateMasks().register(EntityFlag.ForceChat, string); + } /** * Gets the current combat swing handler. @@ -879,13 +872,6 @@ public abstract class Entity extends Node { return walkingQueue; } - /** - * Gets the viewport. - * @return The viewport. - */ - public Viewport getViewport() { - return viewport; - } /** * Gets the skills. @@ -947,7 +933,7 @@ public abstract class Entity extends Node { * @return {@code True} if so. */ public boolean isTeleBlocked() { - return timers.getTimer("teleblock") != null || getLocks().isTeleportLocked() || getZoneMonitor().isRestricted(ZoneRestriction.TELEPORT); + return timers.getTimer("teleblock") != null || getLocks().isTeleportLocked() || getZoneMonitor().isRestricted(ZoneRestriction.TELEPORT); } /** @@ -966,7 +952,7 @@ public abstract class Entity extends Node { this.invisible = invisible; } - public Location getClosestOccupiedTile(@NotNull Location other) { + public Location getClosestOccupiedTile(@NotNull Location other) { List occupied = getOccupiedTiles(); Location closest = location; @@ -982,7 +968,7 @@ public abstract class Entity extends Node { } return closest; - } + } public List getOccupiedTiles() { ArrayList occupied = new ArrayList<>(); @@ -1001,7 +987,7 @@ public abstract class Entity extends Node { return scripts.getDelay() > GameWorld.getTicks(); } - public boolean isTeleporting() { - return getAttribute("tele-pulse", null) != null || properties.getTeleportLocation() != null; - } + public boolean isTeleporting() { + return getAttribute("tele-pulse", null) != null || properties.getTeleportLocation() != null; + } } diff --git a/Server/src/main/core/game/node/entity/combat/CombatPulse.kt b/Server/src/main/core/game/node/entity/combat/CombatPulse.kt index 074a656e9..7a176b1ad 100644 --- a/Server/src/main/core/game/node/entity/combat/CombatPulse.kt +++ b/Server/src/main/core/game/node/entity/combat/CombatPulse.kt @@ -19,6 +19,7 @@ import core.tools.RandomFunction import core.api.* import core.game.interaction.DestinationFlag import core.game.system.timer.impl.* +import core.game.world.map.RegionManager /** * The combat-handling pulse implementation. @@ -116,7 +117,7 @@ class CombatPulse( if (victim == null || DeathTask.isDead(entity) || DeathTask.isDead(victim)) { return true } - if (!entity!!.viewport.region.isActive || !victim!!.viewport.region.isActive) { + if (!RegionManager.forId(entity!!.location.regionId).isActive || !RegionManager.forId(victim!!.location.regionId).isActive) { return true } if (!interactable()) { diff --git a/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt b/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt index 2b151ba47..bbd951985 100644 --- a/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt +++ b/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt @@ -17,7 +17,6 @@ import core.game.world.map.Direction import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.map.RegionManager.getClippingFlag -import core.game.world.map.path.Pathfinder import core.game.world.map.path.Pathfinder.* import core.game.world.update.flag.context.Animation import core.tools.RandomFunction @@ -25,7 +24,6 @@ import core.game.system.config.ItemConfigParser import core.tools.Log import org.rs09.consts.Sounds import java.util.* -import kotlin.math.floor /** * Handles a combat swing. diff --git a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java index 30cf2f238..6ac567b15 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java @@ -15,12 +15,14 @@ import core.game.node.entity.player.link.audio.Audio; import core.game.node.item.Item; import core.game.world.map.RegionManager; import core.game.world.map.zone.impl.WildernessZone; +import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import org.rs09.consts.Sounds; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import static core.api.ContentAPIKt.playGlobalAudio; @@ -108,29 +110,26 @@ public abstract class CombatSpell extends MagicSpell { } - /** - * Gets a list of valid targets for a multihitting spell. - * @param entity The caster of the spell. - * @param target The primary victim. - * @param max The maximum number of extra victims that may be hit. - * @return The list of targets (the primary target is always at index 0). - */ - public List getMultihitTargets(Entity entity, Entity target, int max) { + /** + * Gets a list of valid targets for a multihitting spell. + * @param entity The caster of the spell. + * @param target The primary victim. + * @param max The maximum number of extra victims that may be hit. + * @return The list of targets (the primary target is always at index 0). + */ + public List getMultihitTargets(Entity entity, Entity target, int max) { List victims = new ArrayList<>(20); victims.add(target); - List surrounding = new ArrayList<>(); - surrounding.addAll(RegionManager.getSurroundingPlayers(target)); - surrounding.addAll(RegionManager.getSurroundingNPCs(target)); - - for (Entity e : surrounding) { - if (e == target || e == entity) { - continue; - } - if (CombatStyle.MAGIC.getSwingHandler().canSwing(entity, e) == InteractionType.NO_INTERACT || !e.isAttackable(entity, CombatStyle.MAGIC, false)) { + List surrounding = RegionManager.getLocalEntities(target.getLocation(), 1); + for (Entity e : surrounding) { + if (e == target || e == entity) { continue; } - if (e instanceof Familiar) { + if (CombatStyle.MAGIC.getSwingHandler().canSwing(entity, e) == InteractionType.NO_INTERACT || !e.isAttackable(entity, CombatStyle.MAGIC, false)) { + continue; + } + if (e instanceof Familiar) { Player owner = ((Familiar) e).getOwner(); if (owner != entity && WildernessZone.getInstance().continueAttack(entity, owner, CombatStyle.MAGIC, true)) { victims.add(e); @@ -143,7 +142,7 @@ public abstract class CombatSpell extends MagicSpell { } } return victims; - } + } /** * Visualizes the impact. diff --git a/Server/src/main/core/game/node/entity/impl/ForceMovement.java b/Server/src/main/core/game/node/entity/impl/ForceMovement.java index 8cfc7efd6..f450b6237 100644 --- a/Server/src/main/core/game/node/entity/impl/ForceMovement.java +++ b/Server/src/main/core/game/node/entity/impl/ForceMovement.java @@ -93,7 +93,7 @@ public class ForceMovement extends Pulse { * @param unlockAfter Whether to unlock the entity after the ForceMovement completes * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public ForceMovement(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int commenceSpeed, int pathSpeed, boolean unlockAfter) { super(1, e); this.entity = e; @@ -116,15 +116,15 @@ public class ForceMovement extends Pulse { * @param speed The path speed. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public ForceMovement(Entity e, Location start, Location end, Animation animation, int speed) { this(e, start, end, WALK_ANIMATION, animation, direction(start, end), WALKING_SPEED, speed, true); } - /** + /** * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public ForceMovement(Entity e, Location destination, int startSpeed, int animSpeed){ this(e,e.getLocation(),destination,WALK_ANIMATION,WALK_ANIMATION,direction(e.getLocation(),destination),startSpeed,animSpeed, true); } @@ -137,7 +137,7 @@ public class ForceMovement extends Pulse { * @param animation the animation. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public ForceMovement(Entity e, Location start, Location destination, Animation animation) { this(e, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -149,7 +149,7 @@ public class ForceMovement extends Pulse { * @param animation the animation. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public ForceMovement(Location start, Location destination, Animation animation) { this(null, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -161,7 +161,7 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location destination) { return run(e, e.getLocation(), destination, WALK_ANIMATION, WALK_ANIMATION, direction(e.getLocation(), destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -174,7 +174,7 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination) { return run(e, start, destination, WALK_ANIMATION, WALK_ANIMATION, direction(e.getLocation(), destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -188,7 +188,7 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation animation) { return run(e, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -203,7 +203,7 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation animation, int speed) { return run(e, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, speed, true); } @@ -217,7 +217,7 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation) { return run(e, start, destination, startAnim, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -232,7 +232,7 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction) { return run(e, start, destination, startAnim, animation, direction, WALKING_SPEED, WALKING_SPEED, true); } @@ -248,15 +248,15 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int pathSpeed) { return run(e, start, destination, startAnim, animation, direction, WALKING_SPEED, pathSpeed, true); } - /** + /** * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int commenceSpeed, int pathSpeed) { return run(e, start, destination, startAnim, animation, direction, commenceSpeed, pathSpeed, true); } @@ -271,7 +271,7 @@ public class ForceMovement extends Pulse { * @return The created ForceMovement object. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int commenceSpeed, int pathSpeed, boolean unlockAfter) { if (startAnim != null) { startAnim.setPriority(Animator.Priority.VERY_HIGH); @@ -285,10 +285,10 @@ public class ForceMovement extends Pulse { GameWorld.getPulser().submit(fm); return fm; } - /* + /* * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public static ForceMovement run(Entity e, Location destination, int commenceSpeed, int pathSpeed){ return run(e,e.getLocation(),destination,WALK_ANIMATION,WALK_ANIMATION,direction(e.getLocation(),destination),commenceSpeed,pathSpeed, true); } @@ -298,7 +298,7 @@ public class ForceMovement extends Pulse { * @param e the entity. * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ - @Deprecated + @Deprecated public void run(final Entity e, final int speed) { this.entity = e; int commence = (int) start.getDistance(e.getLocation()); @@ -358,9 +358,9 @@ public class ForceMovement extends Pulse { int ticks = 1 + commenceSpeed + pathSpeed; entity.getImpactHandler().setDisabledTicks(ticks); entity.getUpdateMasks().register(EntityFlag.ForceMove, new ForceMoveCtx(start, destination, commenceSpeed * 30, pathSpeed * 30, direction)); - if(entity instanceof Player) { - entity.getWalkingQueue().updateRegion(destination, false); - } + if (entity instanceof Player) { + entity.getWalkingQueue().updateRegion(start, destination, false); + } super.start(); } diff --git a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java index fbd9d2e36..d10215b40 100644 --- a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java +++ b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java @@ -62,7 +62,7 @@ public final class WalkingQueue { */ private Location footPrint; - public ArrayList routeItems = new ArrayList(); + public ArrayList routeItems = new ArrayList(); /** * Constructs a new {@code WalkingQueue} {@code Object}. @@ -80,29 +80,30 @@ public final class WalkingQueue { boolean isPlayer = entity instanceof Player; this.walkDir = -1; this.runDir = -1; - if(entity.getLocation() == null) { + Location prevLocation = entity.getLocation(); + if (prevLocation == null) { return; } if (updateTeleport()) { return; } - if (isPlayer && updateRegion(entity.getLocation(), true)) { + if (isPlayer && updateRegion(prevLocation, entity.getLocation(), true)) { return; } - if (hasTimerActive(entity, "frozen")) - return; + if (hasTimerActive(entity, "frozen")) + return; Point point = walkingQueue.poll(); - boolean drawPath = entity.getAttribute("routedraw", false); + boolean drawPath = entity.getAttribute("routedraw", false); if (point == null) { updateRunEnergy(false); - if (isPlayer && drawPath) { - for (GroundItem item : routeItems) { - if (item != null) { - RegionManager.getRegionPlane(item.getLocation()).remove(item); - } - } - routeItems.clear(); - } + if (isPlayer && drawPath) { + for (GroundItem item : routeItems) { + if (item != null) { + RegionManager.getRegionChunk(item.getLocation()).remove(item); + } + } + routeItems.clear(); + } return; } if (isPlayer && ((Player) entity).getSettings().getRunEnergy() < 1.0) { @@ -174,7 +175,7 @@ public final class WalkingQueue { } footPrint = entity.getLocation(); entity.setLocation(dest); - RegionManager.move(entity); + RegionManager.move(entity, prevLocation, dest); } this.walkDir = walkDirection; this.runDir = runDirection; @@ -190,9 +191,9 @@ public final class WalkingQueue { if (player.getSettings().getWeight() > 0.0) { rate *= 1 + (player.getSettings().getWeight() / 100); } - if (hasTimerActive(player, "hamstrung")) { - rate *= 4; - } + if (hasTimerActive(player, "hamstrung")) { + rate *= 4; + } return rate; } @@ -237,6 +238,7 @@ public final class WalkingQueue { public boolean updateTeleport() { if (entity.getProperties().getTeleportLocation() != null) { reset(false); + Location prevLocation = entity.getLocation(); entity.setLocation(entity.getProperties().getTeleportLocation()); entity.getProperties().setTeleportLocation(null); if (entity instanceof Player) { @@ -251,7 +253,7 @@ public final class WalkingQueue { p.getPlayerFlags().setUpdateSceneGraph(true); } } - RegionManager.move(entity); + RegionManager.move(entity, prevLocation, entity.getLocation()); footPrint = entity.getLocation(); entity.getProperties().setTeleporting(true); return true; @@ -264,7 +266,7 @@ public final class WalkingQueue { * return true. * @return {@code True} if the region updated, {@code false} if not. */ - public boolean updateRegion(Location location, boolean move) { + public boolean updateRegion(Location prevLocation, Location location, boolean move) { Player p = (Player) entity; Location lastRegion = p.getPlayerFlags().getLastSceneGraph(); if (lastRegion == null) { @@ -285,7 +287,7 @@ public final class WalkingQueue { p.getPlayerFlags().setUpdateSceneGraph(true); } if (move && p.getPlayerFlags().isUpdateSceneGraph()) { - RegionManager.move(entity); + RegionManager.move(entity, prevLocation, location); return true; } return false; @@ -320,13 +322,13 @@ public final class WalkingQueue { if (point == null) { return; } - boolean drawRoute = entity.getAttribute("routedraw", false); - if (drawRoute && entity instanceof Player) { - Player p = (Player) entity; - GroundItem item = new GroundItem(new Item(13444), Location.create(x, y, p.getLocation().getZ()), p); - routeItems.add (item); - RegionManager.getRegionPlane(item.getLocation()).add(item); - } + boolean drawRoute = entity.getAttribute("routedraw", false); + if (drawRoute && entity instanceof Player) { + Player p = (Player) entity; + GroundItem item = new GroundItem(new Item(13444), Location.create(x, y, p.getLocation().getZ()), p); + routeItems.add (item); + RegionManager.getRegionChunk(item.getLocation()).add(item); + } int diffX = x - point.getX(), diffY = y - point.getY(); int max = Math.max(Math.abs(diffX), Math.abs(diffY)); for (int i = 0; i < max; i++) { diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index 18334251e..fe04c19e1 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -142,7 +142,7 @@ public class NPC extends Entity { public NPCBehavior behavior; - public boolean isRespawning = false; + public boolean isRespawning = false; /** * Constructs a new {@code NPC} {@code Object}. @@ -213,8 +213,8 @@ public class NPC extends Entity { getProperties().setSpawnLocation(getLocation()); initConfig(); Repository.getNpcs().add(this); - RegionManager.move(this); - if (getViewport().getRegion().isActive()) { + getLocation().getChunk().add(this); + if (getLocation().getRegion().isActive()) { Repository.addRenderableNPC(this); } interactPlugin.setDefault(); @@ -230,9 +230,9 @@ public class NPC extends Entity { } } behavior.onCreation(this); - // FIXME: hack around MovementPulse's constructor getting run while behavior is null when behavior is set between NPC constructor and init. + // FIXME: hack around MovementPulse's constructor getting run while behavior is null when behavior is set between NPC constructor and init. // FIXME: Commented out as a fix. most npcs were not being able to attack with range/magic due to setting the combat pulse. - // getProperties().setCombatPulse(new CombatPulse(this)); + // getProperties().setCombatPulse(new CombatPulse(this)); } @Override @@ -240,9 +240,7 @@ public class NPC extends Entity { super.clear(); Repository.removeRenderableNPC(this); Repository.getNpcs().remove(this); - getViewport().setCurrentPlane(null); behavior.onRemoval(this); - // getViewport().setRegion(null); } /** @@ -329,7 +327,7 @@ public class NPC extends Entity { */ public boolean openShop(Player player) { if (getName().contains("assistant")) { - NPC n = RegionManager.getNpc(this, getId() - 1); + NPC n = RegionManager.getNpc(location, getId() - 1, 16); if (n != null) { return n.openShop(player); } @@ -425,7 +423,7 @@ public class NPC extends Entity { return false; } return true; - } + } @Override public int getDragonfireProtection(boolean fire) { @@ -434,7 +432,7 @@ public class NPC extends Entity { @Override public void tick() { - if (!getViewport().getRegion().isActive()) { + if (!getLocation().getRegion().isActive()) { onRegionInactivity(); return; } @@ -444,10 +442,10 @@ public class NPC extends Entity { return; } if (isRespawning && respawnTick <= GameWorld.getTicks()) { - behavior.onRespawn(this); + behavior.onRespawn(this); onRespawn(); - fullRestore(); - isRespawning = false; + fullRestore(); + isRespawning = false; } handleTickActions(); super.tick(); @@ -549,10 +547,10 @@ public class NPC extends Entity { nextWalk = GameWorld.getTicks() + 5 + RandomFunction.randomize(10); } - public void resetWalk() { - nextWalk = GameWorld.getTicks() - 1; - getWalkingQueue().reset(); - } + public void resetWalk() { + nextWalk = GameWorld.getTicks() - 1; + getWalkingQueue().reset(); + } /** * Called when the region goes inactive. @@ -570,7 +568,7 @@ public class NPC extends Entity { } } Repository.removeRenderableNPC(this); - if (getViewport().getRegion() instanceof DynamicRegion) { + if (getLocation().getRegion() instanceof DynamicRegion) { clear(); } } @@ -597,7 +595,7 @@ public class NPC extends Entity { Player p = !(killer instanceof Player) ? null : (Player) killer; if (p != null) { p.incrementAttribute("/save:" + STATS_BASE + ":" + STATS_ENEMIES_KILLED); - PlayerStatsCounter.incrementKills(p, originalId); + PlayerStatsCounter.incrementKills(p, originalId); } handleDrops(p, killer); if (!isRespawn()) @@ -608,9 +606,9 @@ public class NPC extends Entity { setRespawnTick(GameWorld.getTicks() + definition.getConfiguration(NPCConfigParser.RESPAWN_DELAY, 17)); } - public void setRespawnTicks (int ticks) { - definition.getHandlers().put(NPCConfigParser.RESPAWN_DELAY, ticks); - } + public void setRespawnTicks (int ticks) { + definition.getHandlers().put(NPCConfigParser.RESPAWN_DELAY, ticks); + } @Override public void commenceDeath(Entity killer) { @@ -687,9 +685,9 @@ public class NPC extends Entity { } getProperties().setAttackStyle(new WeaponInterface.AttackStyle(WeaponInterface.STYLE_CONTROLLED, index)); CombatStyle style = getDefinition().getConfiguration(NPCConfigParser.COMBAT_STYLE); - if (style != null) { - getProperties().getCombatPulse().setStyle(style); - } + if (style != null) { + getProperties().getCombatPulse().setStyle(style); + } if (style == CombatStyle.MAGIC) { getProperties().setAutocastSpell(new DefaultCombatSpell(this)); int spell = definition.getConfiguration("spell_id", -1); @@ -744,10 +742,10 @@ public class NPC extends Entity { configure(); interactPlugin.setDefault(); if (id == originalId) { - int ordinal = EntityFlags.getOrdinal (EFlagType.NPC, EntityFlag.TypeSwap); - getUpdateMasks().unregisterSynced(ordinal); + int ordinal = EntityFlags.getOrdinal (EFlagType.NPC, EntityFlag.TypeSwap); + getUpdateMasks().unregisterSynced(ordinal); } - getUpdateMasks().register(EntityFlag.TypeSwap, id, id != originalId); + getUpdateMasks().register(EntityFlag.TypeSwap, id, id != originalId); return this; } @@ -783,10 +781,10 @@ public class NPC extends Entity { Location returnToSpawnLocation = getProperties().getSpawnLocation().transform(RandomFunction.random(-radius, radius+1), RandomFunction.random(-radius, radius+1), 0); int dist = (int) Location.getDistance(location, returnToSpawnLocation); int pathLimit = 14; - if (dist > pathLimit) { - Vector normalizedDir = Vector.betweenLocs(this.location, returnToSpawnLocation).normalized(); - returnToSpawnLocation = this.location.transform (normalizedDir.times(pathLimit)); - } + if (dist > pathLimit) { + Vector normalizedDir = Vector.betweenLocs(this.location, returnToSpawnLocation).normalized(); + returnToSpawnLocation = this.location.transform (normalizedDir.times(pathLimit)); + } return returnToSpawnLocation; } Location l = movementPath[movementIndex++]; diff --git a/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java b/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java index 50f93be3f..0e8b8a1fe 100644 --- a/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java +++ b/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java @@ -6,6 +6,7 @@ import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.world.map.zone.impl.WildernessZone; import core.game.world.map.RegionManager; +import core.game.world.repository.Repository; import java.util.ArrayList; import java.util.List; @@ -116,7 +117,7 @@ public class AggressiveBehavior { */ public List getPossibleTargets(Entity entity, int radius) { List targets = new ArrayList<>(20); - for (Player player : RegionManager.getLocalPlayers(entity, radius)) { + for (Player player : RegionManager.getLocalPlayers(entity.getLocation(), radius)) { if (canSelectTarget(entity, player)) { targets.add(player); } diff --git a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java index baacc117b..ebd086000 100644 --- a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java +++ b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java @@ -25,6 +25,7 @@ import core.game.world.repository.Repository; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * Holds and handles the NPC drop tables. @@ -111,9 +112,9 @@ public final class NPCDropTables { } return; } - announceIfRare(player, item); + announceIfRare(player, item); if(item.getId() == 6199 && player instanceof Player){ - player.sendMessage("A mystery box has fallen on the ground."); + player.sendMessage("A mystery box has fallen on the ground."); } sendDropMessage(player, npc.getId(), item); if (player == null) { @@ -144,7 +145,7 @@ public final class NPCDropTables { int itemId = item.getDefinition().isUnnoted() ? item.getId() : item.getNoteChange(); if (player != null && npc.getProperties().isMultiZone() && (item.getDefinition().isTradeable() || item.getName().endsWith("charm")) && player.getCommunication().getClan() != null && player.getCommunication().isLootShare() && player.getCommunication().getLootRequirement().ordinal() >= player.getCommunication().getClan().getLootRequirement().ordinal() && !player.getIronmanManager().isIronman()) { Player looter = player; - List players = RegionManager.getLocalPlayers(npc, 16); + List players = RegionManager.getLocalPlayers(npc.getLocation(), 16); List looters = new ArrayList<>(20); for (Player p : players) { if (p != null && p.getCommunication().getClan() != null && p.getCommunication().getClan() == player.getCommunication().getClan() && p.getCommunication().isLootShare() && p.getCommunication().getLootRequirement().ordinal() >= p.getCommunication().getClan().getLootRequirement().ordinal()) { diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index d21c591fc..cb94a83bd 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -131,22 +131,22 @@ public class Player extends Entity { public Boolean isAfkLogout; - private StorageState POHStorageState; + private StorageState POHStorageState; - public final Container POHStorageProxyContainer = new POHStorageProxyContainer(this); + public final Container POHStorageProxyContainer = new POHStorageProxyContainer(this); - public StorageState getPOHStorageState() { - if (POHStorageState == null) { - POHStorageState = new StorageState(this); - } - return POHStorageState; - } + public StorageState getPOHStorageState() { + if (POHStorageState == null) { + POHStorageState = new StorageState(this); + } + return POHStorageState; + } - public void setPOHStorageState(StorageState state) { - this.POHStorageState = state; - } + public void setPOHStorageState(StorageState state) { + this.POHStorageState = state; + } - /** + /** * The inventory. */ private final Container inventory = new Container(28).register(new InventoryListener(this)); @@ -854,10 +854,9 @@ public class Player extends Entity { getInterfaceManager().setChatbox(null); getPulseManager().clear(); getZoneMonitor().getZones().clear(); - getViewport().setCurrentPlane(RegionManager.forId(66666).getPlanes()[3]); playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); - playerFlags.setLastViewport(new RegionChunk[Viewport.CHUNK_SIZE][Viewport.CHUNK_SIZE]); + playerFlags.setLastViewport(new RegionChunk[13][13]); renderInfo.getLocalNpcs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); @@ -891,7 +890,7 @@ public class Player extends Entity { * @param login If the player is logging in. */ public void updateSceneGraph(boolean login) { - Region region = getViewport().getRegion(); + Region region = getLocation().getRegion(); if (region instanceof DynamicRegion || region == null && (region = RegionManager.forId(location.getRegionId())) instanceof DynamicRegion) { PacketRepository.send(BuildDynamicScene.class, new DynamicSceneContext(this, login)); } else { diff --git a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java index fb50ee051..dc3fcb107 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java +++ b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java @@ -1,9 +1,11 @@ package core.game.node.entity.player.info.login; +import core.Server; import core.game.component.Component; import core.game.node.entity.player.Player; import core.game.node.entity.player.link.emote.Emotes; import core.game.node.item.Item; +import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.net.packet.PacketRepository; import core.net.packet.context.InterfaceContext; @@ -37,270 +39,271 @@ import content.data.Quests; */ public final class LoginConfiguration { - /** - * The login plugins. - */ - private static final List> LOGIN_PLUGINS = new ArrayList<>(20); + /** + * The login plugins. + */ + private static final List> LOGIN_PLUGINS = new ArrayList<>(20); - /** - * The lobby pane component. - */ - private static final Component LOBBY_PANE = new Component(549); + /** + * The lobby pane component. + */ + private static final Component LOBBY_PANE = new Component(549); - /** - * The lobby interface component. - */ - private static final Component LOBBY_INTERFACE = new Component(378); + /** + * The lobby interface component. + */ + private static final Component LOBBY_INTERFACE = new Component(378); - /** - * The lobby message of the week models & constant to be set for auto selecting the models - */ - private static final int[] MESSAGE_MODEL = {15, 16, 17, 18, 19, 20, 21, 22, 23, 405, 447, 622, 623, 679, 715, 800}; - private static int messModel; + /** + * The lobby message of the week models & constant to be set for auto selecting the models + */ + private static final int[] MESSAGE_MODEL = {15, 16, 17, 18, 19, 20, 21, 22, 23, 405, 447, 622, 623, 679, 715, 800}; + private static int messModel; - /** - * Constructs a new {@Code LoginConfiguration} {@Code Object} - */ - public LoginConfiguration() { - /* - * empty. - */ - } + /** + * Constructs a new {@Code LoginConfiguration} {@Code Object} + */ + public LoginConfiguration() { + /* + * empty. + */ + } - /** - * Configures the lobby login. - * - * @param player The player. - */ - public static void configureLobby(Player player) { - player.updateSceneGraph(true); - if (!player.isArtificial() && player.getAttribute("tutorial:complete",false) && player.getAttribute("login_type", LoginType.NORMAL_LOGIN) != LoginType.RECONNECT_TYPE) { - sendLobbyScreen(player); - } else { - configureGameWorld(player); - } - } + /** + * Configures the lobby login. + * + * @param player The player. + */ + public static void configureLobby(Player player) { + player.updateSceneGraph(true); + if (!player.isArtificial() && player.getAttribute("tutorial:complete",false) && player.getAttribute("login_type", LoginType.NORMAL_LOGIN) != LoginType.RECONNECT_TYPE) { + sendLobbyScreen(player); + } else { + configureGameWorld(player); + } + } - /** - * Sends the lobby interface-related packets. - * - * @param player The player. - */ - public static void sendLobbyScreen(Player player) { - messModel = autoSelect(); - for(Player p : Repository.getLobbyPlayers()){ - if(p.getName().equals(player.getName())){ - p.clear(); - Repository.getLobbyPlayers().remove(p); - break; - } - } - Repository.getLobbyPlayers().add(player); - setInterfaceText(player, "Welcome to " + ServerConstants.SERVER_NAME, 378, 115); - setInterfaceText(player, getLastLogin(player), 378, 116); - setInterfaceText(player, "", 378, 37); - setInterfaceText(player, "Want to stay up to date with the latest news and updates? Join our discord by using the link on our website!", 378, 38); - setInterfaceText(player, "", 378, 39); - setInterfaceText(player, "Discord Invite", 378, 14); - setInterfaceText(player, "Discord Invite", 378, 129); - setInterfaceText(player, "You can gain more credits by reporting bugs and various other methods of contribution.", 378, 93); - setInterfaceText(player, player.getDetails().getCredits() + "", 378, 96); - setInterfaceText(player, "Credits", 378, 94); - setInterfaceText(player, "", 378, 229); - setInterfaceText(player, "Want to contribute to " + ServerConstants.SERVER_NAME + "? Visit the GitLab using the link on our website!", 378, 230); - setInterfaceText(player, "", 378, 231); - setInterfaceText(player, "Github", 378, 240); - setInterfaceText(player, GameWorld.getSettings().getMessage_string(), messModel, getMessageChild(messModel)); - player.getInterfaceManager().openWindowsPane(LOBBY_PANE); - player.getInterfaceManager().setOpened(LOBBY_INTERFACE); - PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 2, 378, true)); - PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 3, messModel, true));//UPDATE `configs` SET `value`=FLOOR(RAND()*(25-10)+10) WHERE key_="messageInterface" - player.getDetails().setLastLogin(System.currentTimeMillis()); - } + /** + * Sends the lobby interface-related packets. + * + * @param player The player. + */ + public static void sendLobbyScreen(Player player) { + messModel = autoSelect(); + for(Player p : Repository.getLobbyPlayers()){ + if(p.getName().equals(player.getName())){ + p.clear(); + Repository.getLobbyPlayers().remove(p); + break; + } + } + Repository.getLobbyPlayers().add(player); + setInterfaceText(player, "Welcome to " + ServerConstants.SERVER_NAME, 378, 115); + setInterfaceText(player, getLastLogin(player), 378, 116); + setInterfaceText(player, "", 378, 37); + setInterfaceText(player, "Want to stay up to date with the latest news and updates? Join our discord by using the link on our website!", 378, 38); + setInterfaceText(player, "", 378, 39); + setInterfaceText(player, "Discord Invite", 378, 14); + setInterfaceText(player, "Discord Invite", 378, 129); + setInterfaceText(player, "You can gain more credits by reporting bugs and various other methods of contribution.", 378, 93); + setInterfaceText(player, player.getDetails().getCredits() + "", 378, 96); + setInterfaceText(player, "Credits", 378, 94); + setInterfaceText(player, "", 378, 229); + setInterfaceText(player, "Want to contribute to " + ServerConstants.SERVER_NAME + "? Visit the GitLab using the link on our website!", 378, 230); + setInterfaceText(player, "", 378, 231); + setInterfaceText(player, "Github", 378, 240); + setInterfaceText(player, GameWorld.getSettings().getMessage_string(), messModel, getMessageChild(messModel)); + player.getInterfaceManager().openWindowsPane(LOBBY_PANE); + player.getInterfaceManager().setOpened(LOBBY_INTERFACE); + PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 2, 378, true)); + PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 3, messModel, true));//UPDATE `configs` SET `value`=FLOOR(RAND()*(25-10)+10) WHERE key_="messageInterface" + player.getDetails().setLastLogin(System.currentTimeMillis()); + } - /** - * Configures the game world. - * - * @param player The player. - */ - public static void configureGameWorld(final Player player) { - sendGameConfiguration(player); - Repository.getLobbyPlayers().remove(player); - player.setPlaying(true); - UpdateSequence.getRenderablePlayers().add(player); - RegionManager.move(player); - player.getMusicPlayer().init(); - player.updateAppearance(); - player.getPlayerFlags().setUpdateSceneGraph(true); - player.getPacketDispatch().sendInterfaceConfig(226, 1, true); + /** + * Configures the game world. + * + * @param player The player. + */ + public static void configureGameWorld(final Player player) { + sendGameConfiguration(player); + Repository.getLobbyPlayers().remove(player); + player.setPlaying(true); + UpdateSequence.getRenderablePlayers().add(player); + RegionManager.move(player, ServerConstants.START_LOCATION, player.getLocation()); + player.getMusicPlayer().init(); + player.updateAppearance(); + player.getPlayerFlags().setUpdateSceneGraph(true); + player.getPacketDispatch().sendInterfaceConfig(226, 1, true); - if(player.getGlobalData().getTestStage() == 3 && !player.getEmoteManager().isUnlocked(Emotes.SAFETY_FIRST)){ - player.getEmoteManager().unlock(Emotes.SAFETY_FIRST); - } + if (player.getGlobalData().getTestStage() == 3 && !player.getEmoteManager().isUnlocked(Emotes.SAFETY_FIRST)) { + //TODO: port this to save version later. when you do, please also do this for the Explore emote, which has a similar problem (e.g. player_name.json has this). + player.getEmoteManager().unlock(Emotes.SAFETY_FIRST); + } - for (Item item : player.getEquipment().toArray()) { - //Run equip hooks for all items equipped on login. - //We should have already been doing this. - //Frankly, I don't even want to imagine the number of bugs us *not* doing this has caused. - if (item == null) continue; - player.getEquipment().remove(item); - if (!InteractionListeners.run(item.getId(), player, item, true) || !player.getEquipment().add(item, true, false)) { - player.sendMessage(colorize("%RAs you can no longer wear " + item.getName() + ", it has been unequipped.")); - addItemOrBank(player, item.getId(), item.getAmount()); - } - } + for (Item item : player.getEquipment().toArray()) { + //Run equip hooks for all items equipped on login. + //We should have already been doing this. + //Frankly, I don't even want to imagine the number of bugs us *not* doing this has caused. + if (item == null) continue; + player.getEquipment().remove(item); + if (!InteractionListeners.run(item.getId(), player, item, true) || !player.getEquipment().add(item, true, false)) { + player.sendMessage(colorize("%RAs you can no longer wear " + item.getName() + ", it has been unequipped.")); + addItemOrBank(player, item.getId(), item.getAmount()); + } + } - SpellBookManager.SpellBook currentSpellBook = SpellBookManager.SpellBook.forInterface(player.getSpellBookManager().getSpellBook()); - if (currentSpellBook == SpellBookManager.SpellBook.ANCIENT && !hasRequirement(player, Quests.DESERT_TREASURE)) { - player.sendMessage(colorize("%RAs you can no longer use Ancient Magic, you have been set back to Modern.")); - player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); - } else if (currentSpellBook == SpellBookManager.SpellBook.LUNAR && !hasRequirement(player, Quests.LUNAR_DIPLOMACY)) { - player.sendMessage(colorize("%RAs you can no longer use Lunar Magic, you have been set back to Modern.")); - player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); - } - player.getSpellBookManager().update(player); + SpellBookManager.SpellBook currentSpellBook = SpellBookManager.SpellBook.forInterface(player.getSpellBookManager().getSpellBook()); + if (currentSpellBook == SpellBookManager.SpellBook.ANCIENT && !hasRequirement(player, Quests.DESERT_TREASURE)) { + player.sendMessage(colorize("%RAs you can no longer use Ancient Magic, you have been set back to Modern.")); + player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); + } else if (currentSpellBook == SpellBookManager.SpellBook.LUNAR && !hasRequirement(player, Quests.LUNAR_DIPLOMACY)) { + player.sendMessage(colorize("%RAs you can no longer use Lunar Magic, you have been set back to Modern.")); + player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); + } + player.getSpellBookManager().update(player); - // 1050 is checked client-side for making piety/chivalry disallowed sfx, likely due to the minigame requirement. - // Set it here unconditionally until the minigame is implemented. - if (hasRequirement(player, Quests.KINGS_RANSOM, false)) { - setVarbit(player, 3909, 8, false); - } - if(ServerConstants.RULES_AND_INFO_ENABLED) - RulesAndInfo.openFor(player); - /*if (TutorialSession.getExtension(player).getStage() != 73) { - TutorialStage.load(player, TutorialSession.getExtension(player).getStage(), true); - }*/ - } + // 1050 is checked client-side for making piety/chivalry disallowed sfx, likely due to the minigame requirement. + // Set it here unconditionally until the minigame is implemented. + if (hasRequirement(player, Quests.KINGS_RANSOM, false)) { + setVarbit(player, 3909, 8, false); + } + if(ServerConstants.RULES_AND_INFO_ENABLED) + RulesAndInfo.openFor(player); + /*if (TutorialSession.getExtension(player).getStage() != 73) { + TutorialStage.load(player, TutorialSession.getExtension(player).getStage(), true); + }*/ + } - /** - * Sends the game configuration packets. - * - * @param player The player to send to. - */ - public static void sendGameConfiguration(final Player player) { - player.getInterfaceManager().openWindowsPane(new Component(player.getInterfaceManager().isResizable() ? 746 : 548)); - player.getInterfaceManager().openChatbox(137); - player.getInterfaceManager().openDefaultTabs(); - welcome(player); - config(player); - for (Plugin plugin : LOGIN_PLUGINS) { - try { - plugin.newInstance(player); - } catch (Throwable e) { - e.printStackTrace(); - } - } - player.getAppearance().sync(); - } + /** + * Sends the game configuration packets. + * + * @param player The player to send to. + */ + public static void sendGameConfiguration(final Player player) { + player.getInterfaceManager().openWindowsPane(new Component(player.getInterfaceManager().isResizable() ? 746 : 548)); + player.getInterfaceManager().openChatbox(137); + player.getInterfaceManager().openDefaultTabs(); + welcome(player); + config(player); + for (Plugin plugin : LOGIN_PLUGINS) { + try { + plugin.newInstance(player); + } catch (Throwable e) { + e.printStackTrace(); + } + } + player.getAppearance().sync(); + } - /** - * Method used to welcome the player. - * - * @param player the player. Fullscreen mode Object id: - */ - public static final void welcome(final Player player) { - if (player.isArtificial()) { - return; - } - player.getPacketDispatch().sendMessage("Welcome to " + ServerConstants.SERVER_NAME + "."); - if (player.getDetails().isMuted()) { - player.getPacketDispatch().sendMessage("You are muted."); - player.getPacketDispatch().sendMessage("To prevent further mutes please read the rules."); - } - } + /** + * Method used to welcome the player. + * + * @param player the player. Fullscreen mode Object id: + */ + public static final void welcome(final Player player) { + if (player.isArtificial()) { + return; + } + player.getPacketDispatch().sendMessage("Welcome to " + ServerConstants.SERVER_NAME + "."); + if (player.getDetails().isMuted()) { + player.getPacketDispatch().sendMessage("You are muted."); + player.getPacketDispatch().sendMessage("To prevent further mutes please read the rules."); + } + } - /** - * Method used to configure all possible settings for the player. - * - * @param player the player. - */ - public static final void config(final Player player) { - if(!player.isArtificial()) - log(LoginConfiguration.class, Log.INFO, "configuring player " + player.getUsername()); - player.getInventory().refresh(); - player.getEquipment().refresh(); - player.getSkills().refresh(); - player.getSkills().configure(); - player.getSettings().update(); - player.getInteraction().setDefault(); - player.getPacketDispatch().sendRunEnergy(); - player.getFamiliarManager().login(); - player.getInterfaceManager().openDefaultTabs(); - setInterfaceText(player, "Friends List - " + ServerConstants.SERVER_NAME + " " + GameWorld.getSettings().getWorldId(), 550, 3); - setInterfaceText(player, "When you have finished playing " + ServerConstants.SERVER_NAME + ", always use the button below to logout safely.", 182, 0); - player.getQuestRepository().syncronizeTab(player); - player.getInterfaceManager().close(); - player.getEmoteManager().refresh(); - player.getInterfaceManager().openInfoBars(); - if(!player.isArtificial()) - log(LoginConfiguration.class, Log.INFO, "finished configuring player " + player.getUsername()); - } + /** + * Method used to configure all possible settings for the player. + * + * @param player the player. + */ + public static final void config(final Player player) { + if(!player.isArtificial()) + log(LoginConfiguration.class, Log.INFO, "configuring player " + player.getUsername()); + player.getInventory().refresh(); + player.getEquipment().refresh(); + player.getSkills().refresh(); + player.getSkills().configure(); + player.getSettings().update(); + player.getInteraction().setDefault(); + player.getPacketDispatch().sendRunEnergy(); + player.getFamiliarManager().login(); + player.getInterfaceManager().openDefaultTabs(); + setInterfaceText(player, "Friends List - " + ServerConstants.SERVER_NAME + " " + GameWorld.getSettings().getWorldId(), 550, 3); + setInterfaceText(player, "When you have finished playing " + ServerConstants.SERVER_NAME + ", always use the button below to logout safely.", 182, 0); + player.getQuestRepository().syncronizeTab(player); + player.getInterfaceManager().close(); + player.getEmoteManager().refresh(); + player.getInterfaceManager().openInfoBars(); + if(!player.isArtificial()) + log(LoginConfiguration.class, Log.INFO, "finished configuring player " + player.getUsername()); + } - /** - * Gets the message child for the inter id. - * @notice GameSettings.kt contains the list of what these are - * @param interfaceId The interface id. - * @return The child id. - */ - public static int getMessageChild(int interfaceId) { - if (interfaceId == 622) { - return 8; - } else if (interfaceId == 16) { - return 6; - } else if (interfaceId == 20 || interfaceId == 623) { - return 5; - } else if (interfaceId == 15 || interfaceId == 18 || interfaceId == 19 || interfaceId == 21 || interfaceId == 22 || interfaceId == 447 || interfaceId == 405) { - return 4; - } else if (interfaceId == 17 || interfaceId == 23 || interfaceId == 800) { - return 3; - } else if (interfaceId == 715) { - return 2; - } else if (interfaceId == 679) { - return 1; - } - return 0; - } + /** + * Gets the message child for the inter id. + * @notice GameSettings.kt contains the list of what these are + * @param interfaceId The interface id. + * @return The child id. + */ + public static int getMessageChild(int interfaceId) { + if (interfaceId == 622) { + return 8; + } else if (interfaceId == 16) { + return 6; + } else if (interfaceId == 20 || interfaceId == 623) { + return 5; + } else if (interfaceId == 15 || interfaceId == 18 || interfaceId == 19 || interfaceId == 21 || interfaceId == 22 || interfaceId == 447 || interfaceId == 405) { + return 4; + } else if (interfaceId == 17 || interfaceId == 23 || interfaceId == 800) { + return 3; + } else if (interfaceId == 715) { + return 2; + } else if (interfaceId == 679) { + return 1; + } + return 0; + } - /** - * Sets a random interface id for the "message of the week" models - */ - private final static int autoSelect() { - boolean contains = IntStream.of(MESSAGE_MODEL).anyMatch(x -> x == GameWorld.getSettings().getMessage_model()); - return contains ? GameWorld.getSettings().getMessage_model():MESSAGE_MODEL[new Random().nextInt(MESSAGE_MODEL.length)]; - } + /** + * Sets a random interface id for the "message of the week" models + */ + private final static int autoSelect() { + boolean contains = IntStream.of(MESSAGE_MODEL).anyMatch(x -> x == GameWorld.getSettings().getMessage_model()); + return contains ? GameWorld.getSettings().getMessage_model():MESSAGE_MODEL[new Random().nextInt(MESSAGE_MODEL.length)]; + } - /** - * Gets the last login string for the lobby. - * - * @param player the player. - * @return the last login. - */ - public static String getLastLogin(Player player) { - player.getPacketDispatch().sendLastLoginInfo(); - String string = "You last logged in @timeAgo from:"; - long time = player.getDetails().getLastLogin(); - Date lastLogin = new Date(time); - Date current = new Date(); - long diff = current.getTime() - lastLogin.getTime(); - int days = (int) TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS); - if (days < 1) { - string = string.replace("@timeAgo", "earlier today"); - } else if (days == 1) { - string = string.replace("@timeAgo", "yesterday"); - } else { - string = string.replace("@timeAgo", days + " days ago"); - } - return string; - } + /** + * Gets the last login string for the lobby. + * + * @param player the player. + * @return the last login. + */ + public static String getLastLogin(Player player) { + player.getPacketDispatch().sendLastLoginInfo(); + String string = "You last logged in @timeAgo from:"; + long time = player.getDetails().getLastLogin(); + Date lastLogin = new Date(time); + Date current = new Date(); + long diff = current.getTime() - lastLogin.getTime(); + int days = (int) TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS); + if (days < 1) { + string = string.replace("@timeAgo", "earlier today"); + } else if (days == 1) { + string = string.replace("@timeAgo", "yesterday"); + } else { + string = string.replace("@timeAgo", days + " days ago"); + } + return string; + } - /** - * Gets the loginPlugins. - * - * @return The loginPlugins. - */ - public static List> getLoginPlugins() { - return LOGIN_PLUGINS; - } + /** + * Gets the loginPlugins. + * + * @return The loginPlugins. + */ + public static List> getLoginPlugins() { + return LOGIN_PLUGINS; + } } diff --git a/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt b/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt index 351c8dc34..ffac22bf9 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt +++ b/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt @@ -350,7 +350,6 @@ class PlayerSaver (val player: Player){ globalData.put("zafTime",player.savedData.globalData.zafTime.toString()) globalData.put("fritzGlass",player.savedData.globalData.isFritzGlass) globalData.put("wydinEmployee",player.savedData.globalData.isWydinEmployee) - globalData.put("draynorRecording",player.savedData.globalData.isDraynorRecording) globalData.put("geTutorial",player.savedData.globalData.isGeTutorial) globalData.put("essenceTeleporter",player.savedData.globalData.essenceTeleporter.toString()) globalData.put("recoilDamage",player.savedData.globalData.recoilDamage.toString()) diff --git a/Server/src/main/core/game/node/entity/player/link/GlobalData.java b/Server/src/main/core/game/node/entity/player/link/GlobalData.java index 62873b245..3565b4309 100644 --- a/Server/src/main/core/game/node/entity/player/link/GlobalData.java +++ b/Server/src/main/core/game/node/entity/player/link/GlobalData.java @@ -94,11 +94,6 @@ public final class GlobalData { */ private boolean wydinEmployee; - /** - * Represents if the draynor recording has been seen. - */ - private boolean draynorRecording; - /** * Represents if the ge tutorial has been done. */ @@ -313,7 +308,6 @@ public final class GlobalData { zafTime = Long.parseLong(data.get("zafTime").toString()); fritzGlass = (boolean) data.get("fritzGlass"); wydinEmployee = (boolean) data.get("wydinEmployee"); - draynorRecording = (boolean) data.get("draynorRecording"); geTutorial = (boolean) data.get("geTutorial"); essenceTeleporter = Integer.parseInt( data.get("essenceTeleporter").toString()); recoilDamage = Integer.parseInt( data.get("recoilDamage").toString()); @@ -661,22 +655,6 @@ public final class GlobalData { return zafTime; } - /** - * Gets the draynorRecording. - * @return The draynorRecording. - */ - public boolean isDraynorRecording() { - return draynorRecording; - } - - /** - * Sets the draynorRecording. - * @param draynorRecording The draynorRecording to set. - */ - public void setDraynorRecording(boolean draynorRecording) { - this.draynorRecording = draynorRecording; - } - /** * Gets the wydinEmployee. * @return The wydinEmployee. diff --git a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java index de6bb8233..8f2557652 100644 --- a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java +++ b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java @@ -2,6 +2,7 @@ package core.game.node.entity.player.link; import core.game.node.entity.player.Player; import core.game.node.scenery.Scenery; +import core.game.world.repository.Repository; import core.tools.Log; import core.game.system.task.Pulse; import core.game.world.GameWorld; @@ -50,9 +51,9 @@ public final class PacketDispatch { PacketRepository.send(Config.class, new ConfigContext(player, index, value)); } - public void sendVarcUpdate(short index, int value) { - PacketRepository.send(VarcUpdate.class, new VarcUpdateContext(player, index, value)); - } + public void sendVarcUpdate(short index, int value) { + PacketRepository.send(VarcUpdate.class, new VarcUpdateContext(player, index, value)); + } /** * Send a game message. @@ -312,7 +313,7 @@ public final class PacketDispatch { * @param id The animation id. */ public void sendAnimation(int id) { - player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id)); + player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id)); } /** @@ -321,7 +322,7 @@ public final class PacketDispatch { * @param delay The animation delay. */ public void sendAnimation(int id, int delay) { - player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id, delay)); + player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id, delay)); } /** @@ -329,7 +330,7 @@ public final class PacketDispatch { * @param id The graphic id. */ public void sendGraphic(int id) { - player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id)); + player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id)); } /** @@ -395,7 +396,7 @@ public final class PacketDispatch { * @param height The graphic height. */ public void sendGraphic(int id, int height) { - player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id, height)); + player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id, height)); } public void sendVarClient(int id, int value, boolean cs2) { PacketRepository.send(Config.class, new ConfigContext(player, id, value, cs2)); diff --git a/Server/src/main/core/game/node/entity/player/link/emote/Emotes.java b/Server/src/main/core/game/node/entity/player/link/emote/Emotes.java index 2bda2ca57..40ba72ab1 100644 --- a/Server/src/main/core/game/node/entity/player/link/emote/Emotes.java +++ b/Server/src/main/core/game/node/entity/player/link/emote/Emotes.java @@ -106,7 +106,7 @@ public enum Emotes { @Override public void play(Player player) { if(player.getLocation().getRegionId() == 13206 && !player.getAttribute("mistag-greeted", false)) { - RegionManager.getLocalNpcs(player).forEach(npc -> { + RegionManager.getLocalNPCs(player.getLocation()).forEach(npc -> { if (npc.getId() == 2084 && npc.getLocation().withinDistance(player.getLocation(), 3) && player.getQuestRepository().getQuest(Quests.THE_LOST_TRIBE).getStage(player) == 45) { player.getDialogueInterpreter().open(2084,npc,"greeting"); player.setAttribute("/save:mistag-greeted",true); @@ -422,4 +422,4 @@ public enum Emotes { return lockedMessage; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java index 8dcdf8265..4f2780a7b 100644 --- a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java +++ b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java @@ -113,14 +113,17 @@ public final class Prayer { } if (player.getProperties().isMultiZone()) { @SuppressWarnings("rawtypes") - List targets = null; + List targets; if (killer instanceof NPC) { - targets = RegionManager.getSurroundingNPCs(player, player, killer); + targets = RegionManager.getLocalNPCs(player.getLocation(), 1); } else { - targets = RegionManager.getSurroundingPlayers(player, player, killer); + targets = RegionManager.getLocalPlayers(player.getLocation(), 1); } for (Object o : targets) { Entity entity = (Entity) o; + if (entity == player) { + continue; + } if (entity.isAttackable(player, CombatStyle.MAGIC, false)) { entity.getImpactHandler().manualHit(player, 1 + RandomFunction.randomize(maximum), HitsplatType.NORMAL); } diff --git a/Server/src/main/core/game/node/entity/skill/Skills.java b/Server/src/main/core/game/node/entity/skill/Skills.java index 06a978589..5b8b30b5c 100644 --- a/Server/src/main/core/game/node/entity/skill/Skills.java +++ b/Server/src/main/core/game/node/entity/skill/Skills.java @@ -252,9 +252,9 @@ public final class Skills { staticLevels[slot] = newLevel; if (entity instanceof Player) { - player.updateAppearance(); - LevelUp.levelup(player, slot, amount); - updateCombatLevel(); + player.updateAppearance(); + LevelUp.levelup(player, slot, amount); + updateCombatLevel(); } } if (entity instanceof Player) { @@ -303,11 +303,11 @@ public final class Skills { mod *= 1.5; } //Grand Exchange region XP boost. - if(entity.getViewport().getRegion().getRegionId() == 12598){ + if(entity.getLocation().getRegion().getRegionId() == 12598){ mod += 1.5; } // Pest control, XP halved during the game - if (entity.getViewport().getRegion().getRegionId() == 10536) { + if (entity.getLocation().getRegion().getRegionId() == 10536) { mod *= .5; } if (SystemManager.getSystemConfig().isDoubleExp()) { diff --git a/Server/src/main/core/game/node/item/GroundItemManager.java b/Server/src/main/core/game/node/item/GroundItemManager.java index 464dbbe25..98bc91ee3 100644 --- a/Server/src/main/core/game/node/item/GroundItemManager.java +++ b/Server/src/main/core/game/node/item/GroundItemManager.java @@ -3,6 +3,7 @@ package core.game.node.item; import core.game.node.entity.player.Player; import core.game.world.GameWorld; import core.game.world.map.Location; +import core.game.world.map.RegionChunk; import core.game.world.map.RegionManager; import core.game.world.update.flag.chunk.ItemUpdateFlag; import core.net.packet.PacketRepository; @@ -81,7 +82,7 @@ public final class GroundItemManager { item.getPlugin().remove(item.getDropper(), item, ItemPlugin.DROP); } item.setRemoved(false); - RegionManager.getRegionPlane(item.getLocation()).add(item); + RegionManager.getRegionChunk(item.getLocation()).add(item); if (GROUND_ITEMS.add(item)) { return item; } @@ -97,7 +98,7 @@ public final class GroundItemManager { return null; } GROUND_ITEMS.remove(item); - RegionManager.getRegionPlane(item.getLocation()).remove(item); + RegionManager.getRegionChunk(item.getLocation()).remove(item); if (item.isAutoSpawn()) { item.respawn(); } @@ -112,7 +113,18 @@ public final class GroundItemManager { * @return The ground item, or {@code null} if the ground item wasn't found. */ public static GroundItem get(int itemId, Location location, Player player) { - return RegionManager.getRegionPlane(location).getItem(itemId, location, player); + RegionChunk chunk = RegionManager.getRegionChunk(location); + for (GroundItem item : chunk.getItems()) { + if (item.getId() == itemId && location.equals(item.getLocation()) && !item.isRemoved()) { + if (!item.isPrivate()) { + return item; + } + if (player != null && item.droppedBy(player)) { + return item; + } + } + } + return null; } /** @@ -155,7 +167,7 @@ public final class GroundItemManager { } } if (!item.isRemoved()) { - RegionManager.getRegionPlane(item.getLocation()).remove(item); + RegionManager.getRegionChunk(item.getLocation()).remove(item); } } else if (!item.isRemainPrivate() && item.getDecayTime() - GameWorld.getTicks() == 100) { RegionManager.getRegionChunk(item.getLocation()).flag(new ItemUpdateFlag(item, ItemUpdateFlag.CONSTRUCT_TYPE)); diff --git a/Server/src/main/core/game/node/scenery/SceneryBuilder.java b/Server/src/main/core/game/node/scenery/SceneryBuilder.java index 3dac14bf0..304403930 100644 --- a/Server/src/main/core/game/node/scenery/SceneryBuilder.java +++ b/Server/src/main/core/game/node/scenery/SceneryBuilder.java @@ -23,7 +23,7 @@ public final class SceneryBuilder { /** * Replaces a scenery. * - * @param remove The object to remove. + * @param remove The object to remove. * @param construct The object to add. * @return {@code True} if successful. */ @@ -34,9 +34,9 @@ public final class SceneryBuilder { /** * Replaces a scenery. * - * @param remove The object to remove. + * @param remove The object to remove. * @param construct The object to add. - * @param clip If clipping should be adjusted. + * @param clip If clipping should be adjusted. * @return {@code True} if successful. */ public static boolean replace(Scenery remove, Scenery construct, boolean clip, boolean permanent) { @@ -72,8 +72,8 @@ public final class SceneryBuilder { /** * Replaces the object client sided alone. * - * @param remove The object to remove. - * @param construct The object to replace with. + * @param remove The object to remove. + * @param construct The object to replace with. * @param restoreTicks The restoration ticks. * @return {@code True} if successful. */ @@ -94,8 +94,8 @@ public final class SceneryBuilder { /** * Replaces a scenery temporarily. * - * @param remove The object to remove. - * @param construct The object to add. + * @param remove The object to remove. + * @param construct The object to add. * @param restoreTicks The amount of ticks before the object gets restored. * @return {@code True} if successful. */ @@ -106,8 +106,8 @@ public final class SceneryBuilder { /** * Replaces a scenery temporarily. * - * @param remove The object to remove. - * @param construct The object to add. + * @param remove The object to remove. + * @param construct The object to add. * @param restoreTicks The amount of ticks before the object gets restored. * @return {@code True} if successful. */ @@ -164,7 +164,7 @@ public final class SceneryBuilder { * * @param object The object to add. * @param ticks The amount of ticks this object should last for (-1 for - * permanent). + * permanent). * @return {@code True} if successful. */ public static Constructed add(Scenery object, int ticks, final GroundItem... items) { @@ -189,29 +189,6 @@ public final class SceneryBuilder { return constructed; } - /** - * Removes all objects within a box - * @param objectId - the object id to remove - * @param southWest - * @param northEast - * @return - */ - public static boolean removeAll(int objectId, Location southWest, Location northEast) { - if (southWest.getX() > northEast.getX() || southWest.getY() > northEast.getY()) - return false; - - int differenceX = northEast.getX() - southWest.getX(); - int differenceY = northEast.getY() - southWest.getY(); - - for (int x = 0; x <= differenceX; x++) { - for (int y = 0; y <= differenceY; y++){ - Scenery object = new Scenery(objectId, Location.create(southWest.getX() + x, southWest.getY() + y, southWest.getZ())); - remove(object); - } - } - return true; - } - /** * Removes a scenery. * @@ -234,7 +211,7 @@ public final class SceneryBuilder { /** * Removes a scenery. * - * @param object the object. + * @param object the object. * @param respawnTicks the respawn ticks. * @return {@code True}if removed. */ diff --git a/Server/src/main/core/game/system/command/rottenpotato/RottenPotatoExtraDialogue.kt b/Server/src/main/core/game/system/command/rottenpotato/RottenPotatoExtraDialogue.kt index 5528ecf20..8281ef994 100644 --- a/Server/src/main/core/game/system/command/rottenpotato/RottenPotatoExtraDialogue.kt +++ b/Server/src/main/core/game/system/command/rottenpotato/RottenPotatoExtraDialogue.kt @@ -62,7 +62,7 @@ class RottenPotatoExtraDialogue(player: Player? = null) : core.game.dialogue.Dia end() sendInputDialogue(player, InputType.STRING_LONG,"Enter the chat message:"){ value -> val msg = value as String - RegionManager.getLocalNpcs(player).forEach { + RegionManager.getLocalNPCs(player.location).forEach { it.sendChat(msg) } } @@ -71,7 +71,7 @@ class RottenPotatoExtraDialogue(player: Player? = null) : core.game.dialogue.Dia //Kill all nearby NPCs 5 -> { end() - RegionManager.getLocalNpcs(player).forEach { + RegionManager.getLocalNPCs(player.location).forEach { it.finalizeDeath(player) } } diff --git a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt index 25ef32fef..780319bc3 100644 --- a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt @@ -31,7 +31,7 @@ import core.tools.Log import core.game.node.entity.player.info.Rights import core.game.node.entity.skill.Skills import core.game.world.map.Location -import core.game.world.map.RegionManager.getLocalEntitys +import core.game.world.map.RegionManager import core.game.world.repository.Repository import org.json.simple.JSONArray import kotlin.collections.set @@ -43,6 +43,7 @@ import content.global.activity.penguinhns.PenguinManager.Companion.spawner import content.global.activity.penguinhns.PenguinManager.Companion.tagMapping import content.global.activity.penguinhns.PenguinManager.Companion.updateStoreFile import core.ServerStore.Companion.toJSONArray +import core.game.world.map.RegionManager.getLocalEntities import org.rs09.consts.NPCs @Initializable @@ -120,7 +121,7 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { return@define } - define("cs2", Privilege.ADMIN, "::cs2 id args", "Allows you to call arbitrary cs2 scripts during runtime") {player, args -> + define("cs2", Privilege.ADMIN, "::cs2 id args", "Allows you to call arbitrary cs2 scripts during runtime") {player, args -> var scriptArgs = ArrayList() if (args.size == 2) { runcs2(player, args[1].toIntOrNull() ?: return@define) @@ -156,7 +157,7 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { } define("region", Privilege.STANDARD, "", "Prints your current Region ID.") {player, args -> - sendMessage(player, "Region ID: ${player.viewport.region.regionId}") + sendMessage(player, "Region ID: ${player.location.regionId}") } define("spellbook", Privilege.ADMIN, "::spellbook book ID (0 = MODERN, 1 = ANCIENTS, 2 = LUNARS)", "Swaps your spellbook to the given book ID."){player, args -> @@ -376,6 +377,28 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { player.dialogueInterpreter.sendDialogues(player, id, "Expression ID: $id") } + define("tileinfo", Privilege.ADMIN, "::tileinfo", "Prints out your current tile's clipping flags and entities on it.") { player, args -> + if (args.size != 1) reject(player, "::tileinfo doesn't take arguments.") + sendMessage(player, "Location: ${player.location}") + sendMessage(player, "Clipping: ${RegionManager.getClippingFlag(player.location, false)}") + sendMessage(player, "Projectile: ${RegionManager.getClippingFlag(player.location, true)}") + sendMessage(player, "${player.location.chunk.players.size} players and ${player.location.chunk.npcs.size} npcs on this chunk.") + sendMessage(player, "Entities on this tile:") + for (p in RegionManager.getLocalPlayers(player.location, 0)) { + sendMessage(p, " player ${player.username}") + } + for (npc in RegionManager.getLocalNPCs(player.location, 0)) { + sendMessage(player, " npc ${npc.name}") + } + sendMessage(player, "Entities within render distance:") + for (p in RegionManager.getLocalPlayers(player.location)) { + sendMessage(p, " player ${player.username} at ${player.location}") + } + for (npc in RegionManager.getLocalNPCs(player.location)) { + sendMessage(player, " npc ${npc.name} at ${npc.location}}") + } + } + define("timers", Privilege.ADMIN, "::timers", "Print out timers") { player, args -> player.sendMessage("Active timers:") for(timer in player.timers.activeTimers) { @@ -466,7 +489,7 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { spawnedOrdinals.forEach { val peng = Penguin.values()[it] - val nearNPCs = getLocalEntitys(peng.location,1) + val nearNPCs = getLocalEntities(peng.location,1) nearNPCs.forEach { npc -> if (npc.id in penguinNPCs) { poofClear(npc as NPC) @@ -507,6 +530,5 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { val pengCoords = peng.location player.debug("Penguin spawned at:$pengCoords") } - - } + } } diff --git a/Server/src/main/core/game/system/command/sets/FunCommandSet.kt b/Server/src/main/core/game/system/command/sets/FunCommandSet.kt index 05b59c153..c65db80df 100644 --- a/Server/src/main/core/game/system/command/sets/FunCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/FunCommandSet.kt @@ -27,7 +27,6 @@ import org.rs09.consts.Sounds import java.awt.HeadlessException import java.awt.Toolkit import java.awt.datatransfer.StringSelection -import kotlin.streams.toList @Initializable class FunCommandSet : CommandSet(Privilege.ADMIN) { @@ -99,7 +98,7 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) { if (args.size < 2) { reject(player, "Syntax error: ::npcanim ") } - npcs = RegionManager.getLocalNpcs(player.location, 10) + npcs = RegionManager.getLocalNPCs(player.location, 10) for (n in npcs) { n.lock(6) n.faceTemporary(player, 6) @@ -356,10 +355,13 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) { if (args.size != 2) reject(player, "Usage: ::barrage radius[max = 50]") val radius = if (args[1].toInt() > 50) 50 else args[1].toInt() - val nearbyPlayers = RegionManager.getLocalPlayers(player, radius).stream().filter { p: Player -> p.username != player.username }.toList() + val nearbyPlayers = RegionManager.getLocalPlayers(player.location, radius) animate(player, 1978) playGlobalAudio(player.location, Sounds.ICE_CAST_171) for (p in nearbyPlayers) { + if (p.name == player.name) { + continue + } playGlobalAudio(p.location, Sounds.ICE_BARRAGE_IMPACT_168, 20) val impactAmount = if (p.skills.lifepoints < 10 ) 0 else RandomFunction.getRandom(3) impact(p, impactAmount, ImpactHandler.HitsplatType.NORMAL) diff --git a/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt b/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt index 281491ae2..56ffc13df 100644 --- a/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt @@ -93,7 +93,7 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){ */ define("loc", Privilege.STANDARD, "", "Prints quite a lot of information about your current location."){ player, _-> val l = player.location - val r = player.viewport.region + val r = l.region var obj: Scenery? = null notify(player,"Absolute: " + l + ", regional: [" + l.localX + ", " + l.localY + "], chunk: [" + l.chunkOffsetX + ", " + l.chunkOffsetY + "], flag: [" + RegionManager.isTeleportPermitted(l) + ", " + RegionManager.getClippingFlag(l) + ", " + RegionManager.isLandscape(l) + "].") notify(player,"Region: [id=" + l.regionId + ", active=" + r.isActive + ", instanced=" + (r is DynamicRegion) + "], obj=" + RegionManager.getObject(l) + ".") diff --git a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt index 468bdaf96..0e2151425 100644 --- a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt @@ -3,13 +3,17 @@ package core.game.system.command.sets import core.api.log import core.api.sendMessage import core.cache.Cache -import core.game.node.scenery.Scenery -import core.game.node.scenery.SceneryBuilder import core.game.node.entity.npc.NPC import core.game.node.item.Item +import core.game.node.scenery.Constructed +import core.game.node.scenery.Scenery +import core.game.node.scenery.SceneryBuilder import core.game.system.command.CommandPlugin -import core.plugin.Initializable import core.game.system.command.Privilege +import core.game.world.map.RegionManager +import core.game.world.map.RegionManager.getObject +import core.game.world.map.RegionManager.getRegionChunk +import core.plugin.Initializable import core.tools.Log import java.awt.Toolkit import java.awt.datatransfer.StringSelection @@ -142,5 +146,55 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ } } } + + define("removeobject", Privilege.ADMIN, "::removeobject", "Removes the first scenery at your current coordinates (the meaning of 'the first' is currently arbitrary, do not use this in production)") { player, args -> + if (args.size != 1) reject(player, "::removeobject doesn't support arguments") + val obj = getObject(player.location) + if (obj == null) { + sendMessage(player, "All ten objects on the tile were null.") + return@define + } + sendMessage(player, "The first object found on the tile was ${obj.id}; it will now be removed.") + SceneryBuilder.remove(obj) + } + + define("objects", Privilege.STANDARD, "::objects", "Prints a list of all ten sceneries at your current coordinates") { player, args -> + if (args.size != 1) reject(player, "::objects doesn't support arguments") + val chunk = getRegionChunk(player.location) + val region = RegionManager.forId(player.location.regionId) + fun dump(label: String, objects: List) { + sendMessage(player, "--- $label ---") + val nulls = ArrayList(10) + for (i in 0 until objects.size) { + val o = objects[i] + if (o == null) { + nulls.add(i) + } else { + val c = if (o is Constructed) "C" else "" + val r = if (o.isRenderable) "R" else "" + val a = if (o.isActive) "A" else "" + var props = c + r + a + if (props.length > 0) { + props = " *$props" + } + sendMessage(player, " $i: $o$props") + } + } + if (nulls.isNotEmpty()) { + sendMessage(player, " ${nulls.joinToString()}: null") + } + } + val stat = ArrayList(10) + for (i in 0 until chunk.statObjects.size) { + val obj = chunk.statObjects[i][player.location.chunkOffsetX][player.location.chunkOffsetY] + if (obj != null) { + stat.add(obj) + } + } + dump("Chunk static objects", stat) + dump("Chunk dynamic objects", chunk.getObjects(player.location.chunkOffsetX, player.location.chunkOffsetY).asList()) + dump("RegionManager", listOf(getObject(player.location))) //getObject can only get one + sendMessage(player, "--- That's all, folks! ---") + } } } diff --git a/Server/src/main/core/game/system/command/sets/TeleportCommandSet.kt b/Server/src/main/core/game/system/command/sets/TeleportCommandSet.kt index 30e4107c9..e8d7b84f3 100644 --- a/Server/src/main/core/game/system/command/sets/TeleportCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/TeleportCommandSet.kt @@ -100,69 +100,6 @@ class TeleportCommandSet : CommandSet(Privilege.ADMIN){ player.properties.teleportLocation = Location.create(args[1].toInt(), args[2].toInt(), if (args.size > 3) args[3].toInt() else 0) } - /** - * Teleport to the first object with the given name in the given regionX regionY - */ - define("teleobj", Privilege.ADMIN, "::teleobj RX_RY OBJ NAME", "Teleports to the first object with the given name."){player, args -> - if(args.size < 3) reject(player, "Usage: regionX_regionY Object Name") - var objName = "" - for(i in 2 until args.size) objName += (args[i] + if(i + 1 == args.size) "" else " ") - - val tokens = args[1].split("_") - if(tokens.size != 2) reject(player, "Usage: regionX_regionY Object Name") - val regionX = tokens[0].toInt() - val regionY = tokens[1].toInt() - - val regionId = (regionX shl 8) or regionY - val region = RegionManager.forId(regionId) - - GlobalScope.launch { - for (plane in region.planes) { - for (objects in plane.objects.filterNotNull()) { - for (parent in objects.filterNotNull()) { - if (parent.childs != null) { - for (obj in parent.childs.filterNotNull()) { - if (obj.name.equals(objName, ignoreCase = true)) { - player.properties.teleportLocation = obj.location - return@launch - } - } - } else { - if (parent.name.equals(objName, ignoreCase = true)) { - player.properties.teleportLocation = parent.location - return@launch - } - } - } - } - } - } - } - - /** - * Finds a list of objects/sceneries in a region - */ - define("findobjs", Privilege.ADMIN, "::findobjs REGION ID SCENERY ID", "Finds all locations of scenery objects of id."){player, args -> - if(args.size < 4) reject(player, "Usage: region_id scenery_id") - val regionId = args[1].toInt() - val sceneryId = args[2].toInt() - val sceneryIdEnd = args[3].toInt() - - val region = RegionManager.forId(regionId) - - GlobalScope.launch { - for (plane in region.planes) { - for (objects in plane.objects.filterNotNull()) { - for (parent in objects.filterNotNull()) { - if (parent.id in sceneryId..sceneryIdEnd) { - println(parent.location) - } - } - } - } - } - } - /** * Teleport to a specific player */ diff --git a/Server/src/main/core/game/system/config/ConfigParser.kt b/Server/src/main/core/game/system/config/ConfigParser.kt index db7e1b0f3..00c8e72e7 100644 --- a/Server/src/main/core/game/system/config/ConfigParser.kt +++ b/Server/src/main/core/game/system/config/ConfigParser.kt @@ -16,6 +16,7 @@ class ConfigParser : Commands { ItemConfigParser().load() ObjectConfigParser().load() XteaParser().load() + ObjectOverrideParser().load() InterfaceConfigParser().load() } fun postPlugin() { @@ -31,7 +32,12 @@ class ConfigParser : Commands { } fun reloadConfigs(callback: () -> Unit) { - GlobalScope.launch { + GlobalScope.launch { + RegionManager.apply { r -> + r.addScenery.clear() + r.removeScenery.clear() + } + Repository.npcs.toTypedArray().forEach { npc -> npc.isRespawn = false npc.clear() @@ -41,7 +47,7 @@ class ConfigParser : Commands { GroundItemManager.getItems().toTypedArray().forEach {gi -> GroundItemManager.getItems().remove(gi) - RegionManager.getRegionPlane(gi.location).remove(gi) + RegionManager.getRegionChunk(gi.location).remove(gi) } prePlugin() diff --git a/Server/src/main/core/game/system/config/ObjectOverrideParser.kt b/Server/src/main/core/game/system/config/ObjectOverrideParser.kt new file mode 100644 index 000000000..68705d7ca --- /dev/null +++ b/Server/src/main/core/game/system/config/ObjectOverrideParser.kt @@ -0,0 +1,57 @@ +package core.game.system.config + +import core.ServerConstants +import core.api.log +import core.game.node.scenery.Scenery +import core.game.world.map.Location +import core.game.world.map.RegionManager +import core.tools.Log +import org.json.simple.JSONArray +import org.json.simple.JSONObject +import org.json.simple.parser.JSONParser +import java.io.FileReader + +class ObjectOverrideParser { + val parser = JSONParser() + var reader: FileReader? = null + fun load() { + var count = 0 + reader = FileReader(ServerConstants.CONFIG_PATH + "object_overrides.json") + val overridelist = parser.parse(reader) as JSONArray + for (entry in overridelist) { + val e = entry as JSONObject + + // Mandatory fields + val mode = e["mode"].toString() + val id = e["id"].toString().toInt() + val loc = Location.fromString(e["location"].toString()) + + // Optional fields + val type = e["type"]?.toString()?.toInt() ?: 10 + val direction = e["direction"]?.toString() ?: "n" + + // Now create a Scenery object and assign it to its region + val rotation = when (direction) { + "n" -> 1 + "ne" -> 2 + "nw" -> 0 + "w" -> 3 + "e" -> 4 + "sw" -> 5 + "se" -> 7 + "s" -> 6 + else -> 1 + } + val obj = Scenery(id, loc, type, rotation) + val region = RegionManager.forId(loc.regionId) + when (mode) { + "remove" -> region.removeScenery.add(obj) //type and rotation are currently ignored, but this can be changed in Region.java if needed + "add" -> region.addScenery.add(obj) + else -> log(this::class.java, Log.ERR, "Ignored unknown ObjectOverride mode $mode!") + } + count++ + } + log(this::class.java, Log.FINE, "Parsed $count object overrides.") + } +} + diff --git a/Server/src/main/core/game/world/map/BuildRegionChunk.java b/Server/src/main/core/game/world/map/BuildRegionChunk.java deleted file mode 100644 index 008937301..000000000 --- a/Server/src/main/core/game/world/map/BuildRegionChunk.java +++ /dev/null @@ -1,336 +0,0 @@ -package core.game.world.map; - - -import core.game.node.entity.player.Player; -import core.game.node.item.GroundItem; -import core.game.node.item.Item; -import core.game.node.scenery.Constructed; -import core.game.node.scenery.Scenery; -import core.game.node.scenery.SceneryBuilder; -import core.tools.Log; -import core.tools.SystemLogger; -import core.game.world.map.build.LandscapeParser; -import core.net.packet.IoBuffer; -import core.net.packet.out.ClearScenery; -import core.net.packet.out.ConstructGroundItem; -import core.net.packet.out.ConstructScenery; - -import static core.api.ContentAPIKt.log; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * A region chunk, used for easily modifying objects. - * @author Emperor - * - */ -public class BuildRegionChunk extends RegionChunk { - - /** - * The maximum amount of objects to be stored on one tile in the chunk. - */ - public static final int ARRAY_SIZE = 10; - - /** - * The list of changes made. - */ - private final Scenery[][][] objects; - - /** - * Constructs a new {@code BuildRegionChunk} {@code Object} - * @param base The base location. - * @param rotation The rotation. - * @param plane The region plane. - */ - public BuildRegionChunk(Location base, int rotation, RegionPlane plane) { - super(base, rotation, plane); - this.objects = new Scenery[ARRAY_SIZE][8][8]; - } - - public BuildRegionChunk(Location base, int rotation, RegionPlane plane, Scenery[][] objects) { - this(base, rotation, plane); - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - if(objects[x][y] != null) { - this.objects[0][x][y] = new Scenery(objects[x][y]); - } - } - } - } - - @Override - protected boolean appendUpdate(Player player, IoBuffer buffer) { - boolean updated = false;//super.appendUpdate(player, buffer); - for (int i = 0; i < objects.length; i++) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - Scenery o = objects[i][x][y]; - if (o instanceof Constructed) { - ConstructScenery.write(buffer, o); - updated = true; - } - else if (o != null && !o.isRenderable()) { - ClearScenery.write(buffer, o); - updated = true; - } - } - } - } - ArrayList totalItems = drawItems(items, player); - for (GroundItem item : totalItems) { - if (item != null && item.isActive() && item.getLocation() != null) { - if (!item.isPrivate() || item.droppedBy(player)) { - ConstructGroundItem.write(buffer, item); - updated = true; - } - } - } - return updated; - } - - @Override - public void rotate(Direction direction) { - if (rotation != 0) { - log(this.getClass(), Log.ERR, "Region chunk was already rotated!"); - return; - } - Scenery[][][] copy = new Scenery[ARRAY_SIZE][SIZE][SIZE]; - int baseX = currentBase.getLocalX(); - int baseY = currentBase.getLocalY(); - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - for (int i = 0; i < objects.length; i++) { - Scenery object = copy[i][x][y] = objects[i][x][y]; - if (object != null) { - SceneryBuilder.remove(object); - this.remove(object); - } - } - } - } - clear(); - switch(direction) { - case NORTH: rotation = 0; break; - case EAST: rotation = 1; break; - case SOUTH: rotation = 2; break; - case WEST: rotation = 3; break; - default: rotation = (direction.toInteger() + (direction.toInteger() % 2 == 0 ? 2 : 0)) % 4; - log(this.getClass(), Log.ERR, "Attempted to rotate a chunk in a non-cardinal direction - using fallback rotation code. This should be investigated!"); - break; - }; - for (int i = 0; i < objects.length; i++) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - Scenery object = copy[i][x][y]; - if (object != null) { - int[] pos = getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation); - Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); - if (object instanceof Constructed) { - obj = obj.asConstructed(); - } - obj.setActive(object.isActive()); - obj.setRenderable(object.isRenderable()); - LandscapeParser.flagScenery(plane, baseX + pos[0], baseY + pos[1], obj, true, true); - } - } - } - } - } - - @Override - public BuildRegionChunk copy(RegionPlane plane) { - BuildRegionChunk chunk = new BuildRegionChunk(base, rotation, plane); - for (int i = 0; i < chunk.objects.length; i++) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - Scenery o = objects[i][x][y]; - if (o instanceof Constructed) { - chunk.objects[i][x][y] = o.transform(o.getId(), o.getRotation()).asConstructed(); - } - else if (o != null) { - chunk.objects[i][x][y] = o.transform(o.getId()); - chunk.objects[i][x][y].setActive(o.isActive()); - chunk.objects[i][x][y].setRenderable(o.isRenderable()); - } - } - } - } - return chunk; - } - - @Override public void rebuildFlags(RegionPlane from) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - Location loc = currentBase.transform(x,y,0); - Location fromLoc = base.transform(x,y,0); - plane.getFlags().getLandscape()[loc.getLocalX()][loc.getLocalY()] = from.getFlags().getLandscape()[fromLoc.getLocalX()][fromLoc.getLocalY()]; - plane.getFlags().clearFlag(x, y); - for (int i = 0; i < ARRAY_SIZE; i++) { - Scenery obj = objects[i][x][y]; - if (obj != null) - LandscapeParser.applyClippingFlagsFor(plane, loc.getLocalX(), loc.getLocalY(), obj); - } - } - } - } - - @Override - public void clear() { - super.clear(); - for (int i = 0; i < objects.length; i++) { - for (int x = 0; x < objects[i].length; x++) { - for (int y = 0; y < objects[i][x].length; y++) { - objects[i][x][y] = null; - } - } - } - } - - /** - * Removes the scenery. - * @param object The object to remove. - */ - public void remove(Scenery object) { - int chunkX = object.getLocation().getChunkOffsetX(); - int chunkY = object.getLocation().getChunkOffsetY(); - Scenery current = null; - int index = -1; - int i = 0; - while ((current == null || current.getId() != object.getId()) && i < objects.length) { - current = objects[i++][chunkX][chunkY]; - if ((current == null || current.getId() < 1) && index == -1) { - index = i - 1; - } - } - if (current != null && current.equals(object)) { - current.setActive(false); - object.setRenderable(false); - } - else { - objects[index][chunkX][chunkY] = object; - } - object.setActive(false); - object.setRenderable(false); - } - - /** - * Adds the scenery. - * @param object The object to add. - */ - public void add(Scenery object) { - int chunkX = object.getLocation().getChunkOffsetX(); - int chunkY = object.getLocation().getChunkOffsetY(); - Scenery current = null; - int index = -1; - int i = 0; - while ((current == null || current.getId() != object.getId()) && i < objects.length) { - current = objects[i++][chunkX][chunkY]; - if ((current == null || current.getId() < 1) && index == -1) { - index = i - 1; - } - } - if (current != null && current.equals(object)) { - current.setActive(true); - current.setRenderable(true); - } - else if (index == -1) { - throw new IllegalStateException("Insufficient array length for storing object!"); - } - else { - objects[index][chunkX][chunkY] = object = object.asConstructed(); - } - object.setActive(true); - object.setRenderable(true); - } - - /** - * Stores an object on the region chunk. - * @param object The object. - */ - public void store(Scenery object) { - if (object == null) { - return; - } - int chunkX = object.getLocation().getChunkOffsetX(); - int chunkY = object.getLocation().getChunkOffsetY(); - for (int i = 0; i < objects.length; i++) { - Scenery stat = objects[i][chunkX][chunkY]; - if (stat == null || stat.getId() < 1) { - objects[i][chunkX][chunkY] = object; - object.setActive(true); - object.setRenderable(true); - return; - } - } - System.err.print("Objects - ["); - for (int i = 0; i < objects.length; i++) { - System.err.print(objects[i][chunkX][chunkY]); - if (i < objects.length - 1) { - System.err.print(", "); - } - } - log(this.getClass(), Log.ERR, "]!"); - throw new IllegalStateException("Insufficient array length for storing all objects! "); - } - - /** - * Gets the objects index for the given object id. - * @param x The x-coordinate on the region chunk. - * @param y The y-coordinate on the region chunk. - * @param objectId The object id. - */ - public int getIndex(int x, int y, int objectId) { - for (int i = 0; i < objects.length; i++) { - Scenery o = get(x, y, i); - if (o != null && ((objectId > -1 && o.getId() == objectId) || (objectId == -1 && o.getDefinition().hasOptions(false)))) { - return i; - } - } - return 0; - } - - /** - * Gets a scenery. - * @param x The chunk x-coordinate. - * @param y The chunk y-coordinate. - * @param index The index (0 = default). - * @return The object. - */ - public Scenery get(int x, int y, int index) { - return objects[index][x][y]; - } - - @Override - public Scenery[] getObjects(int chunkX, int chunkY) { - Scenery[] objects = new Scenery[ARRAY_SIZE]; - for (int i = 0; i < ARRAY_SIZE; i++) { - objects[i] = this.objects[i][chunkX][chunkY]; - } - return objects; - } - - /** - * Gets the objects. - * @param index The index. - * @return The objects array. - */ - public Scenery[][] getObjects(int index) { - return objects[index]; - } - - @Override - public void setCurrentBase(Location currentBase) { - for (int i = 0; i < objects.length; i++) { - for (int x = 0; x < objects[i].length; x++) { - for (int y = 0; y < objects[i][x].length; y++) { - if (objects[i][x][y] != null) { - Location newLoc = currentBase.transform(x, y, 0); - objects[i][x][y].setLocation(newLoc); - } - } - } - } - super.setCurrentBase(currentBase); - } -} diff --git a/Server/src/main/core/game/world/map/Location.kt b/Server/src/main/core/game/world/map/Location.kt index a202e4a49..0d2d01bb9 100644 --- a/Server/src/main/core/game/world/map/Location.kt +++ b/Server/src/main/core/game/world/map/Location.kt @@ -101,6 +101,8 @@ class Location(var hash: LocationHash) : Node(null, null) { // Derived variables. Please note the following isn't a 1-1 representation of what is officially used. // Region - (Officially: Map Square) 64x64 + /** The region. */ + val region: Region get() = RegionManager.forId(regionId) /** Unique index "key" (Officially: region_uid) for a 64x64 area. Made of x and y joined bitwise together. Used in xteas.json. */ val regionId: Int get() = x shr 6 shl 8 or (y shr 6) // Cuts off the end 6 bits of both x y and joins them together. E.g. 10392 /** The chunk x index for this position (x/8). For sets of 8x8 area. THIS IS NAMED WRONG, THIS IS A CHUNK(8) NOT REGION(64). */ @@ -116,7 +118,14 @@ class Location(var hash: LocationHash) : Node(null, null) { fun isInRegion(region: Int): Boolean = regionId == region // Chunk - (Officially: Zones) 8x8 + /** The chunk. */ + val chunk: RegionChunk get() = region.chunks[chunkX][chunkY][z] + /** The chunk base on the world map. */ val chunkBase: Location get() = create(regionX shl 3, regionY shl 3, z) + /** The ABSOLUTE chunk x index for this position. (Same as regionX, but named correctly.) */ + val absChunkX: Int get() = x shr 3 // shr 3 is essentially divide by 8 + /** The ABSOLUTE chunk y index for this position. (Same as regionY, but named correctly.) */ + val absChunkY: Int get() = y shr 3 // shr 3 is essentially divide by 8 /** The chunk x index for this position RELATIVE to a region[localX](x/8). THIS IS NOT GLOBAL CHUNK X. */ val chunkX: Int get() = localX shr 3 // shr 3 is essentially divide by 8 (note this is localX) /** The chunk y index for this position RELATIVE to a region[localY](y/8). THIS IS NOT GLOBAL CHUNK Y. */ @@ -136,8 +145,6 @@ class Location(var hash: LocationHash) : Node(null, null) { /** @return The local scene y-coordinate relative to another location's regionY. */ fun getSceneY(loc: Location): Int = y - (loc.regionY - 6 shl 3) - - /** @return The location incremented by another location's coordinates. (POTENTIAL Z PROBLEMS HERE) */ // TODO: THE FOLLOWING TRANSFORM HAS SHIT Z HANDLING. fun transform(l: Location): Location = Location(x + l.x, y + l.y, (z + l.z) % 4) @@ -148,7 +155,6 @@ class Location(var hash: LocationHash) : Node(null, null) { /** Location transformed by a Vector. Limit usage to more complicated functionality. */ fun transform(vector: Vector): Location = create(x + floor(vector.x).toInt(), y + floor(vector.y).toInt()) - /** @return True if this location is 1 tile N, W, S, or E of the node. THIS CAN BE REFACTORED OUT. */ fun isNextTo(node: Node): Boolean { val l = node.location @@ -167,7 +173,7 @@ class Location(var hash: LocationHash) : Node(null, null) { /** @return The straight-line(Euclidean) distance between this and another location. */ fun getDistance(other: Location): Double = getDistance(this, other) - /** @returns ArrayList of the 8 cardinal and diagonal tiles. Order is important and follows [Direction] indexing **/ + /** @returns ArrayList of the 8 cardinal and diagonal tiles. Order is important and follows [Direction] indexing */ val surroundingTiles: ArrayList get() { val locations = ArrayList() locations.add(transform(-1, -1, 0)) @@ -181,7 +187,7 @@ class Location(var hash: LocationHash) : Node(null, null) { return locations } - /** @returns ArrayList of the 4 cardinal direction tiles. Order is important and follows [Direction] indexing **/ + /** @returns ArrayList of the 4 cardinal direction tiles. Order is important and follows [Direction] indexing */ val cardinalTiles: ArrayList get() { val locations = ArrayList() locations.add(transform(-1, 0, 0)) @@ -191,7 +197,6 @@ class Location(var hash: LocationHash) : Node(null, null) { return locations } - /** * Gets the directional components of a movement step. * TODO: would prefer this in the other place. This doesn't exactly belong here since this isn't a common function for other instances of Location diff --git a/Server/src/main/core/game/world/map/Region.java b/Server/src/main/core/game/world/map/Region.java index ff87d8e6b..40e455aea 100644 --- a/Server/src/main/core/game/world/map/Region.java +++ b/Server/src/main/core/game/world/map/Region.java @@ -1,9 +1,12 @@ package core.game.world.map; import core.cache.Cache; +import core.game.node.Node; import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.node.entity.player.link.music.MusicZone; +import core.game.node.scenery.Scenery; +import core.game.node.scenery.SceneryBuilder; import core.game.system.communication.CommunicationInfo; import core.game.system.task.Pulse; import core.game.world.map.build.DynamicRegion; @@ -29,12 +32,6 @@ import static core.api.ContentAPIKt.log; * @author Emperor */ public class Region { - - /** - * The default size of a region. - */ - public static final int SIZE = 64; - /** * The region x-coordinate. */ @@ -46,9 +43,9 @@ public class Region { private final int y; /** - * The region planes. + * The chunks in this region. */ - private final RegionPlane[] planes = new RegionPlane[4]; + protected RegionChunk[][][] chunks = new RegionChunk[8][8][4]; /** * The activity pulse. @@ -73,7 +70,7 @@ public class Region { /** * Keeps track of players and time in region for tolerance purposes */ - private final HashMap tolerances = new HashMap<>(); + private final HashMap tolerances = new HashMap(); /** * If the region is active. @@ -106,9 +103,10 @@ public class Region { private boolean build; /** - * If all planes should be updated when in this region (instead of just current one). + * Any scenery overrides for this region */ - private boolean updateAllPlanes; + private ArrayList addScenery = new ArrayList<>(); + private ArrayList removeScenery = new ArrayList<>(); /** * Constructs a new {@code Region} {@code Object}. @@ -118,8 +116,14 @@ public class Region { public Region(int x, int y) { this.x = x; this.y = y; - for (int plane = 0; plane < 4; plane++) { - planes[plane] = new RegionPlane(this, plane); + Location swCorner = getBaseLocation(); + for (x = 0; x < 8; x++) { + for (y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + Location loc = swCorner.transform(x*8, y*8, z); + chunks[x][y][z] = new RegionChunk(loc, 0); + } + } } this.activityPulse = new Pulse(50) { @Override @@ -139,79 +143,57 @@ public class Region { return Location.create(x << 6, y << 6, 0); } + /** + * Gets the chunks. + * @return The chunks. + */ + public RegionChunk[][][] getChunks() { + return chunks; + } + /** * Adds a region zone to this region. * @param zone The region zone. */ public void add(RegionZone zone) { regionZones.add(zone); - for (RegionPlane plane : planes) { - for (NPC npc : plane.getNpcs()) { - npc.getZoneMonitor().updateLocation(npc.getLocation()); - } - for (Player p : plane.getPlayers()) { - p.getZoneMonitor().updateLocation(p.getLocation()); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + for (NPC npc : chunks[x][y][z].getNpcs()) { + npc.getZoneMonitor().updateLocation(npc.getLocation()); + } + for (Player player : chunks[x][y][z].getPlayers()) { + if (player != null) { + player.getZoneMonitor().updateLocation(player.getLocation()); + } + } + } } } } public void remove(RegionZone zone) { regionZones.remove(zone); - for (RegionPlane plane : planes) { - for (NPC npc : plane.getNpcs()) { - npc.getZoneMonitor().updateLocation(npc.getLocation()); - } - for (Player p : plane.getPlayers()) { - p.getZoneMonitor().updateLocation(p.getLocation()); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + for (NPC npc : chunks[x][y][z].getNpcs()) { + npc.getZoneMonitor().updateLocation(npc.getLocation()); + } + for (Player player : chunks[x][y][z].getPlayers()) { + player.getZoneMonitor().updateLocation(player.getLocation()); + } + } } } } - /** - * Adds a player to this region. - * @param player The player. - */ - public void add(Player player) { - planes[player.getLocation().getZ()].add(player); - tolerances.put(player.getUsername(), System.currentTimeMillis()); - flagActive(); - } - - /** - * Adds an npc to this region. - * @param npc The npc. - */ - public void add(NPC npc) { - planes[npc.getLocation().getZ()].add(npc); - } - - /** - * Removes an NPC from this region. - * @param npc The NPC. - */ - public void remove(NPC npc) { - RegionPlane plane = npc.getViewport().getCurrentPlane(); - if (plane != null && plane != planes[npc.getLocation().getZ()]) { - plane.remove(npc); - } - planes[npc.getLocation().getZ()].remove(npc); - } - - /** - * Removes a player from this region. - * @param player The player. - */ - public void remove(Player player) { - player.getViewport().getCurrentPlane().remove(player); - tolerances.remove(player.getUsername()); - checkInactive(); - } - /** * Checks if player is tolerated by enemies in this region */ - public boolean isTolerated(Player player){ - return System.currentTimeMillis() - tolerances.getOrDefault(player.getUsername(), System.currentTimeMillis()) > TimeUnit.MINUTES.toMillis(10); + public boolean isTolerated(Player player) { + return System.currentTimeMillis() - tolerances.getOrDefault(player.getName(), System.currentTimeMillis()) > TimeUnit.MINUTES.toMillis(10); } /** @@ -231,9 +213,13 @@ public class Region { if (isViewed()) { return false; } - for (RegionPlane p : planes) { - if (!p.getPlayers().isEmpty()) { - return false; + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + if (!chunks[x][y][z].getPlayers().isEmpty()) { + return false; + } + } } } if (runPulse) { @@ -246,14 +232,6 @@ public class Region { return true; } - /** - * Checks if this region has the inactivity flagging pulse running. - * @return {@code True} if so. - */ - public boolean isPendingRemoval() { - return activityPulse.isRunning(); - } - /** * Flags the region as active. */ @@ -262,10 +240,14 @@ public class Region { if (!active) { active = true; load(this); - for (RegionPlane r : planes) { - for (NPC n : r.getNpcs()) { - if (n.isActive()) { - Repository.addRenderableNPC(n); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + for (NPC npc : chunks[x][y][z].getNpcs()) { + if (npc.isActive()) { + Repository.addRenderableNPC(npc); + } + } } } } @@ -285,7 +267,7 @@ public class Region { * Flags the region as inactive. */ public boolean flagInactive() { - return flagInactive(false); + return flagInactive(false); } /** @@ -299,7 +281,7 @@ public class Region { /** * Loads the flags for a region. * @param r The region. - * @param build if all objects in this region should be stored (rather than just the ones with options). + * @param build If the region can be edited. */ public static void load(Region r, boolean build) { try { @@ -318,11 +300,13 @@ public class Region { return; } - byte[][][] mapscapeData = new byte[4][SIZE][SIZE]; - for (RegionPlane plane : r.planes) { - plane.getFlags().setLandscape(new boolean[SIZE][SIZE]); - //plane.getFlags().setClippingFlags(new int[SIZE][SIZE]); - //plane.getProjectileFlags().setClippingFlags(new int[SIZE][SIZE]); + byte[][][] mapscapeData = new byte[4][64][64]; + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + r.chunks[x][y][z].getFlags().setLandscape(new boolean[8][8]); + } + } } if (mapscapeId > -1) { ByteBuffer mapscape = ByteBuffer.wrap(Cache.getIndexes()[5].getCacheFile().getContainerUnpackedData(mapscapeId)); @@ -338,50 +322,63 @@ public class Region { } r.hasFlags = true; try { - LandscapeParser.parse(r, mapscapeData, ByteBuffer.wrap(landscape), build); + LandscapeParser.parse(r, r.chunks, mapscapeData, ByteBuffer.wrap(landscape), build); } catch (Throwable t) { new Throwable("Failed parsing region " + regionId + "!", t).printStackTrace(); } } - MapscapeParser.clipMapscape(r, mapscapeData); + MapscapeParser.clipMapscape(r, r.chunks, mapscapeData); + for (Scenery object : r.removeScenery) { + // Get the actual object, not the instance that's kept in the removeScenery array + Scenery realObject = RegionManager.getObject(object.getLocation()); //can be extended to take into account type and rotation if needed + if (realObject != null) { + SceneryBuilder.remove(realObject); + } + } + for (Scenery object : r.addScenery) { + SceneryBuilder.add(object); + } } catch (Throwable e) { e.printStackTrace(); } } - public static boolean unload(Region r) { - return unload(r, false); - } - /** * Unloads a region. * @param r The region. */ - public static boolean unload(Region r, boolean force) { + public boolean unload(Region r, boolean force) { if (!force && r.isViewed()) { log(CommunicationInfo.class, Log.ERR, "Players viewing region!"); r.flagActive(); return false; } - for (RegionPlane p : r.planes) { - if (!force && !p.getPlayers().isEmpty()) { - log(CommunicationInfo.class, Log.ERR, "Players still in region!"); - r.flagActive(); - return false; - } - } - for (RegionPlane p : r.planes) { - p.clear(); - if (!(r instanceof DynamicRegion)) { - for (NPC n : p.getNpcs()) { - n.onRegionInactivity(); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + if (!force && !chunks[x][y][z].getPlayers().isEmpty()) { + log(CommunicationInfo.class, Log.ERR, "Players still in region!"); + r.flagActive(); + return false; + } } } } - if (r.isBuild()) - r.setLoaded(false); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + if (!(r instanceof DynamicRegion)) { + for (NPC npc : chunks[x][y][z].getNpcs()) { + npc.onRegionInactivity(); + } + } + chunks[x][y][z].clear(); + } + } + } + r.setLoaded(false); r.activityPulse.stop(); - return true; + return true; } /** @@ -426,17 +423,6 @@ public class Region { return active; } - /** - * Sets the active. - * @param active The active to set. - * @deprecated This should not be used, instead use the {@link #flagInactive()}, - * {@link #flagActive()} & {@link #checkInactive()} methods to safely change the activity state. - */ - @Deprecated - public void setActive(boolean active) { - this.active = active; - } - /** * Gets the region id. * @return The region id. @@ -469,14 +455,6 @@ public class Region { return y; } - /** - * Gets the planes. - * @return The planes. - */ - public RegionPlane[] getPlanes() { - return planes; - } - /** * Sets the region-wide music track. */ @@ -532,14 +510,6 @@ public class Region { return hasFlags; } - /** - * Sets the hasFlags. - * @param hasFlags The hasFlags to set. - */ - public void setHasFlags(boolean hasFlags) { - this.hasFlags = hasFlags; - } - /** * Sets the region time out duration. * @param ticks The amount of ticks before the region is flagged as inactive. @@ -564,14 +534,6 @@ public class Region { this.loaded = loaded; } - /** - * Sets the viewAmount. - * @param viewAmount The viewAmount to set. - */ - public void setViewAmount(int viewAmount) { - this.viewAmount = viewAmount; - } - /** * Gets the build. * @return the build @@ -588,19 +550,70 @@ public class Region { this.build = build; } - /** - * Gets the updateAllPlanes value. - * @return The updateAllPlanes. - */ - public boolean isUpdateAllPlanes() { - return updateAllPlanes; + public List assembleObjectList(int z) { + ArrayList list = new ArrayList<>(); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + RegionChunk chunk = chunks[x][y][z]; + for (int offsetX = 0; offsetX < 8; offsetX++) { + for (int offsetY = 0; offsetY < 8; offsetY++) { + for (int i = 0; i < 4; i++) { + Scenery object = chunk.getObjects()[i][offsetX][offsetY]; + if (object != null) { + list.add(object); + } + } + } + } + } + } + return list; + } + + public List assembleNpcList(int z) { + ArrayList list = new ArrayList<>(); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + RegionChunk chunk = chunks[x][y][z]; + list.addAll(chunk.getNpcs()); + } + } + return list; + } + + public List assemblePlayerList(int z) { + ArrayList list = new ArrayList<>(); + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + RegionChunk chunk = chunks[x][y][z]; + list.addAll(chunk.getPlayers()); + } + } + return list; + } + + public List assembleEntityList(int z) { + ArrayList list = new ArrayList<>(assembleObjectList(z)); + list.addAll(assemblePlayerList(z)); + list.addAll(assembleNpcList(z)); + return list; } /** - * Sets the updateAllPlanes value. - * @param updateAllPlanes The updateAllPlanes to set. + * Getter for region aggro tolerances. + * @return */ - public void setUpdateAllPlanes(boolean updateAllPlanes) { - this.updateAllPlanes = updateAllPlanes; + public HashMap getTolerances() { + return tolerances; + } + + /** + * Getters for addScenery and removeScenery. + */ + public ArrayList getAddScenery() { + return addScenery; + } + public ArrayList getRemoveScenery() { + return removeScenery; } } diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 7b3fb71c8..7ee787878 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -1,19 +1,23 @@ package core.game.world.map; +import core.game.node.Node; +import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.node.item.GroundItem; import core.game.node.item.Item; +import core.game.node.scenery.Constructed; import core.game.node.scenery.Scenery; +import core.game.node.scenery.SceneryBuilder; +import core.game.world.map.build.ChunkFlags; +import core.game.world.update.flag.chunk.ItemUpdateFlag; +import core.net.packet.PacketRepository; +import core.net.packet.context.BuildItemContext; +import core.net.packet.out.*; import core.tools.Log; -import core.tools.SystemLogger; import core.game.world.map.build.DynamicRegion; import core.game.world.map.build.LandscapeParser; import core.game.world.update.flag.UpdateFlag; import core.net.packet.IoBuffer; -import core.net.packet.out.ClearScenery; -import core.net.packet.out.ConstructGroundItem; -import core.net.packet.out.ConstructScenery; -import core.net.packet.out.UpdateAreaPosition; import java.util.ArrayList; import java.util.List; @@ -22,10 +26,15 @@ import static core.api.ContentAPIKt.log; /** * Represents a region chunk. - * @author Emperor + * @author Emperor, Player Name * */ public class RegionChunk { + /** + * The maximum amount of objects to be stored on one tile in the chunk. + * Four objects per tile is the authentic RuneTek engine limit. + */ + public static final int ARRAY_SIZE = 4; /** * The chunk size. @@ -42,20 +51,27 @@ public class RegionChunk { */ protected Location currentBase; - /** - * The region plane. - */ - protected RegionPlane plane; - /** * The items in this chunk. */ - protected List items; + protected List items = new ArrayList<>(); /** - * The scenerys in this chunk. + * The static objects in this chunk. Only used as a reference, do not act on these unless you are the landscape- + * parsing code. + * The game protocol requires us to send separate updates for dynamically added scenery and dynamically + * removed scenery. We implement this by maintaining two lists: one of static scenery, which contains the + * reference state obtained from the cache, and one of dynamic scenery, which is the actual current state of + * the sceneries on a chunk. This means that during landscape-parsing (and, crucially, only then), we need + * to add objects to both the static and dynamic lists. All object interactions in the game, however, only + * use the dynamic list (hence why that is just called 'objects'). */ - protected Scenery[][] objects; + protected Scenery[][][] statObjects; + + /** + * The (dynamic, actual) objects in this chunk. + */ + protected Scenery[][][] objects; /** * The rotation. @@ -65,28 +81,262 @@ public class RegionChunk { /** * The update flags. */ - private List> flags = new ArrayList<>(20); + private List> updateFlags = new ArrayList<>(20); + + /** + * The region flags. + */ + private ChunkFlags flags; + + /** + * The region projectile flags. + */ + private ChunkFlags projectileFlags; + + /** + * The players on this chunk. + */ + private final List players = new ArrayList<>(); + + /** + * The NPCs on this chunk. + */ + private final List npcs = new ArrayList<>(); /** * Constructs a new {@code RegionChunk} {@code Object}. * @param base The base location of the region chunk. * @param rotation The rotation. */ - public RegionChunk(Location base, int rotation, RegionPlane plane) { + public RegionChunk(Location base, int rotation) { this.base = base; this.currentBase = base; this.rotation = rotation; - this.plane = plane; - this.objects = new Scenery[SIZE][SIZE]; + this.statObjects = new Scenery[ARRAY_SIZE][SIZE][SIZE]; + this.objects = new Scenery[ARRAY_SIZE][SIZE][SIZE]; + this.flags = new ChunkFlags(base.getX(), base.getY(), base.getZ()); + this.projectileFlags = new ChunkFlags(base.getX(), base.getY(), base.getZ(), true); + } + + /** + * Corrects objects' Locations when copying them from a template region into an instance - public version. + */ + public void rebaseObjects() { + rebaseObjects(statObjects); + rebaseObjects(objects); + } + + /** + * Corrects objects' Locations when copying them from a template region into an instance - private version. + */ + private void rebaseObjects(Scenery[][][] objects) { + for (int i = 0; i < objects.length; i++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + Scenery o = objects[i][x][y]; + if (o == null) { + continue; + } + o.setLocation(getCurrentBase().transform(x, y, 0)); + } + } + } + } + + /** + * Makes a deep copy of an object list - private version. + */ + private void copyObjects(Scenery[][][] src, Scenery[][][] dest) { + for (int i = 0; i < src.length; i++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + Scenery o = src[i][x][y]; + if (o == null) { + continue; + } + Scenery copy = o.transform(o.getId()); + if (o instanceof Constructed) { + dest[i][x][y] = copy.asConstructed(); + } else { + dest[i][x][y] = copy; + } + dest[i][x][y].setActive(o.isActive()); + dest[i][x][y].setRenderable(o.isRenderable()); + } + } + } } /** * Copies the region chunk. - * @param plane The region plane. - * @return The region chunk. + * @return The destination chunk. */ - public BuildRegionChunk copy(RegionPlane plane) { - return new BuildRegionChunk(base, rotation, plane, this.objects); + public RegionChunk copy() { + RegionChunk chunk = new RegionChunk(base, rotation); + copyObjects(statObjects, chunk.statObjects); //note that the objects' locations have not been repointed to the new chunk yet, since we don't know _where_ the new chunk will be at this point + copyObjects(objects, chunk.objects); + return chunk; + } + + /** + * Adds the scenery to the static and dynamic object lists. You never want this unless you are the landscape-parsing + * code. + * @param object The object to add. + * @return The slot it was added into. + */ + public int addStatDyn(Scenery object, int chunkOffsetX, int chunkOffsetY) { + for (int i = 0; i < statObjects.length; i++) { + Scenery current = statObjects[i][chunkOffsetX][chunkOffsetY]; + if (current == null) { + statObjects[i][chunkOffsetX][chunkOffsetY] = object; + objects[i][chunkOffsetX][chunkOffsetY] = object.transform(object.getId()); //deep copy so that active/renderable flags don't synchronize across multiple copies of e.g. a POH + return i; + } + if (current.getId() == object.getId()) { + // It's possible that we already have this object. One instance of this was found at 1906, 5082, 0, + // where our cache has more than one copy of the same [Scenery 15349, [1906, 5082, 0], type=22, rot=1] + // object. Since authentically, the engine can only support one of the same type of object per tile, + // if the ID matches we can be confident that this is a duplicate. + return i; + } + } + throw new IllegalStateException("RC addStatDyn insufficient array length for storing object " + object); + } + + /** + * Adds the scenery to the dynamic object list. + * @param object The object to add. + * @return The slot it was added into. + */ + public int add(Scenery object) { + int chunkOffsetX = object.getLocation().getChunkOffsetX(); + int chunkOffsetY = object.getLocation().getChunkOffsetY(); + for (int i = 0; i < objects.length; i++) { + Scenery current = objects[i][chunkOffsetX][chunkOffsetY]; + if (current == null) { + objects[i][chunkOffsetX][chunkOffsetY] = object.asConstructed(); + object.setRenderable(true); + object.setActive(true); + return i; + } + if (current.equals(object)) { + // Just reactivate the old instance + current.setRenderable(true); + current.setActive(true); + return i; + } + } + throw new IllegalStateException("RC add insufficient array length for storing object " + object); + } + + /** + * Adds an NPC to this chunk. + * @param npc The NPC to add. + */ + public void add(NPC npc) { + npcs.add(npc); + } + + /** + * Adds a player to this chunk. + * @param player The player. + */ + public void addPlayer(Player player) { + players.add(player); + Region region = getCurrentBase().getRegion(); + region.getTolerances().put(player.getName(), System.currentTimeMillis()); + } + + /** + * Adds an item to this region. + * @param item The item. + */ + public void add(GroundItem item) { + items.add(item); + if (item.isPrivate()) { + if (item.getDropper() != null) { + PacketRepository.send(ConstructGroundItem.class, new BuildItemContext(item.getDropper(), item)); + } + return; + } + flag(new ItemUpdateFlag(item, ItemUpdateFlag.CONSTRUCT_TYPE)); + } + + /** + * Removes an NPC from this chunk. + * @param npc The NPC. + */ + public void remove(NPC npc) { + npcs.remove(npc); + } + + /** + * Removes a player from this chunk. + * @param player The player. + */ + public void removePlayer(Player player) { + players.remove(player); + Region region = getCurrentBase().getRegion(); + region.getTolerances().remove(player.getName()); + } + + /** + * Removes an item from this chunk. + * @param item The ground item. + */ + public void remove(GroundItem item) { + Location l = item.getLocation(); + if (!items.remove(item)) { + return; + } + if (item.isPrivate()) { + if (item.getDropper() != null && item.getDropper().isPlaying() && item.getDropper().getLocation().withinDistance(l)) { + PacketRepository.send(ClearGroundItem.class, new BuildItemContext(item.getDropper(), item)); + } + return; + } + flag(new ItemUpdateFlag(item, ItemUpdateFlag.REMOVE_TYPE)); + } + + /** + * Gets the npcs. + * @return The npcs. + */ + public List getNpcs() { + return npcs; + } + + /** + * Assembles a flat object list. + * @return The objects. + */ + public List assembleObjectList() { + ArrayList list = new ArrayList<>(ARRAY_SIZE); + for (int offsetX = 0; offsetX < 8; offsetX++) { + for (int offsetY = 0; offsetY < 8; offsetY++) { + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery object = objects[i][offsetX][offsetY]; + if (object != null) { + list.add(object); + } + } + } + } + return list; + } + + public List getEntities() { + List entities = new ArrayList<>(assembleObjectList()); + entities.addAll(npcs); + return entities; + } + + /** + * Gets the players. + * @return The players. + */ + public List getPlayers() { + return players; } /** @@ -94,18 +344,26 @@ public class RegionChunk { * @param flag The flag. */ public void flag(UpdateFlag flag) { - flags.add(flag); + updateFlags.add(flag); } /** * Clears the region chunk. */ public void clear() { - flags.clear(); - if (items != null && plane.getRegion() instanceof DynamicRegion) { + updateFlags.clear(); + Region region = RegionManager.forId(currentBase.getRegionId()); + if (items != null && region instanceof DynamicRegion) { items.clear(); items = null; } + for (int i = 0; i < objects.length; i++) { + for (int x = 0; x < objects[i].length; x++) { + for (int y = 0; y < objects[i][x].length; y++) { + statObjects[i][x][y] = objects[i][x][y] = null; + } + } + } } /** @@ -123,29 +381,26 @@ public class RegionChunk { * Writes the region chunk update data on the buffer. * @param player The player we're updating for. * @param buffer The buffer to write on. - * @return {@code True} if an update occured. + * @return {@code True} if an update occurred. */ protected boolean appendUpdate(Player player, IoBuffer buffer) { boolean updated = false; - int baseX = currentBase.getLocalX(); - int baseY = currentBase.getLocalY(); - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - Scenery dyn = objects[x][y]; - if (dyn == null || plane.getObjects() == null) { - continue; - } - Scenery stat = plane.getObjects()[baseX + x][baseY + y]; - if (!dyn.isRenderable() && stat != null) { - ClearScenery.write(buffer, stat); - updated = true; - } - else if (dyn != stat) { + for (int i = 0; i < objects.length; i++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + Scenery dyn = objects[i][x][y]; + Scenery stat = statObjects[i][x][y]; + if (dyn == stat) { + continue; + } if (stat != null) { ClearScenery.write(buffer, stat); + updated = true; + } + if (dyn != null) { + ConstructScenery.write(buffer, dyn); + updated = true; } - ConstructScenery.write(buffer, dyn); - updated = true; } } } @@ -161,7 +416,6 @@ public class RegionChunk { return updated; } - public ArrayList drawItems(List items, Player player) { ArrayList totalItems = items != null ? new ArrayList(items) : new ArrayList(); @@ -225,89 +479,16 @@ public class RegionChunk { public void update(Player player) { if (isUpdated()) { IoBuffer buffer = UpdateAreaPosition.getChunkUpdateBuffer(player, currentBase); - Object[] flagsArray = flags.toArray(); + Object[] flagsArray = updateFlags.toArray(); int size = flagsArray.length; - for (int i = 0; i < size; i++) { - UpdateFlag flag = (UpdateFlag) flagsArray[i]; + for (Object o : flagsArray) { + UpdateFlag flag = (UpdateFlag) o; flag.writeDynamic(buffer, player); } player.getSession().write(buffer); } } - /** - * Rotates the chunk. - * @param direction The direction. - */ - public void rotate(Direction direction) { - if (rotation != 0) { - log(this.getClass(), Log.ERR, "Region chunk was already rotated!"); - return; - } - Scenery[][] copy = new Scenery[SIZE][SIZE]; - Scenery[][] staticCopy = new Scenery[SIZE][SIZE]; - int baseX = currentBase.getLocalX(); - int baseY = currentBase.getLocalY(); - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - copy[x][y] = objects[x][y]; - staticCopy[x][y] = plane.getObjects()[baseX + x][baseY + y]; - objects[x][y] = plane.getObjects()[baseX + x][baseY + y] = null; - plane.getFlags().clearFlag(baseX + x, baseY + y); - } - } - rotation = direction.toInteger(); - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - Scenery object = copy[x][y]; - Scenery stat = staticCopy[x][y]; - boolean match = object == stat; - if (stat == null) { - continue; - } - int[] pos = getRotatedPosition(x, y, stat.getDefinition().getSizeX(), stat.getDefinition().getSizeY(), stat.getRotation(), rotation); - if (object != null) { - object = object.transform(object.getId(), (object.getRotation() + rotation) % 4, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); - LandscapeParser.flagScenery(plane, baseX + pos[0], baseY + pos[1], object, true, true); - } - if (match) { - stat = object; - } else { - stat = stat.transform(stat.getId(), (stat.getRotation() + rotation) % 4, stat.getLocation().transform(pos[0] - x, pos[1] - y, 0)); - } - plane.getObjects()[baseX + pos[0]][baseY + pos[1]] = stat; - } - } - } - - /** - * Gets the new coordinates for an object/chunk tile when rotating. - * @param x The current x-coordinate. - * @param y The current y-coordinate. - * @param sizeX The x-size of the object. - * @param sizeY The y-size of the object. - * @param rotation The object rotation. - * @param chunkRotation The chunk rotation. - * @return The new x-coordinate. - */ - public static int[] getRotatedPosition(int x, int y, int sizeX, int sizeY, int rotation, int chunkRotation) { - if ((rotation & 0x1) == 1) { - int s = sizeX; - sizeX = sizeY; - sizeY = s; - } - if (chunkRotation == 0) { - return new int[] { x, y }; - } - if (chunkRotation == 1) { - return new int[] { y, 7 - x - (sizeX - 1) }; - } - if (chunkRotation == 2) { - return new int[] { 7 - x - (sizeX - 1), 7 - y - (sizeY - 1) }; - } - return new int[] { 7 - y - (sizeY - 1), x }; - } - /** * Gets the items. * @return The items. @@ -328,29 +509,64 @@ public class RegionChunk { } /** - * Gets the scenerys located on the coordinates in this chunk. + * Gets the sceneries located on the coordinates in this chunk. * @param chunkX The chunk x-coordinate (0-7). * @param chunkY The chunk y-coordinate (0-7). * @return The objects. */ public Scenery[] getObjects(int chunkX, int chunkY) { - return new Scenery[] { objects[chunkX][chunkY] }; + Scenery[] result = new Scenery[ARRAY_SIZE]; + for (int i = 0; i < objects.length; i++) { + result[i] = objects[i][chunkX][chunkY]; + } + return result; + } + + /** + * Gets the static objects. + * @return The static objects. + */ + public Scenery[][][] getStatObjects() { + return statObjects; } /** * Gets the objects. * @return The objects. */ - public Scenery[][] getObjects() { + public Scenery[][][] getObjects() { return objects; } /** - * Sets the objects. - * @param objects The objects to set. + * Gets the objects index for the given object id and/or scenery type. + * @param x The x-coordinate on the region chunk. + * @param y The y-coordinate on the region chunk. + * @param objectId The object id. + * @param type The scenery type. */ - public void setObjects(Scenery[][] objects) { - this.objects = objects; + public int getIndex(int x, int y, int objectId, int type) { + for (int i = 0; i < objects.length; i++) { + Scenery o = objects[i][x][y]; + if (o != null) { + if (objectId < 0) { + if (type >= 0 && o.getType() != type) { + continue; + } + // Caller didn't ask for anything specific, so we assume they want whatever *interactable-excluding-examine* object is in here + // We should probably discourage this and instead make functions calling this function more specific + if (o.getDefinition().hasOptions(false)) { + return i; + } + } else { + if (o.getId() == objectId) { + // TODO: what if there are multiple instances of the same object? Hopefully this is only a theoretical possibility in this game + return i; + } + } + } + } + return 0; } /** @@ -390,22 +606,14 @@ public class RegionChunk { * @return The updated. */ public boolean isUpdated() { - return !flags.isEmpty(); + return !updateFlags.isEmpty(); } /** * Resets the flags. */ public void resetFlags() { - flags.clear(); - } - - /** - * Gets the region plane. - * @return The plane. - */ - public RegionPlane getPlane() { - return plane; + updateFlags.clear(); } /** @@ -424,18 +632,124 @@ public class RegionChunk { this.currentBase = currentBase; } - public void rebuildFlags(RegionPlane from) { + /** + * Reinitializes the clipping flags; used when a region is copied into a new dynamic region. + */ + public void syncFlagsToRegionManager() { + flags = new ChunkFlags(currentBase.getX(), currentBase.getY(), currentBase.getZ()); + projectileFlags = new ChunkFlags(currentBase.getX(), currentBase.getY(), currentBase.getZ(), true); + } + + /** + * Rebuilds the clipping flags based on those of a source chunk (used when a chunk is being replaced). + * @param from The region plane to get the new clipping flags from. + */ + public void rebuildFlags(RegionChunk from) { for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { - Location loc = currentBase.transform(x,y,0); - Location fromLoc = base.transform(x,y,0); - plane.getFlags().getLandscape()[loc.getLocalX()][loc.getLocalY()] = from.getFlags().getLandscape()[fromLoc.getLocalX()][fromLoc.getLocalY()]; - plane.getFlags().clearFlag(x, y); - Scenery obj = objects[x][y]; - if (obj != null) - LandscapeParser.flagScenery(plane, loc.getLocalX(), loc.getLocalY(), obj, false, true); + // Import the landscape flags from the template chunk to the new chunk + flags.getLandscape()[x][y] = from.getFlags().getLandscape()[x][y]; + projectileFlags.getLandscape()[x][y] = from.getProjectileFlags().getLandscape()[x][y]; + // Reflag any objects + for (int i = 0; i < objects.length; i++) { + Scenery obj = objects[i][x][y]; + if (obj != null) { + LandscapeParser.flagScenery(this, x, y, obj, false, true); + } + } } } } + /** + * Rotates the chunk. + * @param direction The direction. + */ + public void rotate(Direction direction) { + if (rotation != 0) { + log(this.getClass(), Log.ERR, "Region chunk was already rotated!"); + return; + } + Scenery[][][] copy = new Scenery[ARRAY_SIZE][SIZE][SIZE]; + int baseX = currentBase.getLocalX(); + int baseY = currentBase.getLocalY(); + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + for (int i = 0; i < objects.length; i++) { + Scenery object = copy[i][x][y] = objects[i][x][y]; + if (object != null) { + SceneryBuilder.remove(object); + objects[i][x][y] = null; + } + } + } + } + clear(); + switch(direction) { + case NORTH: rotation = 0; break; + case EAST: rotation = 1; break; + case SOUTH: rotation = 2; break; + case WEST: rotation = 3; break; + default: rotation = (direction.toInteger() + (direction.toInteger() % 2 == 0 ? 2 : 0)) % 4; + log(this.getClass(), Log.ERR, "Attempted to rotate a chunk in a non-cardinal direction - using fallback rotation code. This should be investigated!"); + break; + }; + for (int i = 0; i < objects.length; i++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + Scenery object = copy[i][x][y]; + if (object != null) { + int[] pos = getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation); + Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); + if (object instanceof Constructed) { + obj = obj.asConstructed(); + } + obj.setActive(object.isActive()); + obj.setRenderable(object.isRenderable()); + LandscapeParser.flagScenery(this, pos[0], pos[1], obj, true, true); + } + } + } + } + } + + /** + * Gets the new coordinates for an object/chunk tile when rotating. + * @param x The current x-coordinate. + * @param y The current y-coordinate. + * @param sizeX The x-size of the object. + * @param sizeY The y-size of the object. + * @param rotation The object rotation. + * @param chunkRotation The chunk rotation. + * @return The new x-coordinate. + */ + public static int[] getRotatedPosition(int x, int y, int sizeX, int sizeY, int rotation, int chunkRotation) { + if ((rotation & 0x1) == 1) { + int s = sizeX; + sizeX = sizeY; + sizeY = s; + } + if (chunkRotation == 0) { + return new int[] { x, y }; + } + if (chunkRotation == 1) { + return new int[] { y, 7 - x - (sizeX - 1) }; + } + if (chunkRotation == 2) { + return new int[] { 7 - x - (sizeX - 1), 7 - y - (sizeY - 1) }; + } + return new int[] { 7 - y - (sizeY - 1), x }; + } + + public ChunkFlags getFlags() { + return flags; + } + + public ChunkFlags getProjectileFlags() { + return projectileFlags; + } + + public Region getRegion() { + return RegionManager.forId(currentBase.getRegionId()); + } } diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 9fb7b848b..b58cb17f6 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -9,11 +9,9 @@ import core.game.node.scenery.Scenery import core.game.world.map.zone.ZoneBorders import core.tools.Log import core.tools.RandomFunction -import core.tools.SystemLogger import java.util.* import java.util.concurrent.TimeUnit import java.util.concurrent.locks.ReentrantLock -import kotlin.collections.HashMap /** * Manages the regions. @@ -27,7 +25,7 @@ object RegionManager { @JvmStatic val CLIPPING_FLAGS = HashMap>() @JvmStatic val PROJECTILE_FLAGS = HashMap>() - public val LOCK = ReentrantLock() + val LOCK = ReentrantLock() /** * Gets the region for the given region id. @@ -36,7 +34,7 @@ object RegionManager { */ @JvmStatic fun forId(regionId: Int): Region { - if(LOCK.tryLock() || LOCK.tryLock(10000, TimeUnit.MILLISECONDS)) { + if (LOCK.tryLock() || LOCK.tryLock(10000, TimeUnit.MILLISECONDS)) { var region = REGION_CACHE[regionId] if (region == null) { region = Region((regionId shr 8) and 0xFF, regionId and 0xFF) @@ -45,21 +43,19 @@ object RegionManager { LOCK.unlock() return REGION_CACHE[regionId]!! } - log(this::class.java, Log.ERR, "UNABLE TO OBTAIN LOCK WHEN GETTING REGION BY ID. RETURNING BLANK REGION.") - return Region(0,0) + log(this::class.java, Log.ERR, "UNABLE TO OBTAIN LOCK WHEN GETTING REGION BY ID. RETURNING BLANK REGION.") + return Region(0, 0) } /** - * Pulses the active regions. + * Applies a function to all active regions */ @JvmStatic - fun pulse() { - if(LOCK.tryLock() || LOCK.tryLock(10000,TimeUnit.MILLISECONDS)) { + fun apply(callback: (r: Region) -> Unit) { + if (LOCK.tryLock() || LOCK.tryLock(10000,TimeUnit.MILLISECONDS)) { for (r in REGION_CACHE.values) { if (r.isActive) { - for (p in r.planes) { - p.pulse() - } + callback(r) } } LOCK.unlock() @@ -67,13 +63,19 @@ object RegionManager { } /** - * Gets the clipping flag on the given location. - * @param l The location. - * @return The clipping flag. + * Pulses the active regions. */ @JvmStatic - fun getClippingFlag(l: Location): Int { - return getClippingFlag(l.z, l.x, l.y) + fun pulse() { + apply { r -> + for (x in 0 until 8) { + for (y in 0 until 8) { + for (z in 0 until 4) { + r.chunks[x][y][z]?.resetFlags() + } + } + } + } } /** @@ -85,56 +87,36 @@ object RegionManager { */ @JvmStatic fun getClippingFlag(z: Int, x: Int, y: Int): Int { - val regionX = x shr 6 - val regionY = y shr 6 - val localX = x and 63 - val localY = y and 63 - return getClippingFlag(z, regionX, regionY, localX, localY) + return getClippingFlag(Location(x, y, z)) } /** - * Gets the clipping flags using Jagex-style coords - * e.g 0_50_50_13_13 gets plane 0, region 50-50 (12850), (13, 13) which is in lumbridge. + * Gets the clipping flag. + * @param loc The location. + * @param projectile Clipping flags or projectile flags. */ @JvmStatic - fun getClippingFlag(z: Int, regionX: Int, regionY: Int, localX: Int, localY: Int, projectile: Boolean = false) : Int { - val (region, index) = getFlagIndex(z, regionX, regionY, localX, localY) - var flag = getFlags(region, projectile)[index] - - if (flag == -1) { - val r = forId((regionX shr 8) or regionY) - if (!r.isLoaded) - Region.load(r) - if (!r.isHasFlags) - return -1 - flag = getFlags(region, projectile)[index] + fun getClippingFlag(loc: Location, projectile: Boolean = false) : Int { + val region = forId(loc.regionId) + Region.load(region) + if (!region.isHasFlags) { + return -1 } - - return flag + // Index by absChunkX and absChunkY coordinates; these give the position of the chunk on the world map. Together with chunkOffsetX and chunkOffsetY, they identify individual tiles. + val (key, index) = getFlagIndex(loc.absChunkX, loc.absChunkY, loc.z, loc.chunkOffsetX, loc.chunkOffsetY) + return getFlags(key, projectile)[index] } - private fun getFlagIndex(z: Int, regionX: Int, regionY: Int, localX: Int, localY: Int) : Pair { - return Pair((regionX shl 8) or regionY, (z * 64 * 64) + (localX * 64) + localY) + private fun getFlagIndex(absChunkX: Int, absChunkY: Int, z: Int, chunkOffsetX: Int, chunkOffsetY: Int) : Pair { + return Pair((z shl 22) or (absChunkX shl 11) or absChunkY, (chunkOffsetX * 8) + chunkOffsetY) } @JvmStatic - fun getFlags(regionX: Int, regionY: Int, projectile: Boolean) : Array { - val region = (regionX shl 8) or regionY - return getFlags(region, projectile) - } - - @JvmStatic - fun getFlags(regionId: Int, projectile: Boolean) : Array { + fun getFlags(chunkId: Int, projectile: Boolean) : Array { return if (projectile) - PROJECTILE_FLAGS.getOrPut (regionId) {Array(16384){0}} + PROJECTILE_FLAGS.getOrPut(chunkId) { Array(64){0} } else - CLIPPING_FLAGS.getOrPut (regionId) {Array(16384){-1}} - } - - @JvmStatic - fun resetFlags(regionId: Int) { - PROJECTILE_FLAGS.put (regionId, Array(16384){0}) - CLIPPING_FLAGS.put (regionId, Array(16384){-1}) + CLIPPING_FLAGS.getOrPut(chunkId) { Array(64){-1} } } /** @@ -144,41 +126,37 @@ object RegionManager { */ @JvmStatic fun getWaterClipFlag(z: Int, x: Int, y: Int): Int { - val flag = getClippingFlag(z, x, y) - return if (!isClipped(z, x, y)) { + return getWaterClipFlag(Location(x, y, z)) + } + + /** + * Gets the water variant of a tile's clipping flag + * Essentially strips the landscape flag off a tile and keeps other flags, and makes normally walkable tiles unwalkable. + */ + @JvmStatic + fun getWaterClipFlag(loc: Location): Int { + val flag = getClippingFlag(loc) + return if (!isClipped(loc)) { flag or 0x100 } else flag and 0x200000.inv() } /** * Checks if the tile is part of the landscape. - * @param l The location. + * @param loc The location. * @return `True` if so. */ @JvmStatic - fun isLandscape(l: Location): Boolean { - return isLandscape(l.z, l.x, l.y) - } - - /** - * Checks if the tile is part of the landscape. - * @param z The plane. - * @param x The absolute x-coordinate. - * @param y The absolute y-coordinate. - * @return `True` if so. - */ - @JvmStatic - fun isLandscape(z: Int, x: Int, y: Int): Boolean { - var x = x - var y = y - val region = forId(((x shr 6) shl 8) or (y shr 6)) + fun isLandscape(loc: Location): Boolean { + val region = forId(loc.regionId) Region.load(region) - if (!region.isHasFlags || region.planes[z].flags.landscape == null) { + if (!region.isHasFlags) { return false } - x -= x shr 6 shl 6 - y -= y shr 6 shl 6 - return region.planes[z].flags.landscape[x][y] + if (loc.chunk.flags.landscape == null) { + return false + } + return loc.chunk.flags.landscape[loc.chunkOffsetX][loc.chunkOffsetY] } /** @@ -191,24 +169,31 @@ object RegionManager { */ @JvmStatic fun addClippingFlag(z: Int, x: Int, y: Int, projectile: Boolean, flag: Int) { - var x = x - var y = y - val region = forId(((x shr 6) shl 8) or (y shr 6)) - Region.load(region) - if (!region.isHasFlags) { - return - } - x -= (x shr 6) shl 6 - y -= (y shr 6) shl 6 - if (projectile) { - region.planes[z].projectileFlags.flag(x, y, flag) - } else { - region.planes[z].flags.flag(x, y, flag) - } + return addClippingFlag(Location(x, y, z), projectile, flag) } /** * Adds a clipping flag. + * @param loc The location. + * @param projectile If the flag is being set for projectile pathfinding. + * @param flag The clipping flag. + */ + @JvmStatic + fun addClippingFlag(loc: Location, projectile: Boolean, flag: Int) { + val region = forId(loc.regionId) + Region.load(region) + if (!region.isHasFlags) { + return + } + if (projectile) { + loc.chunk.projectileFlags.flag(loc.chunkOffsetX, loc.chunkOffsetY, flag) + } else { + loc.chunk.flags.flag(loc.chunkOffsetX, loc.chunkOffsetY, flag) + } + } + + /** + * Removes a clipping flag. * @param z The plane. * @param x The absolute x-coordinate. * @param y The absolute y-coordinate. @@ -217,24 +202,31 @@ object RegionManager { */ @JvmStatic fun removeClippingFlag(z: Int, x: Int, y: Int, projectile: Boolean, flag: Int) { - var x = x - var y = y - val region = forId(((x shr 6) shl 8) or (y shr 6)) + return removeClippingFlag(Location(x, y, z), projectile, flag) + } + + /** + * Removes a clipping flag. + * @param loc The location. + * @param projectile If the flag is being set for projectile pathfinding. + * @param flag The clipping flag. + */ + @JvmStatic + fun removeClippingFlag(loc: Location, projectile: Boolean, flag: Int) { + val region = forId(loc.regionId) Region.load(region) if (!region.isHasFlags) { return } - x -= (x shr 6) shl 6 - y -= (y shr 6) shl 6 if (projectile) { - region.planes[z].projectileFlags.unflag(x, y, flag) + loc.chunk.projectileFlags.unflag(loc.chunkOffsetX, loc.chunkOffsetY, flag) } else { - region.planes[z].flags.unflag(x, y, flag) + loc.chunk.flags.unflag(loc.chunkOffsetX, loc.chunkOffsetY, flag) } } /** - * Gets the clipping flag. + * Gets the projectile flag. * @param z The plane. * @param x The absolute x-coordinate. * @param y The absolute y-coordinate. @@ -242,62 +234,34 @@ object RegionManager { */ @JvmStatic fun getProjectileFlag(z: Int, x: Int, y: Int): Int { - val regionX = x shr 6 - val regionY = y shr 6 - val localX = x and 63 - val localY = y and 63 - return getClippingFlag(z, regionX, regionY, localX, localY, true) + return getClippingFlag(Location(x, y, z), true) } /** - * Gets the clipping flag - * @param location the Location - * @return the clipping flag + * Checks if teleport is permitted. + * @param loc The Location. + * @return If teleport is permitted. */ @JvmStatic - fun isTeleportPermitted(location: Location): Boolean { - return isTeleportPermitted(location.z, location.x, location.y) - } - - /** - * Gets the clipping flag. - * @param z The plane. - * @param x The absolute x-coordinate. - * @param y The absolute y-coordinate. - * @return The clipping flags. - */ - @JvmStatic - fun isTeleportPermitted(z: Int, x: Int, y: Int): Boolean { - if (!isLandscape(z, x, y)) { + fun isTeleportPermitted(loc: Location): Boolean { + if (!isLandscape(loc)) { return false } - val flag = getClippingFlag(z, x, y) + val flag = getClippingFlag(loc) return flag and 0x12c0102 == 0 || flag and 0x12c0108 == 0 || flag and 0x12c0120 == 0 || flag and 0x12c0180 == 0 } /** * Checks if the location has any clipping flags. - * @param location The location. + * @param loc The location. * @return `True` if a clipping flag disables access for this location. */ @JvmStatic - fun isClipped(location: Location): Boolean { - return isClipped(location.z, location.x, location.y) - } - - /** - * Checks if the location has any clipping flags. - * @param z The plane. - * @param x The x-coordinate. - * @param y The y-coordinate. - * @return `True` if a clipping flag disables access for this location. - */ - @JvmStatic - fun isClipped(z: Int, x: Int, y: Int): Boolean { - if (!isLandscape(z, x, y)) { + fun isClipped(loc: Location): Boolean { + if (!isLandscape(loc)) { return true } - val flag = getClippingFlag(z, x, y) + val flag = getClippingFlag(loc) return flag and 0x12c0102 != 0 || flag and 0x12c0108 != 0 || flag and 0x12c0120 != 0 || flag and 0x12c0180 != 0 } @@ -355,6 +319,17 @@ object RegionManager { return getObject(l.z, l.x, l.y) } + /** + * Gets the scenery on the current location of the same type as a different piece of scenery. + * @param l The location. + * @param type The scenery type. + * @return The scenery, or `null` if no object was found. + */ + @JvmStatic + fun getObject(l: Location, type: Int): Scenery? { + return getObject(l.z, l.x, l.y, -1, type) + } + /** * Gets the scenery on the current absolute coordinates. * @param z The height. @@ -377,28 +352,30 @@ object RegionManager { */ @JvmStatic fun getObject(z: Int, x: Int, y: Int, objectId: Int): Scenery? { - var x = x - var y = y - val regionId = ((x shr 6) shl 8) or (y shr 6) - x -= (x shr 6) shl 6 - y -= (y shr 6) shl 6 - val region = forId(regionId) - Region.load(region) - val `object`: Scenery? = region.planes[z].getChunkObject(x, y, objectId) - return if (`object` != null && !`object`.isRenderable) { - null - } else `object` + return getObject(z, x, y, objectId, -1) } /** - * Gets the region plane for this location. - * @param l The location. - * @return The region plane. + * Gets the object on the given absolute coordinates. + * @param z The height. + * @param x The x-coordinate. + * @param y The y-coordinate. + * @param objectId The object id. May be -1, which means 'any'. + * @param type The scenery type. May be -1, which means 'any'. + * @return The scenery, or `null` if no object was found. */ @JvmStatic - fun getRegionPlane(l: Location): RegionPlane { - val regionId = ((l.x shr 6) shl 8) or (l.y shr 6) - return forId(regionId).planes[l.z] + fun getObject(z: Int, x: Int, y: Int, objectId: Int, type: Int): Scenery? { + val loc = Location(x, y, z) + val region = forId(loc.regionId) + Region.load(region) + val chunk = region.chunks[loc.chunkX][loc.chunkY][loc.z] + val index = chunk.getIndex(loc.chunkOffsetX, loc.chunkOffsetY, objectId, type) + val obj = chunk.objects[index][loc.chunkOffsetX][loc.chunkOffsetY] + if (obj != null && !obj.isRenderable) { + return null + } + return obj } /** @@ -408,247 +385,75 @@ object RegionManager { */ @JvmStatic fun getRegionChunk(l: Location): RegionChunk { - val plane = getRegionPlane(l) - return plane.getRegionChunk(l.localX / RegionChunk.SIZE, l.localY / RegionChunk.SIZE) + val regionId = ((l.x shr 6) shl 8) or (l.y shr 6) + return forId(regionId).chunks[l.chunkX][l.chunkY][l.z] } /** - * Moves the entity from the current region to the new one. + * Moves the entity from the current chunk to the new one. * @param entity The entity. */ @JvmStatic - fun move(entity: Entity) { - val player = entity is Player - val regionId = ((entity.location.regionX shr 3) shl 8) or (entity.location.regionY shr 3) - val viewport = entity.viewport - val current = forId(regionId) - val z = entity.location.z - val plane = current.planes[z] - viewport.updateViewport(entity) - if (plane == viewport.currentPlane) { - entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint) - return - } - viewport.remove(entity) - if (player) { - current.add(entity as Player) - } else { - current.add(entity as NPC) - } - viewport.region = current - viewport.currentPlane = plane - val view: MutableList = LinkedList() - for (regionX in ((entity.location.regionX shr 3) - 1)..((entity.location.regionX shr 3) + 1)) { - for (regionY in ((entity.location.regionY shr 3) - 1)..((entity.location.regionY shr 3) + 1)) { - if (regionX < 0 || regionY < 0) { - continue + fun move(entity: Entity, src: Location, dst: Location) { + if (src.chunk != dst.chunk) { + when (entity) { + is Player -> { + src.chunk.removePlayer(entity) + src.region.decrementViewAmount() + dst.chunk.addPlayer(entity) + dst.region.incrementViewAmount() + dst.region.flagActive() } - val region = forId((regionX shl 8) or regionY) - val p = region.planes[z] - if (player) { - region.incrementViewAmount() - region.flagActive() + is NPC -> { + src.chunk.remove(entity) + dst.chunk.add(entity) + } + else -> { + throw (IllegalStateException("Tried to move an Entity that was neither Player nor NPC")) } - view.add(p) } } - viewport.viewingPlanes = view entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint) } /** - * Gets the list of local NPCs with a maximum distance of 16. - * @param n The entity. - * @return The list of local NPCs. - */ - @JvmStatic - fun getLocalNpcs(n: Entity): List { - return getLocalNpcs(n, MapDistance.RENDERING.distance) - } - - /** - * Gets the location entitys. + * Gets local entities. You never call the below function directly (it's inlined); instead, you use one of the typed helpers defined directly below this function. * @param location the location. * @param distance the distance. + * @param maximum the maximum number of entities to return. + * @param ignore an entity to exclude (may be null). * @return the list. */ - @JvmStatic - fun getLocalEntitys(location: Location, distance: Int): List { - val entitys: MutableList = ArrayList(20) - entitys.addAll(getLocalNpcs(location, distance)) - entitys.addAll(getLocalPlayers(location, distance)) - return entitys - } - - /** - * Gets the location entitys. - * @param entity the entity. - * @param distance the distance. - * @return the list. - */ - @JvmStatic - fun getLocalEntitys(entity: Entity, distance: Int): List { - return getLocalEntitys(entity.location, distance) - } - - /** - * Gets the local entitys. - * @param entity the entity. - * @return the entitys. - */ - @JvmStatic - fun getLocalEntitys(entity: Entity): List { - return getLocalEntitys(entity.location, MapDistance.RENDERING.distance) - } - - /** - * Gets the list of local NPCs. - * @param n The entity. - * @param distance The distance to the entity. - * @return The list of local NPCs. - */ - @JvmStatic - fun getLocalNpcs(n: Entity, distance: Int): List { - val npcs: MutableList = LinkedList() - for (r in n.viewport.viewingPlanes) { - for (npc in r.npcs) { - if (npc.location.withinDistance(n.location, distance)) { - npcs.add(npc) + inline fun getLocalEntities(location: Location, distance: Int, maximum: Int, ignore: Entity?): List { + val entities: MutableList = ArrayList(20) + for (cx in (location.absChunkX - 2)..(location.absChunkX + 2)) { + for (cy in (location.absChunkY - 2)..(location.absChunkY + 2)) { + val chunk = Location(cx shl 3, cy shl 3, location.z).chunk + if (Player::class.java.isAssignableFrom(T::class.java)) { + entities.addAll(chunk.players as Collection) + } + if (NPC::class.java.isAssignableFrom(T::class.java)) { + entities.addAll(chunk.npcs as Collection) } } } - return npcs - } - - /** - * Gets the list of local players with a maximum distance of 15. - * @param n The entity. - * @return The list of local players. - */ - @JvmStatic - fun getLocalPlayers(n: Entity): List { - return getLocalPlayers(n, MapDistance.RENDERING.distance) - } - - /** - * Gets the list of local players. - * @param n The entity. - * @param distance The distance to the entity. - * @return The list of local players. - */ - @JvmStatic - fun getLocalPlayers(n: Entity, distance: Int): List { - val players: MutableList = LinkedList() - for (r in n.viewport.viewingPlanes) { - for (p in r.players) { - if (p.location.withinDistance(n.location, distance)) { - players.add(p) - } - } + val b = ZoneBorders(location.x - distance, location.y - distance, location.x + distance, location.y + distance) + var filtered = entities.filter { it != ignore && b.insideBorder(it.location.x, it.location.y) } + if (maximum > 0 && filtered.size > maximum) { + filtered = filtered.slice(0 until maximum) } - return players - } - - /** - * Gets the surrounding players. - * @param n The node the players should be surrounding. - * @param ignore The nodes not to add to the list. - * @return The list of players. - */ - @JvmStatic - fun getSurroundingPlayers(n: Node, vararg ignore: Node): List { - return getSurroundingPlayers(n, 9, *ignore) - } - - /** - * Gets the surrounding players. - * @param n The node the players should be surrounding. - * @param ignore The nodes not to add to the list. - * @return The list of players. - */ - @JvmStatic - fun getSurroundingPlayers(n: Node, maximum: Int, vararg ignore: Node): List { - val players = getLocalPlayers(n.location, 2) - var count = 0 - val it = players.iterator() - while (it.hasNext()) { - val p = it.next() - if(p.isInvisible()) { - it.remove() - } - if(!p.location.withinMaxnormDistance(n.location, 1)) { - it.remove() - continue - } - if (++count >= maximum) { - it.remove() - continue - } - for (node in ignore) { - if (p === node) { - count-- - it.remove() - break - } - } - } - return players - } - - /** - * Gets the surrounding players. - * @param n The node the players should be surrounding. - * @param ignore The nodes not to add to the list. - * @return The list of players. - */ - @JvmStatic - fun getSurroundingNPCs(n: Node, vararg ignore: Node): List { - return getSurroundingNPCs(n, 9, *ignore) - } - - /** - * Gets the surrounding players. - * @param n The node the npcs should be surrounding. - * @param ignore The nodes not to add to the list. - * @return The list of npcs. - */ - @JvmStatic - fun getSurroundingNPCs(n: Node, maximum: Int, vararg ignore: Node): List { - val npcs = getLocalNpcs(n.location, 2) - var count = 0 - val it = npcs.iterator() - while (it.hasNext()) { - val p = it.next() - if(p.properties.teleportLocation != null && !p.properties.teleportLocation.withinMaxnormDistance(n.location, 1)) { - it.remove() - continue - } - if(p.getAttribute("state:death", false)) { - it.remove() - continue - } - if(p.isInvisible()) { - it.remove() - continue - } - if(!p.location.withinMaxnormDistance(n.location, 1)) { - it.remove() - continue - } - if (++count > maximum) { - it.remove() - continue - } - for (node in ignore) { - if (p === node) { - count-- - it.remove() - break - } - } - } - return npcs + return filtered } + @JvmStatic fun getLocalEntities(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) + @JvmStatic fun getLocalPlayers(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) + @JvmStatic fun getLocalNPCs(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) + @JvmStatic fun getLocalPlayers(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0, null) + @JvmStatic fun getLocalNPCs(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0, null) + @JvmStatic fun getSurroundingPlayers(player: Entity, maximum: Int): List = getLocalEntities(player.location, 1, maximum, null) + @JvmStatic fun getSurroundingNPCs(npc: Entity, maximum: Int): List = getLocalEntities(npc.location, 1, maximum, null) + @JvmStatic fun getLocalPlayersBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum, null) + @JvmStatic fun getLocalNPCBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum, null) + @JvmStatic fun getLocalEntitys(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) //typoed version to avoid merge conflict with !2269 /** * Gets a random teleport location in the radius around the given location. @@ -701,162 +506,14 @@ object RegionManager { } /** - * Gets the current viewport for the location. - * @param l The location. - * @return The viewport. - */ - @JvmStatic - fun getViewportPlayers(l: Location): List { - var l = l - val players: MutableList = LinkedList() - l = l.chunkBase.transform(-8, -8, 0) - val b = ZoneBorders(l.x, l.y, l.x + 24, l.y + 24) - for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) { - for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) { - for (player in forId(regionX shl 8 or regionY).planes[l.z].players) { - l = player.location - if (b.insideBorder(l.x, l.y)) { - players.add(player) - } - } - } - } - return players - } - - /** - * Gets a list of players in the given region. - * @param regionId The region id. - * @return The list of players in this region. - */ - @JvmStatic - fun getRegionPlayers(regionId: Int): List { - val r = forId(regionId) - val players: MutableList = ArrayList(20) - for (plane in r.planes) { - players.addAll(plane.players) - } - return players - } - - /** - * Gets a list of local players within rendering distance of the location. - * @param l The location. - * @return The list of players. - */ - @JvmStatic - fun getLocalPlayers(l: Location): List { - return getLocalPlayers(l, MapDistance.RENDERING.distance) - } - - /** - * Gets a list of local players. - * @param l The location. - * @param distance The distance to that location. - * @return The list of players. - */ - @JvmStatic - fun getLocalPlayers(l: Location, distance: Int): MutableList { - val players: MutableList = LinkedList() - for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) { - for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) { - for (player in forId((regionX shl 8) or regionY).planes[l.z].players) { - if (player.location.withinDistance(l, distance)) { - players.add(player) - } - } - } - } - return players - } - - /** - * Gets a list of local players within a symmetric bounding box. - * @param l The location. - * @param xdist The distance from the location on the x plane that is considered within bounds. - * @param ydist The distance from the location on the y plane that is considered within bounds. - * @return The list of players. - */ - @JvmStatic - fun getLocalPlayersBoundingBox(l: Location, xdist: Int, ydist: Int): MutableList { - val players: MutableList = LinkedList() - for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) { - for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) { - for (player in forId((regionX shl 8) or regionY).planes[l.z].players) { - if (player.location.x >= l.x - xdist && - player.location.x <= l.x + xdist && - player.location.y >= l.y - ydist && - player.location.y <= l.y + ydist) { - players.add(player) - } - } - } - } - return players - } - - /** - * Gets a list of local players. - * @param l The location. - * @param distance The distance to that location. - * @return The list of players. - */ - @JvmStatic - fun getLocalPlayersMaxNorm(l: Location, distance: Int): MutableList { - val players: MutableList = LinkedList() - for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) { - for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) { - for (player in forId((regionX shl 8) or regionY).planes[l.z].players) { - if (player.location.withinMaxnormDistance(l, distance)) { - players.add(player) - } - } - } - } - return players - } - - /** - * Gets a list of local players within 16 tile distance of the location. - * @param l The location. - * @return The list of players. - */ - @JvmStatic - fun getLocalNpcs(l: Location): List { - return getLocalNpcs(l, MapDistance.RENDERING.distance) - } - - /** - * Gets the npc. - * @param entity the entity. - * @param id the id. - */ - @JvmStatic - fun getNpc(entity: Entity, id: Int): NPC? { - return getNpc(entity, id, 16) - } - - /** - * Gets the npc. - * @param entity the entity. - * @param id the id. + * Gets an npc near a location. + * @param id the id, * @param distance the distance. * @return the npc. */ @JvmStatic - fun getNpc(entity: Entity, id: Int, distance: Int): NPC? { - return getNpc(entity.location, id, distance) - } - - /** - * Gets an npc near the entity. - * @param id the id, - * @param distance the dinstance. - * @return the npc. - */ - @JvmStatic fun getNpc(location: Location, id: Int, distance: Int): NPC? { - val npcs: List = getLocalNpcs(location, distance) + val npcs: List = getLocalNPCs(location, distance) for (n in npcs) { if (n.id == id) { return n @@ -865,27 +522,6 @@ object RegionManager { return null } - /** - * Gets a list of local players. - * @param l The location. - * @param distance The distance to that location. - * @return The list of players. - */ - @JvmStatic - fun getLocalNpcs(l: Location, distance: Int): MutableList { - val npcs: MutableList = LinkedList() - for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) { - for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) { - for (n in forId(regionX shl 8 or regionY).planes[l.z].npcs) { - if (n.location.withinDistance(l, (n.size() shr 1) + distance)) { - npcs.add(n) - } - } - } - } - return npcs - } - @JvmStatic fun addRegion(id: Int, region: Region){ if(lock.tryLock() || LOCK.tryLock(10000, TimeUnit.MILLISECONDS)) { diff --git a/Server/src/main/core/game/world/map/RegionPlane.java b/Server/src/main/core/game/world/map/RegionPlane.java deleted file mode 100644 index f83724ec0..000000000 --- a/Server/src/main/core/game/world/map/RegionPlane.java +++ /dev/null @@ -1,444 +0,0 @@ -package core.game.world.map; - -import core.game.node.Node; -import core.game.node.entity.npc.NPC; -import core.game.node.entity.player.Player; -import core.game.node.item.GroundItem; -import core.game.node.item.Item; -import core.game.node.scenery.Scenery; -import core.game.world.map.build.DynamicRegion; -import core.game.world.map.build.RegionFlags; -import core.game.world.update.flag.chunk.ItemUpdateFlag; -import core.net.packet.PacketRepository; -import core.net.packet.context.BuildItemContext; -import core.net.packet.out.ClearGroundItem; -import core.net.packet.out.ConstructGroundItem; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Represents one of the 4 planes of a region. - * @author Emperor - * - */ -public final class RegionPlane { - - /** - * The region size. - */ - public static final int REGION_SIZE = 64; - - /** - * The amount of chunks in this plane. - */ - public static final int CHUNK_SIZE = REGION_SIZE >> 3; - - /** - * Represents a removed scenery. - */ - public static final Scenery NULL_OBJECT = new Scenery(0, Location.create(0, 0, 0)); - - /** - * The plane. - */ - private final int plane; - - /** - * The region. - */ - private final Region region; - - /** - * The region flags. - */ - private final RegionFlags flags; - - /** - * The region projectile flags. - */ - private final RegionFlags projectileFlags; - - /** - * The region chunks. - */ - private final RegionChunk[][] chunks; - - /** - * The list of NPCs in this region. - */ - private final List npcs; - - /** - * The list of players in this region. - */ - private final List players; - - /** - * The scenerys. - */ - private Scenery[][] objects; - - /** - * Constructs a new {@code RegionPlane} {@code Object}. - * @param region The region. - * @param plane The plane. - */ - public RegionPlane(Region region, int plane) { - this.plane = plane; - this.region = region; - this.players = new CopyOnWriteArrayList(); - this.npcs = new CopyOnWriteArrayList(); - Location base = region.getBaseLocation(); - this.flags = new RegionFlags(plane, base.getX(), base.getY()); - this.projectileFlags = new RegionFlags(plane, base.getX(), base.getY(), true); - this.objects = new Scenery[REGION_SIZE][REGION_SIZE]; - this.chunks = new RegionChunk[CHUNK_SIZE][CHUNK_SIZE]; - } - - /** - * Called at the end of the update sequence, if the region is active. - */ - public void pulse() { - Arrays.stream(chunks).forEach(regionChunks -> {Arrays.stream(regionChunks).filter(Objects::nonNull).forEach(RegionChunk::resetFlags);}); - } - - /** - * Adds a scenery. - * @param object The object to add. - * @param x The x-coordinate. - * @param y The y-coordinate. - * @param landscape If this object is added through landscape parsing. - */ - public void add(Scenery object, int x, int y, boolean landscape) { - setChunkObject(x, y, object); - if (landscape) { - objects[x][y] = object; - } - if (object != null) { - object.setRenderable(true); - } - } - - /** - * Gets the region chunk. - * @param chunkX The chunk base x-coordinate. - * @param chunkY The chunk base y-coordinate. - * @return The region chunk. - */ - public RegionChunk getRegionChunk(int chunkX, int chunkY) { - RegionChunk r = chunks[chunkX][chunkY]; - if (r != null) { - return r; - } - if (region.isBuild()) { - return chunks[chunkX][chunkY] = new BuildRegionChunk(region.getBaseLocation().transform(chunkX << 3, chunkY << 3, plane), 0, this); - } - return chunks[chunkX][chunkY] = new RegionChunk(region.getBaseLocation().transform(chunkX << 3, chunkY << 3, plane), 0, this); - } - - public void setRegionChunk(int chunkX, int chunkY, RegionChunk chunk) { - chunks[chunkX][chunkY] = chunk; - } - - /** - * Removes a scenery. - * @param x The x-coordinate. - * @param y The y-coordinate. - */ - public void remove(int x, int y) { - remove(x, y, -1); - } - - /** - * Removes a scenery. - * @param x The x-coordinate. - * @param y The y-coordinate. - * @param objectId The object id. - */ - public void remove(int x, int y, int objectId) { - int chunkX = x / CHUNK_SIZE; - int chunkY = y / CHUNK_SIZE; - int offsetX = x - chunkX * CHUNK_SIZE; - int offsetY = y - chunkY * CHUNK_SIZE; - RegionChunk chunk = getRegionChunk(chunkX, chunkY); - Scenery remove = new Scenery(0, region.getBaseLocation().transform(x, y, plane), 22, 0); - remove.setRenderable(false); - if (chunk instanceof BuildRegionChunk) { - int index = ((BuildRegionChunk) chunk).getIndex(offsetX, offsetY, objectId); - ((BuildRegionChunk) chunk).getObjects(index)[offsetX][offsetY] = remove; - return; - } - chunk.getObjects()[offsetX][offsetY] = remove; - } - - /** - * Sets an object on a chunk. - * @param x The regional x-coordinate. - * @param y The regional y-coordinate. - * @param object The object to set. - */ - private void setChunkObject(int x, int y, Scenery object) { - int chunkX = x / CHUNK_SIZE; - int chunkY = y / CHUNK_SIZE; - int offsetX = x - chunkX * CHUNK_SIZE; - int offsetY = y - chunkY * CHUNK_SIZE; - RegionChunk r = getRegionChunk(chunkX, chunkY); - if (r instanceof BuildRegionChunk) { - ((BuildRegionChunk) r).store(object); - return; - } - r.getObjects()[offsetX][offsetY] = object; - } - - /** - * Gets the scenerys. - * @return The scenerys. - */ - public Scenery[][] getObjects() { - return objects; - } - - public List getObjectList() { - ArrayList list = new ArrayList(); - for (int x = 0; x < REGION_SIZE; x++) { - for (int y = 0; y < REGION_SIZE; y++) { - if (objects[x][y] != null) - list.add(objects[x][y]); - } - } - return list; - } - - /** - * Clears this region plane. - */ - public void clear() { - for (RegionChunk[] c : chunks) { - for (RegionChunk chunk : c) { - if (chunk != null) { - chunk.clear(); - } - } - } - if (region instanceof DynamicRegion && objects != null) { - for (int x = 0; x < REGION_SIZE; x++) { - for (int y = 0; y < REGION_SIZE; y++) { - objects[x][y] = null; - } - } - objects = null; - } - } - - /** - * Adds an NPC to this region. - * @param npc The NPC to add. - */ - public void add(NPC npc) { - npcs.add(npc); - } - - /** - * Adds a player to this region. - * @param player The player. - */ - public void add(Player player) { - players.add(player); - } - - /** - * Adds an item to this region. - * @param item The item. - */ - public void add(GroundItem item) { - Location l = item.getLocation(); - RegionChunk c = getRegionChunk(l.getLocalX() / RegionChunk.SIZE, l.getLocalY() / RegionChunk.SIZE); - // This adds it to the chunk to be interactable with. - if (!c.getItems().add(item)) { - return; - } - GroundItem g = (GroundItem) item; - if (g.isPrivate()) { - if (g.getDropper() != null) { - // Limit it to the region(8x8 square) you are in +/-2 regions, as the chunk loader will load it all over again. - // This is based on MapChunkRenderer which seems to "update" 2 chunks away. - // Look at RegionChunk.java ConstructGroundItem.write(buffer, item); - if (Math.abs(g.getDropper().getLocation().getRegionX() - l.getRegionX()) <= 2 && - Math.abs(g.getDropper().getLocation().getRegionY() - l.getRegionY()) <= 2 && - g.getDropper().getLocation().getZ() == l.getZ()) { - PacketRepository.send(ConstructGroundItem.class, new BuildItemContext(g.getDropper(), item)); - } - } - return; - } - c.flag(new ItemUpdateFlag(g, ItemUpdateFlag.CONSTRUCT_TYPE)); - } - - /** - * Removes an NPC from this region. - * @param npc The NPC. - */ - public void remove(NPC npc) { - npcs.remove(npc); - } - - /** - * Removes a player from this region. - * @param player The player. - */ - public void remove(Player player) { - players.remove(player); - } - - /** - * Removes an item from this region. - * @param item The ground item. - */ - public void remove(GroundItem item) { - Location l = item.getLocation(); - RegionChunk c = getRegionChunk(l.getLocalX() / RegionChunk.SIZE, l.getLocalY() / RegionChunk.SIZE); - if (!c.getItems().remove(item)) { - return; - } - if (item.isPrivate()) { - if (item.getDropper() != null && item.getDropper().isPlaying() && item.getDropper().getLocation().withinDistance(l)) { - PacketRepository.send(ClearGroundItem.class, new BuildItemContext(item.getDropper(), item)); - } - return; - } - c.flag(new ItemUpdateFlag(item, ItemUpdateFlag.REMOVE_TYPE)); - } - - /** - * Gets the region flags. - * @return The flags. - */ - public RegionFlags getFlags() { - return flags; - } - - /** - * Gets the projectileFlags. - * @return The projectileFlags. - */ - public RegionFlags getProjectileFlags() { - return projectileFlags; - } - - /** - * Gets the npcs. - * @return The npcs. - */ - public List getNpcs() { - return npcs; - } - - public List getEntities() - { - List entities = new ArrayList<>(npcs); - Arrays.stream(getObjects()).forEach(o -> entities.addAll(Arrays.asList(o))); - return entities; - } - - /** - * Gets the players. - * @return The players. - */ - public List getPlayers() { - return players; - } - - /** - * Gets the plane. - * @return The plane. - */ - public int getPlane() { - return plane; - } - - /** - * Gets the region. - * @return The region. - */ - public Region getRegion() { - return region; - } - - /** - * Gets an object from a region chunk. - * @param x The region x-coordinate. - * @param y The region y-coordinate. - * @return The scenery. - */ - public Scenery getChunkObject(int x, int y) { - return getChunkObject(x, y, -1); - } - - /** - * Gets an object from a region chunk. - * @param x The region x-coordinate. - * @param y The region y-coordinate. - * @param objectId The object id. - * @return The scenery. - */ - public Scenery getChunkObject(int x, int y, int objectId) { - int chunkX = x / CHUNK_SIZE; - int chunkY = y / CHUNK_SIZE; - int offsetX = x - chunkX * CHUNK_SIZE; - int offsetY = y - chunkY * CHUNK_SIZE; - RegionChunk chunk = getRegionChunk(chunkX, chunkY); - if (chunk instanceof BuildRegionChunk) { - BuildRegionChunk brc = (BuildRegionChunk) chunk; - return brc.get(offsetX, offsetY, brc.getIndex(offsetX, offsetY, objectId)); - } - return getRegionChunk(chunkX, chunkY).getObjects()[offsetX][offsetY]; - } - - /** - * Gets an object from a region chunk. - * @param x The region x-coordinate. - * @param y The region y-coordinate. - * @return The scenery. - */ - public List getChunkItems(int x, int y) { - int chunkX = x / CHUNK_SIZE; - int chunkY = y / CHUNK_SIZE; - return getRegionChunk(chunkX, chunkY).getItems(); - } - - /** - * Gets a ground item from this plane. - * @param itemId The item id. - * @param l The location. - * @param player The player. - * @return The item. - */ - public GroundItem getItem(int itemId, Location l, Player player) { - GroundItem groundItem = null; - for (Item item : getChunkItems(l.getLocalX(), l.getLocalY())) { - GroundItem g = (GroundItem) item; - if (g.getId() == itemId && l.equals(g.getLocation()) && !g.isRemoved()) { - if (groundItem != null && (!g.isPrivate() || player == null)) { - continue; - } - if ((!g.isPrivate() || player == null || g.droppedBy(player))) { - groundItem = g; - } - } - } - return groundItem; - } - - /** - * Gets the region chunks. - * @return The chunks. - */ - public RegionChunk[][] getChunks() { - return chunks; - } - -} diff --git a/Server/src/main/core/game/world/map/Viewport.java b/Server/src/main/core/game/world/map/Viewport.java deleted file mode 100644 index d563b0357..000000000 --- a/Server/src/main/core/game/world/map/Viewport.java +++ /dev/null @@ -1,155 +0,0 @@ -package core.game.world.map; - -import core.game.node.entity.Entity; -import core.game.node.entity.npc.NPC; -import core.game.node.entity.player.Player; - -import java.util.LinkedList; -import java.util.List; - -/** - * Represents an entity's viewport. - * @author Emperor - */ -public final class Viewport { - - /** - * The amount of chunks in a viewport. - */ - public static final int CHUNK_SIZE = 5; - - /** - * The region region. - */ - private Region region; - - /** - * The region chunks. - */ - private RegionChunk[][] chunks = new RegionChunk[CHUNK_SIZE][CHUNK_SIZE]; - - /** - * The region region plane. - */ - private RegionPlane currentPlane; - - /** - * The region planes the entity can see. - */ - private List viewingPlanes = new LinkedList<>(); - - /** - * Constructs a new {@code Viewport} {@code Object}. - */ - public Viewport() { - /* - * empty. - */ - } - - /** - * Updates the entity's viewport. - * @param entity The entity. - */ - public void updateViewport(Entity entity) { - RegionChunk chunk = RegionManager.getRegionChunk(entity.getLocation()); - int center = chunks.length >> 1; - if (chunks[center][center] == chunk) { - return; - } - int offset = center * -8; - Location l = chunk.getCurrentBase(); - for (int x = 0; x < chunks.length; x++) { - for (int y = 0; y < chunks[x].length; y++) { - chunks[x][y] = RegionManager.getRegionChunk(l.transform(offset + (8 * x), offset + (8 * y), 0)); - } - } - } - - /** - * Removes the entity from the viewingPlanes. - * @param entity The entity. - */ - public void remove(Entity entity) { - if (region == null) { - return; - } - if (entity instanceof Player) { - region.remove((Player) entity); - Region region = null; - for (RegionPlane r : viewingPlanes) { - if (region != r.getRegion()) { - region = r.getRegion(); - region.decrementViewAmount(); - region.checkInactive(); - } - } - } else { - region.remove((NPC) entity); - } - } - - /** - * Gets the region. - * @return The region. - */ - public Region getRegion() { - return region; - } - - /** - * Sets the region. - * @param region The region to set. - */ - public void setRegion(Region region) { - this.region = region; - } - - /** - * Gets the chunks. - * @return The chunks. - */ - public RegionChunk[][] getChunks() { - return chunks; - } - - /** - * Sets the chunks. - * @param chunks The chunks to set. - */ - public void setChunks(RegionChunk[][] chunks) { - this.chunks = chunks; - } - - /** - * Gets the viewingPlanes. - * @return The viewingPlanes. - */ - public List getViewingPlanes() { - return viewingPlanes; - } - - /** - * Sets the viewingPlanes. - */ - public void setViewingPlanes(List regions) { - this.viewingPlanes = regions; - } - - /** - * Gets the currentPlane. - * @return The currentPlane. - */ - public RegionPlane getCurrentPlane() { - return currentPlane; - } - - /** - * Sets the currentPlane. - * @param currentPlane The currentPlane to set. - */ - public void setCurrentPlane(RegionPlane currentPlane) { - this.currentPlane = currentPlane; - } - -} diff --git a/Server/src/main/core/game/world/map/build/RegionFlags.java b/Server/src/main/core/game/world/map/build/ChunkFlags.java similarity index 92% rename from Server/src/main/core/game/world/map/build/RegionFlags.java rename to Server/src/main/core/game/world/map/build/ChunkFlags.java index 177da33c9..a41cb9368 100644 --- a/Server/src/main/core/game/world/map/build/RegionFlags.java +++ b/Server/src/main/core/game/world/map/build/ChunkFlags.java @@ -10,7 +10,7 @@ import static java.lang.Math.max; * @author Emperor * */ -public final class RegionFlags { +public final class ChunkFlags { public static final int TILE_OBJECT = 0x40000; public static final int EMPTY_TILE = 0; @@ -20,7 +20,7 @@ public final class RegionFlags { /** * The plane. */ - private final int plane; + private final int baseZ; /** * If the region is members only. @@ -49,23 +49,25 @@ public final class RegionFlags { /** * Constructs a new {@code RegionFlags} {@code Object}. - * @param x The base x-coordinate (absolute). + * @param x The base x-coordinate (absolute). * @param y The base y-coordinate (absolute). - */ - public RegionFlags(int plane, int x, int y) { - this(plane, x, y, false); + * @param z The base z-coordinate (absolute). + */ + public ChunkFlags(int x, int y, int z) { + this(x, y, z, false); } /** * Constructs a new {@code RegionFlags} {@code Object}. - * @param x The base x-coordinate (absolute). + * @param x The base x-coordinate (absolute). * @param y The base y-coordinate (absolute). - */ - public RegionFlags(int plane, int x, int y, boolean projectile) { - this.plane = plane; + */ + public ChunkFlags(int x, int y, int z, boolean projectile) { this.baseX = x; this.baseY = y; + this.baseZ = z; this.projectile = projectile; + this.landscape = new boolean[8][8]; //all false by default, thanks Java } /** @@ -126,10 +128,10 @@ public final class RegionFlags { * @param clipdata The clip data. */ public void flag(int x, int y, int clipdata) { - if (x > -1 && x < 64 && y > -1 && y < 64) { + if (x > -1 && x < 8 && y > -1 && y < 8) { addFlag(x, y, clipdata); } else { - RegionManager.addClippingFlag(plane, baseX + x, baseY + y, projectile, clipdata); + RegionManager.addClippingFlag(baseZ, baseX + x, baseY + y, projectile, clipdata); } } @@ -160,15 +162,15 @@ public final class RegionFlags { * @param clipdata The clip data. */ public void unflag(int x, int y, int clipdata) { - if (x > -1 && x < 64 && y > -1 && y < 64) { + if (x > -1 && x < 8 && y > -1 && y < 8) { removeFlag(x, y, clipdata); } else { - RegionManager.removeClippingFlag(plane, baseX + x, baseY + y, projectile, clipdata); + RegionManager.removeClippingFlag(baseZ, baseX + x, baseY + y, projectile, clipdata); } } private Pair getFlagIndex(int x, int y) { - return new Pair<>(((baseX >> 6) << 8) | (baseY >> 6), (plane * 64 * 64) + (x * 64) + y); + return new Pair<>((baseZ << 22) | ((baseX >> 3) << 11) | (baseY >> 3), (x * 8) + y); } public int getFlag(int x, int y) { @@ -349,7 +351,7 @@ public final class RegionFlags { } /** - * Unlags a door object (type 0-3). + * Unflags a door object (type 0-3). * @param x The x-coordinate * @param y The y-coordinate. * @param rotation The rotation. @@ -515,8 +517,8 @@ public final class RegionFlags { * Gets the plane. * @return The plane. */ - public int getPlane() { - return plane; + public int getBaseZ() { + return baseZ; } /** @@ -534,4 +536,4 @@ public final class RegionFlags { public void setLandscape(boolean[][] landscape) { this.landscape = landscape; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/world/map/build/DynamicRegion.java b/Server/src/main/core/game/world/map/build/DynamicRegion.java index 2ccbabc69..6e0d06031 100644 --- a/Server/src/main/core/game/world/map/build/DynamicRegion.java +++ b/Server/src/main/core/game/world/map/build/DynamicRegion.java @@ -5,7 +5,6 @@ import core.game.node.entity.player.Player; import core.game.node.entity.player.link.music.MusicZone; import core.game.node.item.GroundItem; import core.game.node.item.GroundItemManager; -import core.game.node.scenery.Scenery; import core.game.world.map.*; import core.game.world.map.zone.RegionZone; import core.game.world.map.zone.ZoneBorders; @@ -13,7 +12,6 @@ import core.game.world.map.zone.impl.MultiwayCombatZone; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -24,7 +22,6 @@ import java.util.List; * @author Emperor */ public final class DynamicRegion extends Region { - /** * The reserved areas. */ @@ -35,11 +32,6 @@ public final class DynamicRegion extends Region { */ private final int regionId; - /** - * The region chunks. - */ - private final RegionChunk[][][] chunks; - /** * The zone borders. */ @@ -76,14 +68,25 @@ public final class DynamicRegion extends Region { public DynamicRegion(int regionId, int x, int y) { super(x, y); this.regionId = regionId; - this.chunks = new RegionChunk[4][SIZE >> 3][SIZE >> 3]; - RegionManager.resetFlags(getId()); + // Reset any stale flags at this region's chunk coordinates + for (int chunkX = 0; chunkX < 8; chunkX++) { + for (int chunkY = 0; chunkY < 8; chunkY++) { + for (int cz = 0; cz < 4; cz++) { + RegionChunk chunk = chunks[chunkX][chunkY][cz]; + for (int chunkOffsetX = 0; chunkOffsetX < 8; chunkOffsetX++) { + for (int chunkOffsetY = 0; chunkOffsetY < 8; chunkOffsetY++) { + chunk.getFlags().invalidateFlag(chunkOffsetX, chunkOffsetY); //the 'invalid' value of -1 triggers reloading + chunk.getProjectileFlags().clearFlag(chunkOffsetX, chunkOffsetY); //the 'clear' value of 0 is the default state + } + } + } + } + } } public DynamicRegion(@NotNull ZoneBorders borders) { this(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6); setBorders(borders); - setUpdateAllPlanes(true); RegionManager.addRegion(getId(), this); } @@ -95,7 +98,7 @@ public final class DynamicRegion extends Region { public static DynamicRegion create(int regionId) { int x = (regionId >> 8) << 6; int y = (regionId & 0xFF) << 6; - return create(new ZoneBorders(x, y, x + SIZE, y + SIZE))[0]; + return create(new ZoneBorders(x, y, x + 64, y + 64))[0]; } /** @@ -109,7 +112,7 @@ public final class DynamicRegion extends Region { int y = (regionOne & 0xFF) << 6; int x1 = (regionTwo >> 8) << 6; int y1 = (regionTwo & 0xFF) << 6; - return create(new ZoneBorders(x, y, x1 + SIZE, y1 + SIZE))[0]; + return create(new ZoneBorders(x, y, x1 + 64, y1 + 64))[0]; } /** @@ -129,23 +132,18 @@ public final class DynamicRegion extends Region { for (int y = copy.getSouthWestY() >> 6; y < copy.getNorthEastY() >> 6; y++) { int regionId = x << 8 | y; Location loc = l.transform((x - baseX) << 6, (y - baseY) << 6, 0); - DynamicRegion region = copy(regionId, loc); - region.setBorders(border); - Region r = RegionManager.forId(region.getId()); - if (r != null) { - for (int z = 0; z < 4; z++) { - region.getPlanes()[z].getPlayers().addAll(r.getPlanes()[z].getPlayers()); - region.getPlanes()[z].getNpcs().addAll(r.getPlanes()[z].getNpcs()); - } - } - RegionManager.addRegion(region.getId(), region); - regions.add(region); + DynamicRegion dest = copy(regionId, loc); + dest.setBorders(border); + RegionManager.addRegion(dest.getId(), dest); + regions.add(dest); } } for (Region r : regions) { for (int z = 0; z < 4; z++) { - for (Player p : r.getPlanes()[z].getPlayers()) { - p.updateSceneGraph(false); + for (Player player : r.assemblePlayerList(z)) { + if (player != null) { + player.updateSceneGraph(false); + } } } } @@ -222,11 +220,13 @@ public final class DynamicRegion extends Region { int x = regionX + (offsetX << 3); int y = regionY + (offsetY << 3); for (int plane = 0; plane < 4; plane++) { - RegionChunk c = base.getPlanes()[plane].getRegionChunk(offsetX, offsetY); + RegionChunk c = base.getChunks()[offsetX][offsetY][plane]; if (c == null) { - region.chunks[plane][offsetX][offsetY] = c = new RegionChunk(Location.create(0, 0, 0), 0, region.getPlanes()[plane]); + c = new RegionChunk(Location.create(0, 0, 0), 0); + region.chunks[offsetX][offsetY][plane] = c; } else { - region.replaceChunk(plane, offsetX, offsetY, (c = c.copy(region.getPlanes()[plane])), base); + c = c.copy(); + region.replaceChunk(plane, offsetX, offsetY, c, base); } c.setRotation(0); c.setBase(Location.create(x, y, plane)); @@ -274,72 +274,25 @@ public final class DynamicRegion extends Region { getMusicZones().add(new MusicZone(musicId, borders)); } - /** - * Rotates the region 90% clockwise. - * TODO: Finish this - */ - public void rotate() { - for (int z = 0; z < 4; z++) { - RegionChunk[][] c = Arrays.copyOf(chunks[z], 8); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - RegionChunk r = chunks[z][x][y] = c[8 - y - 1][x]; - if (r != null) { - r.setRotation(r.getRotation() + 1); - } - } - } - } - } - - /** - * Sets a region chunk (without setting objects/clipping flags). - * @param z The plane. - * @param x The chunk x (0-8). - * @param y The chunk y (0-8). - * @param chunk The chunk to set. - */ - public void setChunk(int z, int x, int y, RegionChunk chunk) { - chunks[z][x][y] = chunk; - getPlanes()[z].getChunks()[x][y] = chunk; - if (chunk != null) { - chunk.setCurrentBase(getBaseLocation().transform(x << 3, y << 3, 0)); - } - } - /** * Replaces a region chunk. * @param z The plane. * @param x The x-coordinate of the chunk. (0-7) * @param y The y-coordinate of the chunk. (0-7) - * @param chunk The chunk to replace with. + * @param replacement The chunk to replace with. * @param fromRegion The region the chunk is copied from. */ - public void replaceChunk(int z, int x, int y, RegionChunk chunk, Region fromRegion) { + public void replaceChunk(int z, int x, int y, RegionChunk replacement, Region fromRegion) { Region.load(DynamicRegion.this); - RegionPlane p = getPlanes()[z]; - chunks[z][x][y] = chunk; - p.getChunks()[x][y] = chunk; - if (chunk == null) { - for (int i = x << 3; i < (x + 1) << 3; i++) { - for (int j = y << 3; j < (y + 1) << 3; j++) { - p.getFlags().invalidateFlag(i, j); - p.getProjectileFlags().invalidateFlag(i, j); - Scenery object = p.getObjects()[i][j]; - if (object != null) { - LandscapeParser.removeScenery(object); - } else { - p.add(null, i, j, true); - } - } - } - } else { - Region.load(fromRegion); - Location l = chunk.getBase(); - RegionPlane rp = fromRegion.getPlanes()[l.getZ()]; - chunk.setCurrentBase(getBaseLocation().transform(x << 3, y << 3, z)); - chunk.rebuildFlags(rp); - } + chunks[x][y][z] = replacement; + Region.load(fromRegion); + RegionChunk orig = fromRegion.getChunks()[x][y][z]; + Location currentBase = getBaseLocation().transform(x << 3, y << 3, z); + replacement.setCurrentBase(currentBase); + replacement.rebaseObjects(); + replacement.rebuildFlags(orig); + replacement.syncFlagsToRegionManager(); + replacement.getNpcs().addAll(orig.getNpcs()); //DO NOT create a copy npc, because it won't be initialized! } @Override @@ -356,20 +309,18 @@ public final class DynamicRegion extends Region { } } } - if(!super.flagInactive(force)) { - return false; - } - for (RegionPlane plane : getPlanes()) { - for (int i = 0; i < plane.getNpcs().size(); i++) { - NPC npc = plane.getNpcs().get(0); - npc.clear(); - } - for (RegionChunk[] chunks : getChunks()[plane.getPlane()]) { - for (RegionChunk chunk : chunks) { - if (chunk != null) { - for (Iterator it = chunk.getItems().iterator(); it.hasNext();) { - GroundItemManager.getItems().remove(it.next()); - } + if (!super.flagInactive(force)) { + return false; + } + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 4; z++) { + RegionChunk chunk = chunks[x][y][z]; + for (NPC npc : chunk.getNpcs()) { + npc.clear(); + } + for (GroundItem item : chunk.getItems()) { + GroundItemManager.destroy(item); } } } @@ -378,16 +329,16 @@ public final class DynamicRegion extends Region { if (multicombat) { toggleMulticombat(); } - boolean allLinkedInactive = true; + boolean allLinkedInactive = true; if (linked != null) { for (DynamicRegion r : linked) { allLinkedInactive &= r.flagInactive(force); } } - return allLinkedInactive; + return allLinkedInactive; } else { - return true; - } + return true; + } } @Override @@ -395,14 +346,6 @@ public final class DynamicRegion extends Region { return regionId; } - /** - * Gets the chunks. - * @return The chunks. - */ - public RegionChunk[][][] getChunks() { - return chunks; - } - /** * Gets the borders. * @return The borders. diff --git a/Server/src/main/core/game/world/map/build/LandscapeParser.java b/Server/src/main/core/game/world/map/build/LandscapeParser.java index 81025e7d6..3c6f44cec 100644 --- a/Server/src/main/core/game/world/map/build/LandscapeParser.java +++ b/Server/src/main/core/game/world/map/build/LandscapeParser.java @@ -3,11 +3,7 @@ package core.game.world.map.build; import core.cache.def.impl.SceneryDefinition; import core.cache.misc.buffer.ByteBufferUtils; import core.game.node.scenery.Scenery; -import core.game.world.map.Location; -import core.game.world.map.Region; -import core.game.world.map.RegionManager; -import core.game.world.map.RegionPlane; -import core.game.system.config.ObjectConfigParser; +import core.game.world.map.*; import java.nio.ByteBuffer; @@ -17,14 +13,13 @@ import java.nio.ByteBuffer; * */ public final class LandscapeParser { - /** * Parses the landscape. * @param r The region. * @param mapscape The mapscape data. * @param storeObjects If all objects should be stored (rather than just the objects with options). */ - public static void parse(Region r, byte[][][] mapscape, ByteBuffer buffer, boolean storeObjects) { + public static void parse(Region r, RegionChunk[][][] chunks, byte[][][] mapscape, ByteBuffer buffer, boolean storeObjects) { int objectId = -1; for (;;) { int offset = ByteBufferUtils.getBigSmart(buffer); @@ -39,23 +34,25 @@ public final class LandscapeParser { break; } location += offset - 1; - int y = location & 0x3f; - int x = location >> 6 & 0x3f; + int localY = location & 0x3f; + int localX = location >> 6 & 0x3f; int configuration = buffer.get() & 0xFF; int rotation = configuration & 0x3; int type = configuration >> 2; int z = location >> 12; r.setObjectCount(r.getObjectCount() + 1); - if (x < 0 || y < 0 || x >= 64 || y >= 64) { - - } else { - if ((mapscape[1][x][y] & 0x2) == 2) { - z--; - } - if (z >= 0 && z <= 3) { - Scenery object = new Scenery(objectId, Location.create((r.getX() << 6) + x, (r.getY() << 6) + y, z), type, rotation); - flagScenery(r.getPlanes()[z], x, y, object, true, storeObjects); - } + if ((mapscape[1][localX][localY] & 0x2) == 2) { + z--; + } + if (z >= 0 && z <= 3) { + Location loc = Location.create((r.getX() << 6) + localX, (r.getY() << 6) + localY, z); + Scenery object = new Scenery(objectId, loc, type, rotation); + int chunkX = loc.getChunkX(); + int chunkY = loc.getChunkY(); + int chunkOffsetX = loc.getChunkOffsetX(); + int chunkOffsetY = loc.getChunkOffsetY(); + RegionChunk chunk = chunks[chunkX][chunkY][z]; + flagScenery(chunk, chunkOffsetX, chunkOffsetY, object, true, storeObjects); } } } @@ -76,34 +73,34 @@ public final class LandscapeParser { */ public static void addScenery(Scenery object, boolean landscape) { Location l = object.getLocation(); - flagScenery(RegionManager.getRegionPlane(l), l.getLocalX(), l.getLocalY(), object, landscape, false); + flagScenery(RegionManager.getRegionChunk(l), l.getChunkOffsetX(), l.getChunkOffsetY(), object, landscape, false); } /** * Flags a scenery on the plane's clipping flags. - * @param plane The plane. + * @param chunk The chunk. * @param object The object. * @param landscape If we are adding this scenery permanent. * @param storeObjects If all objects should be stored (rather than just the objects with options). */ - public static void flagScenery(RegionPlane plane, int localX, int localY, Scenery object, boolean landscape, boolean storeObjects) { - Region.load(plane.getRegion()); + public static void flagScenery(RegionChunk chunk, int chunkOffsetX, int chunkOffsetY, Scenery object, boolean landscape, boolean storeObjects) { + Region r = chunk.getRegion(); + Region.load(r); SceneryDefinition def = object.getDefinition(); object.setActive(true); + object.setRenderable(true); boolean add = storeObjects || !landscape || def.getChildObject(null).hasActions(); if (add) { - addPlaneObject(plane, object, localX, localY, landscape, storeObjects); - } - - if (!applyClippingFlagsFor(plane, localX, localY, object)) - return; - - if (!storeObjects && !add && (!def.getChildObject(null).getName().equals("null"))) { - addPlaneObject(plane, object, localX, localY, landscape, false); + if (landscape) { + chunk.addStatDyn(object, chunkOffsetX, chunkOffsetY); + } else { + chunk.add(object); + } } + applyClippingFlagsFor(chunk, chunkOffsetX, chunkOffsetY, object); } - public static boolean applyClippingFlagsFor(RegionPlane plane, int localX, int localY, Scenery object) { + public static boolean applyClippingFlagsFor(RegionChunk chunk, int chunkOffsetX, int chunkOffsetY, Scenery object) { SceneryDefinition def = object.getDefinition(); int sizeX; int sizeY; @@ -116,27 +113,27 @@ public final class LandscapeParser { } int type = object.getType(); if (type == 22) { //Tile - plane.getFlags().getLandscape()[localX][localY] = true; + chunk.getFlags().getLandscape()[chunkOffsetX][chunkOffsetY] = true; if (def.interactable != 0 || def.clipType == 1 || def.secondBool) { if (def.clipType == 1) { - plane.getFlags().flagTileObject(localX, localY); + chunk.getFlags().flagTileObject(chunkOffsetX, chunkOffsetY); if (def.isProjectileClipped()) { - plane.getProjectileFlags().flagTileObject(localX, localY); + chunk.getProjectileFlags().flagTileObject(chunkOffsetX, chunkOffsetY); } } } } else if (type >= 9) { //Default objects if (def.clipType != 0) { - plane.getFlags().flagSolidObject(localX, localY, sizeX, sizeY, def.projectileClipped); + chunk.getFlags().flagSolidObject(chunkOffsetX, chunkOffsetY, sizeX, sizeY, def.projectileClipped); if (def.isProjectileClipped()) { - plane.getProjectileFlags().flagSolidObject(localX, localY, sizeX, sizeY, def.projectileClipped); + chunk.getProjectileFlags().flagSolidObject(chunkOffsetX, chunkOffsetY, sizeX, sizeY, def.projectileClipped); } } } else if (type >= 0 && type <= 3) { //Doors/walls if (def.clipType != 0) { - plane.getFlags().flagDoorObject(localX, localY, object.getRotation(), type, def.projectileClipped); + chunk.getFlags().flagDoorObject(chunkOffsetX, chunkOffsetY, object.getRotation(), type, def.projectileClipped); if (def.isProjectileClipped()) { - plane.getProjectileFlags().flagDoorObject(localX, localY, object.getRotation(), type, def.projectileClipped); + chunk.getProjectileFlags().flagDoorObject(chunkOffsetX, chunkOffsetY, object.getRotation(), type, def.projectileClipped); } } } else { @@ -145,24 +142,6 @@ public final class LandscapeParser { return true; } - /** - * Adds an object to the region plane. - * @param plane The region plane. - * @param object The object to add. - * @param localX The local x-coordinate. - * @param localY The local y-coordinate. - * @param landscape The landscape. - */ - private static void addPlaneObject(RegionPlane plane, Scenery object, int localX, int localY, boolean landscape, boolean storeAll) { - if (landscape && !storeAll) { - Scenery current = plane.getObjects()[localX][localY]; - if (current != null && current.getDefinition().getChildObject(null).hasOptions(!object.getDefinition().getChildObject(null).hasOptions(false))) { - return; - } - } - plane.add(object, localX, localY, landscape && !storeAll); - } - /** * Removes a scenery. * @param object The object. @@ -172,18 +151,23 @@ public final class LandscapeParser { if (!object.isRenderable()) { return null; } - RegionPlane plane = RegionManager.getRegionPlane(object.getLocation()); - Region.load(plane.getRegion()); - int localX = object.getLocation().getLocalX(); - int localY = object.getLocation().getLocalY(); - Scenery current = plane.getChunkObject(localX, localY, object.getId()); + + // Get and remove the object + Location loc = object.getLocation(); + Region region = RegionManager.forId(loc.getRegionId()); + Region.load(region); + RegionChunk chunk = region.getChunks()[loc.getChunkX()][loc.getChunkY()][loc.getZ()]; + int index = chunk.getIndex(loc.getChunkOffsetX(), loc.getChunkOffsetY(), object.getId(), object.getType()); + Scenery current = chunk.getObjects()[index][loc.getChunkOffsetX()][loc.getChunkOffsetY()]; if (current == null || current.getId() != object.getId()) { return null; } current.setActive(false); object.setActive(false); - plane.remove(localX, localY, object.getId()); + chunk.getObjects()[index][loc.getChunkOffsetX()][loc.getChunkOffsetY()] = null; SceneryDefinition def = object.getDefinition(); + + // Remove its clipping flags int sizeX; int sizeY; if (object.getRotation() % 2 == 0) { @@ -193,28 +177,30 @@ public final class LandscapeParser { sizeX = def.sizeY; sizeY = def.sizeX; } + int chunkOffsetX = loc.getChunkOffsetX(); + int chunkOffsetY = loc.getChunkOffsetY(); int type = object.getType(); if (type == 22) { //Tile if (def.interactable != 0 || def.clipType == 1 || def.secondBool) { if (def.clipType == 1) { - plane.getFlags().unflagTileObject(localX, localY); + chunk.getFlags().unflagTileObject(chunkOffsetX, chunkOffsetY); if (def.isProjectileClipped()) { - plane.getProjectileFlags().unflagTileObject(localX, localY); + chunk.getProjectileFlags().unflagTileObject(chunkOffsetX, chunkOffsetY); } } } } else if (type >= 9) { //Default objects if (def.clipType != 0) { - plane.getFlags().unflagSolidObject(localX, localY, sizeX, sizeY, def.projectileClipped); + chunk.getFlags().unflagSolidObject(chunkOffsetX, chunkOffsetY, sizeX, sizeY, def.projectileClipped); if (def.isProjectileClipped()) { - plane.getProjectileFlags().unflagSolidObject(localX, localY, sizeX, sizeY, def.projectileClipped); + chunk.getProjectileFlags().unflagSolidObject(chunkOffsetX, chunkOffsetY, sizeX, sizeY, def.projectileClipped); } } } else if (type >= 0 && type <= 3) { //Doors/walls if (def.clipType != 0) { - plane.getFlags().unflagDoorObject(localX, localY, object.getRotation(), type, def.projectileClipped); + chunk.getFlags().unflagDoorObject(chunkOffsetX, chunkOffsetY, object.getRotation(), type, def.projectileClipped); if (def.isProjectileClipped()) { - plane.getProjectileFlags().unflagDoorObject(localX, localY, object.getRotation(), type, def.projectileClipped); + chunk.getProjectileFlags().unflagDoorObject(chunkOffsetX, chunkOffsetY, object.getRotation(), type, def.projectileClipped); } } } diff --git a/Server/src/main/core/game/world/map/build/MapscapeParser.java b/Server/src/main/core/game/world/map/build/MapscapeParser.java index 7ecc4c81c..567b308cb 100644 --- a/Server/src/main/core/game/world/map/build/MapscapeParser.java +++ b/Server/src/main/core/game/world/map/build/MapscapeParser.java @@ -1,6 +1,7 @@ package core.game.world.map.build; import core.game.world.map.Region; +import core.game.world.map.RegionChunk; import java.nio.ByteBuffer; @@ -17,10 +18,25 @@ public final class MapscapeParser { * @param buffer The buffer. */ public static void parse(Region r, byte[][][] mapscape, ByteBuffer buffer) { + if (r.getChunks() == null) { + return; //this is a DynamicRegion that has been cleared + } + // The cache is packed by region, so we need to parse it along the local-x/y coordinates for (int z = 0; z < 4; z++) { - boolean[][] landscape = r.getPlanes()[z].getFlags().getLandscape(); - for (int x = 0; x < 64; x++) { - for (int y = 0; y < 64; y++) { + for (int localX = 0; localX < 64; localX++) { + for (int localY = 0; localY < 64; localY++) { + int chunkX = localX >> 3; + int chunkY = localY >> 3; + int chunkOffsetX = localX & 7; + int chunkOffsetY = localY & 7; + RegionChunk chunk = r.getChunks()[chunkX][chunkY][z]; + boolean[][] landscape; + if (chunk == null) { + // Still need to consume the buffer data even for null chunks + landscape = new boolean[8][8]; + } else { + landscape = chunk.getFlags().getLandscape(); + } while (true) { int value = buffer.get() & 0xFF; if (value == 0) { @@ -33,16 +49,14 @@ public final class MapscapeParser { if (value <= 49) { //Overlay data int val = buffer.get() & 0xFF; if (val != 42 && val > 0) { - landscape[x][y] = true; + landscape[chunkOffsetX][chunkOffsetY] = true; } - } - else if (value <= 81) { - mapscape[z][x][y] = (byte) (value - 49); - } - else { + } else if (value <= 81) { + mapscape[z][localX][localY] = (byte) (value - 49); + } else { int val = (byte) (value - 81) & 0xFF; //Underlay data if (val != 42 && val > 0) { - landscape[x][y] = true; + landscape[chunkOffsetX][chunkOffsetY] = true; } } } @@ -56,22 +70,30 @@ public final class MapscapeParser { * @param r The region. * @param mapscape The mapscape. */ - public static void clipMapscape(Region r, byte[][][] mapscape) { + public static void clipMapscape(Region r, RegionChunk[][][] chunks, byte[][][] mapscape) { for (int z = 0; z < 4; z++) { - for (int x = 0; x < 64; x++) { - for (int y = 0; y < 64; y++) { - r.getPlanes()[z].getFlags().flagEmptyTile(x,y); - if ((mapscape[z][x][y] & 0x1) == 1) { - int plane = z; - if ((mapscape[1][x][y] & 0x2) == 2) { - plane--; - } - if (plane > -1) { - r.getPlanes()[plane].getFlags().flagSolidTile(x, y); + for (int chunkX = 0; chunkX < 8; chunkX++) { + for (int chunkY = 0; chunkY < 8; chunkY++) { + RegionChunk chunk = chunks[chunkX][chunkY][z]; + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + chunk.getFlags().flagEmptyTile(x, y); + int chunkOffsetX = chunkX*8 + x; + int chunkOffsetY = chunkY*8 + y; + if ((mapscape[z][chunkOffsetX][chunkOffsetY] & 0x1) == 1) { + int plane = z; + if ((mapscape[1][chunkOffsetX][chunkOffsetY] & 0x2) == 2) { + plane--; + } + if (plane > -1) { + RegionChunk chunkToFlag = r.getChunks()[chunkX][chunkY][plane]; + chunkToFlag.getFlags().flagSolidTile(x, y); + } + } } } } } } } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/world/map/zone/ZoneMonitor.java b/Server/src/main/core/game/world/map/zone/ZoneMonitor.java index 65b4a0322..1fe68e486 100644 --- a/Server/src/main/core/game/world/map/zone/ZoneMonitor.java +++ b/Server/src/main/core/game/world/map/zone/ZoneMonitor.java @@ -160,9 +160,9 @@ public final class ZoneMonitor { } if (entity instanceof Player && target instanceof Player) { if (!((Player) entity).getSkullManager().isWilderness() || !((Player) target).getSkullManager().isWilderness()) { - if(message) { - ((Player) entity).getPacketDispatch().sendMessage("You can only attack other players in the wilderness."); - } + if(message) { + ((Player) entity).getPacketDispatch().sendMessage("You can only attack other players in the wilderness."); + } return false; } } @@ -362,7 +362,7 @@ public final class ZoneMonitor { it.remove(); } } - for (RegionZone zone : entity.getViewport().getRegion().getRegionZones()) { + for (RegionZone zone : entity.getLocation().getRegion().getRegionZones()) { if (!zone.getBorders().insideBorder(entity)) { continue; } @@ -403,7 +403,7 @@ public final class ZoneMonitor { } } } - Region r = player.getViewport().getRegion(); + Region r = player.getLocation().getRegion(); for (MusicZone zone : r.getMusicZones()) { if (zone.getBorders().insideBorder(l.getX(), l.getY())) { zone.enter(player); diff --git a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java index 1c8b113dd..d44cc9f7c 100644 --- a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java +++ b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java @@ -11,6 +11,7 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.MapZone; import core.game.world.map.zone.ZoneBorders; +import core.game.world.repository.Repository; /** * Represents the moderator zone. @@ -66,8 +67,6 @@ public class ModeratorZone extends MapZone { @Override public boolean interact(Entity entity, Node target, Option option) { - if (entity instanceof Player) { - } return super.interact(entity, target, option); } @@ -82,11 +81,11 @@ public class ModeratorZone extends MapZone { * @param on the toggle switch. */ public static final void toggle(final Player player, final boolean on) { - open = on ? true : false; + open = on; player.getPacketDispatch().sendMessage(getToggleMessage()); if (!open) { for (Player p : RegionManager.getLocalPlayers(center)) { - if (p == null || p.getDetails().getRights() == Rights.ADMINISTRATOR) { + if (p.getDetails().getRights() == Rights.ADMINISTRATOR) { continue; } home(p); @@ -123,10 +122,7 @@ public class ModeratorZone extends MapZone { * @return return True if so. */ public static boolean isOpen() { - if (!open) { - return false; - } - return true; + return open; } } diff --git a/Server/src/main/core/game/world/map/zone/impl/MultiwayCombatZone.java b/Server/src/main/core/game/world/map/zone/impl/MultiwayCombatZone.java index 77477b3b1..3723dcf70 100644 --- a/Server/src/main/core/game/world/map/zone/impl/MultiwayCombatZone.java +++ b/Server/src/main/core/game/world/map/zone/impl/MultiwayCombatZone.java @@ -3,7 +3,6 @@ package core.game.world.map.zone.impl; 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.Direction; import core.game.world.map.Location; import core.game.world.map.MapDistance; import core.game.world.map.RegionManager; @@ -127,21 +126,21 @@ public final class MultiwayCombatZone extends MapZone { if (e.getProperties().isNPCWalkable()) { return true; } - for (NPC n : RegionManager.getLocalNpcs(e, MapDistance.RENDERING.getDistance() / 2)) { - if (n.isInvisible() || !n.getDefinition().hasAttackOption() || n == e) { - continue; - } - if(n.shouldPreventStacking(e)) { - int s1 = e.size(); - int s2 = n.size(); - int x = destination.getX(); - int y = destination.getY(); - Location l = n.getLocation(); - if(Pathfinder.isStandingIn(x, y, s1, s1, l.getX(), l.getY(), s2, s2)) { - return false; - } - } - } + for (NPC n : RegionManager.getLocalNPCs(e.getLocation(), MapDistance.RENDERING.getDistance() / 2)) { + if (n.isInvisible() || !n.getDefinition().hasAttackOption() || n == e) { + continue; + } + if(n.shouldPreventStacking(e)) { + int s1 = e.size(); + int s2 = n.size(); + int x = destination.getX(); + int y = destination.getY(); + Location l = n.getLocation(); + if(Pathfinder.isStandingIn(x, y, s1, s1, l.getX(), l.getY(), s2, s2)) { + return false; + } + } + } return true; } diff --git a/Server/src/main/core/game/world/objectparser/ObjectParser.java b/Server/src/main/core/game/world/objectparser/ObjectParser.java deleted file mode 100644 index 39b445e31..000000000 --- a/Server/src/main/core/game/world/objectparser/ObjectParser.java +++ /dev/null @@ -1,101 +0,0 @@ -package core.game.world.objectparser; - -import core.api.StartupListener; -import core.ServerConstants; -import core.game.node.scenery.Scenery; -import core.game.world.map.build.LandscapeParser; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.File; - -public class ObjectParser implements StartupListener { - - public void parseObjects(){ - if(ServerConstants.OBJECT_PARSER_PATH == null) return; - File f = new File(ServerConstants.OBJECT_PARSER_PATH); - if(!f.exists()){ - - return; - } - - try{ - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(f); - - NodeList parseList = doc.getElementsByTagName("ObjectAction"); - - - - for(int i = 0; i < parseList.getLength(); i++){ - Node parseNode = parseList.item(i); - if(parseNode.getNodeType() == Node.ELEMENT_NODE){ - Element parseElement = (Element) parseNode; - String type = parseElement.getAttribute("mode"); - switch(type){ - case "add": { - int id = Integer.parseInt(parseElement.getAttribute("id")); - int x = Integer.parseInt(parseElement.getAttribute("x")); - int y = Integer.parseInt(parseElement.getAttribute("y")); - int z = Integer.parseInt(parseElement.getAttribute("z")); - int objType = 10; - if (parseElement.hasAttribute("type")) { - objType = Integer.parseInt(parseElement.getAttribute("type")); - } - String rawDir = parseElement.getAttribute("direction"); - int dir = 1; - switch (rawDir) { - case "n": - dir = 1; - break; - case "ne": - dir = 2; - break; - case "nw": - dir = 0; - break; - case "w": - dir = 3; - break; - case "e": - dir = 4; - break; - case "sw": - dir = 5; - break; - case "se": - dir = 7; - break; - case "s": - dir = 6; - break; - } - LandscapeParser.addScenery(new Scenery(id, x, y, z, objType, dir)); - break; - } - case "remove": { - int id = Integer.parseInt(parseElement.getAttribute("id")); - int x = Integer.parseInt(parseElement.getAttribute("x")); - int y = Integer.parseInt(parseElement.getAttribute("y")); - int z = Integer.parseInt(parseElement.getAttribute("z")); - int objType = 10; - LandscapeParser.removeScenery(new Scenery(id,x,y,z)); - } - } - } - } - } catch (Exception e){ - e.printStackTrace(); - } - } - - @Override - public void startup() { - parseObjects(); - } -} diff --git a/Server/src/main/core/game/world/repository/Repository.kt b/Server/src/main/core/game/world/repository/Repository.kt index 0b97f197c..d2b09a4bd 100644 --- a/Server/src/main/core/game/world/repository/Repository.kt +++ b/Server/src/main/core/game/world/repository/Repository.kt @@ -127,7 +127,7 @@ object Repository { */ @JvmStatic fun findNPC(l: Location): NPC? { - for (n in RegionManager.getRegionPlane(l).npcs) { + for (n in RegionManager.getRegionChunk(l).npcs) { if (n.location == l) { return n } diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index b9e20112a..47e93ff53 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -6,6 +6,7 @@ import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk import java.util.* +import kotlin.math.abs /** * Handles the rendering of the player's surrounding map chunks. @@ -18,10 +19,20 @@ object MapChunkRenderer { */ @JvmStatic fun render(player: Player) { - val v = player.viewport val last = player.playerFlags.lastViewport val updated: MutableList = ArrayList() - val current = v.chunks + val current: MutableList> = ArrayList() + + val buildAreaDepth = 6 + for (dcx in -buildAreaDepth..+buildAreaDepth) { + val addX = ArrayList() + for (dcy in -buildAreaDepth..+buildAreaDepth) { + val newloc = player.location.chunkBase.transform(dcx*8, dcy*8, 0) + addX.add(newloc.chunk) + } + current.add(addX) + } + var sizeX = last.size for (x in 0 until sizeX) { val sizeY: Int = last[x].size @@ -55,7 +66,7 @@ object MapChunkRenderer { * @param c The region chunk. * @return `True` if so. */ - private fun containsChunk(list: Array>, c: RegionChunk): Boolean { + private fun containsChunk(list: MutableList>, c: RegionChunk): Boolean { val sizeList = list.size for (x in 0 until sizeList) { val chunkSize: Int = list[x].size diff --git a/Server/src/main/core/game/world/update/NPCRenderer.kt b/Server/src/main/core/game/world/update/NPCRenderer.kt index dbb2fd01c..815066844 100644 --- a/Server/src/main/core/game/world/update/NPCRenderer.kt +++ b/Server/src/main/core/game/world/update/NPCRenderer.kt @@ -30,7 +30,7 @@ object NPCRenderer { val it: Iterator = localNPCs.iterator() while (it.hasNext()) { val npc = it.next() - val withinDistance = player.location.withinDistance(npc.location) + val withinDistance = player.location.withinDistance(npc.location, 15) if (npc.isHidden(player) || !withinDistance || npc.properties.isTeleporting) { buffer.putBits(1, 1).putBits(2, 3) toRemove.add(npc) @@ -51,7 +51,7 @@ object NPCRenderer { } } localNPCs.removeAll(toRemove) - for (npc in RegionManager.getLocalNpcs(player)) { + for (npc in RegionManager.getLocalNPCs(player.location, 15)) { if (localNPCs.size >= 255) { break } diff --git a/Server/src/main/core/game/world/update/PlayerRenderer.kt b/Server/src/main/core/game/world/update/PlayerRenderer.kt index e192463d7..b20ab8dd5 100644 --- a/Server/src/main/core/game/world/update/PlayerRenderer.kt +++ b/Server/src/main/core/game/world/update/PlayerRenderer.kt @@ -3,6 +3,7 @@ package core.game.world.update import core.game.node.entity.player.Player import core.game.node.entity.player.info.RenderInfo import core.game.world.map.RegionManager +import core.game.world.repository.Repository import core.net.packet.IoBuffer import core.net.packet.PacketHeader @@ -39,7 +40,7 @@ object PlayerRenderer { renderLocalPlayer(player, other, buffer, flags) } var count = 0 - for (other in RegionManager.getLocalPlayers(player, 15)) { + for (other in RegionManager.getLocalPlayers(player.location, 15)) { if (other === player || !other.isActive || info.localPlayers.contains(other) || other.isInvisible) { continue } @@ -177,4 +178,4 @@ object PlayerRenderer { player.updateMasks.write(local, player, flags) } } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags.java b/Server/src/main/core/game/world/update/flag/PlayerFlags.java index c67408a65..41d0cb441 100644 --- a/Server/src/main/core/game/world/update/flag/PlayerFlags.java +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags.java @@ -2,7 +2,6 @@ package core.game.world.update.flag; import core.game.world.map.Location; import core.game.world.map.RegionChunk; -import core.game.world.map.Viewport; /** * A class holding a player's updating flags. @@ -18,11 +17,11 @@ public final class PlayerFlags { /** * The last viewport. */ - private RegionChunk[][] lastViewport = new RegionChunk[Viewport.CHUNK_SIZE][Viewport.CHUNK_SIZE]; + private RegionChunk[][] lastViewport = new RegionChunk[13][13]; /** * The location the player was standing on when last scene graph update - * occured. + * occurred. */ private Location lastSceneGraph; diff --git a/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt index c10d937f2..9482068c7 100644 --- a/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt +++ b/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt @@ -69,4 +69,4 @@ class SnowStormHolidayRandomNPC : HolidayRandomEventNPC(NPCs.SNOW_6740) { override fun talkTo(npc: NPC) { } -} \ No newline at end of file +} diff --git a/Server/src/main/core/net/packet/PacketProcessor.kt b/Server/src/main/core/net/packet/PacketProcessor.kt index c05798490..7a05cc549 100644 --- a/Server/src/main/core/net/packet/PacketProcessor.kt +++ b/Server/src/main/core/net/packet/PacketProcessor.kt @@ -1,6 +1,5 @@ package core.net.packet -import content.global.ame.events.maze.MazeInterface import content.global.handlers.iface.ge.StockMarket import content.global.skill.magic.SpellListener import content.global.skill.magic.SpellListeners @@ -580,7 +579,7 @@ object PacketProcessor { } else if (pkt is Packet.UseWithScenery) { item = pkt.player.inventory[pkt.slot] ?: return sendClearMinimap(pkt.player) - node = RegionManager.getObject(pkt.player.location.z, pkt.x, pkt.y) ?: return sendClearMinimap(pkt.player) + node = RegionManager.getObject(pkt.player.location.z, pkt.x, pkt.y, pkt.sceneryId) ?: return sendClearMinimap(pkt.player) childNode = node.asScenery().getChild(pkt.player) itemId = pkt.itemId nodeId = node.id @@ -690,11 +689,6 @@ object PacketProcessor { if (pkt.id == 6899) scenery = Scenery(6899, Location(3221, 9618)) - // Random Event Maze chests are overridden by the walls, which needs to be hacked in. - if ((scenery?.id == 3626 || scenery?.id == 3635) && (objId in 3635..3636)) { - scenery = MazeInterface.overrideScenery(scenery, objId) - } - // Family crest levers don't have varps associated with them, so their state is validated with attributes // instead, and they always appear as their down/odd variant in the server's map if (objId in 2421..2426 && objId % 2 == 0) { diff --git a/Server/src/main/core/net/packet/out/BuildDynamicScene.java b/Server/src/main/core/net/packet/out/BuildDynamicScene.java index 3cea2b5db..f9719651f 100644 --- a/Server/src/main/core/net/packet/out/BuildDynamicScene.java +++ b/Server/src/main/core/net/packet/out/BuildDynamicScene.java @@ -29,17 +29,15 @@ public final class BuildDynamicScene implements OutgoingPacket> 3) << 8 | (y >> 3)); + for (int x = baseX; x <= player.getLocation().getRegionX() + 6; x++) { + for (int y = baseY; y <= player.getLocation().getRegionY() + 6; y++) { + for (int z = 0; z < 4; z++) { + Region r = RegionManager.forId((x >> 3) << 8 | (y >> 3)); if (r instanceof DynamicRegion) { - DynamicRegion dr = (DynamicRegion) r; - chunks[z][x - baseX][y - baseY] = dr.getChunks()[z][x - (dr.getX() << 3)][y - (dr.getY() << 3)]; + chunks[x - baseX][y - baseY][z] = r.getChunks()[x - (r.getX() << 3)][y - (r.getY() << 3)][z]; } } } @@ -47,7 +45,7 @@ public final class BuildDynamicScene implements OutgoingPacket - base.planes[destPlane].getRegionChunk(destChunkX, destChunkY) + base.chunks[destchunkX][destChunkY][destPlane] }.from(base).onPlanes(0, 1, 2, 3) ) val region = specification.build() @@ -94,7 +93,7 @@ class RegionSpecificationTests { @Test fun shouldAllowUseExistingDynamicRegion() { val base = RegionManager.forId(12850) Region.load(base) - val chunk = base.planes[0].getRegionChunk(2, 2) + val chunk = base.getChunks()[2][2][0] val dyn = DynamicRegion.create(12850) val specification = RegionSpecification ( using(dyn), @@ -109,13 +108,13 @@ class RegionSpecificationTests { @Test fun fillChunkContractShouldAllowChunkSetCallback() { class TemporaryFillContract(chunk: RegionChunk) : FillChunkContract(chunk) { var callBackRan = false - override fun afterSetting(chunk: BuildRegionChunk?, x: Int, y: Int, plane: Int, dyn: DynamicRegion) { + override fun afterSetting(chunk: RegionChunk?, x: Int, y: Int, plane: Int, dyn: DynamicRegion) { callBackRan = true } } val base = RegionManager.forId(12850) Region.load(base) - val chunk = base.planes[0].getRegionChunk(2, 2) + val chunk = base.getChunks()[2][2][0] val dyn = DynamicRegion.create(12850) val fillTemporary = TemporaryFillContract(chunk) val specification = RegionSpecification ( diff --git a/Server/src/test/kotlin/RegionTests.kt b/Server/src/test/kotlin/RegionTests.kt index 7e48c338a..68f0b428a 100644 --- a/Server/src/test/kotlin/RegionTests.kt +++ b/Server/src/test/kotlin/RegionTests.kt @@ -1,14 +1,8 @@ -import core.cache.Cache import core.game.world.map.Region -import core.game.world.map.RegionChunk import core.game.world.map.RegionManager import core.game.world.map.build.DynamicRegion -import core.game.world.map.build.LandscapeParser -import org.junit.Assert import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test -import core.game.system.config.ServerConfigParser -import core.game.system.config.XteaParser class RegionTests { companion object { @@ -67,8 +61,8 @@ class RegionTests { Region.load(dynamic) val targetLoc = dynamic.baseLocation.transform(23, 17, 0) Assertions.assertEquals(null, RegionManager.getObject(targetLoc), "Object exists pre-copy?") - val replacement = base.planes[0].getRegionChunk(2, 2) - dynamic.replaceChunk(0, 2, 2, replacement.copy(dynamic.planes[0]), base) + val replacement = base.getChunks()[2][2][0] + dynamic.replaceChunk(0, 2, 2, replacement.copy(), base) Assertions.assertEquals(36782, RegionManager.getObject(targetLoc)?.id ?: -1, "Object does not exist at expected location!") } @@ -79,8 +73,8 @@ class RegionTests { Region.load(dynamic, true) val targetLoc = dynamic.baseLocation.transform(23, 17, 0) Assertions.assertEquals(null, RegionManager.getObject(targetLoc), "Object exists pre-copy?") - val replacement = base.planes[0].getRegionChunk(2, 2) - dynamic.replaceChunk(0, 2, 2, replacement.copy(dynamic.planes[0]), base) + val replacement = base.getChunks()[2][2][0] + dynamic.replaceChunk(0, 2, 2, replacement.copy(), base) Assertions.assertEquals(36782, RegionManager.getObject(targetLoc)?.id ?: -1, "Object does not exist at expected location!") } @@ -89,11 +83,10 @@ class RegionTests { val borders = DynamicRegion.reserveArea(8,8) val dynamic = DynamicRegion(-1, borders.southWestX shr 6, borders.southWestY shr 6) dynamic.borders = borders - dynamic.isUpdateAllPlanes = true RegionManager.addRegion(dynamic.id, dynamic) val targetLoc = dynamic.baseLocation.transform(23, 17, 0) - val replacement = base.planes[0].getRegionChunk(2,2) - dynamic.replaceChunk(0, 2, 2, replacement.copy(dynamic.planes[0]), base) + val replacement = base.getChunks()[2][2][0] + dynamic.replaceChunk(0, 2, 2, replacement.copy(), base) Assertions.assertEquals(36782, RegionManager.getObject(targetLoc)?.id ?: -1, "Object does not exist at expected location!") } @@ -102,11 +95,10 @@ class RegionTests { val borders = DynamicRegion.reserveArea(8,8) val dynamic = DynamicRegion(-1, borders.southWestX shr 6, borders.southWestY shr 6) dynamic.borders = borders - dynamic.isUpdateAllPlanes = true RegionManager.addRegion(dynamic.id, dynamic) val targetLoc = dynamic.baseLocation.transform(23, 17, 0) - val replacement = base.planes[0].getRegionChunk(2,2) - dynamic.replaceChunk(0, 2, 2, replacement.copy(dynamic.planes[0]), base) + val replacement = base.getChunks()[2][2][0] + dynamic.replaceChunk(0, 2, 2, replacement.copy(), base) base.link(dynamic) Assertions.assertEquals(36782, RegionManager.getObject(targetLoc)?.id ?: -1, "Object does not exist at expected location!") } diff --git a/Server/src/test/kotlin/TestUtils.kt b/Server/src/test/kotlin/TestUtils.kt index b8d8d45cd..5f672e627 100644 --- a/Server/src/test/kotlin/TestUtils.kt +++ b/Server/src/test/kotlin/TestUtils.kt @@ -146,10 +146,13 @@ class MockPlayer(name: String, val isBot: Boolean) : Player(PlayerDetails(name)) finishClear() } - override fun setLocation(location: Location?) { + override fun setLocation(location: Location) { super.setLocation(location) - RegionManager.move(this) + location.chunk.addPlayer(this) + location.region.incrementViewAmount() + location.region.flagActive() this.playerFlags.lastSceneGraph = location + zoneMonitor.updateLocation(walkingQueue.footPrint) } fun relog(ticksToWait: Int = -1) { diff --git a/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt b/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt index 8926443f1..870d1b265 100644 --- a/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt +++ b/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt @@ -242,4 +242,4 @@ class BlastFurnaceAreaTests { BlastFurnaceListeners().defineListeners() } } -} \ No newline at end of file +} diff --git a/Server/src/test/kotlin/core/PathfinderTests.kt b/Server/src/test/kotlin/core/PathfinderTests.kt index 84f6c640c..eebeb5219 100644 --- a/Server/src/test/kotlin/core/PathfinderTests.kt +++ b/Server/src/test/kotlin/core/PathfinderTests.kt @@ -116,6 +116,22 @@ class PathfinderTests { } } + @Test fun entityTargetMovementPulseShouldTolerateMissingTargetLocation() { + TestUtils.getMockPlayer("missingtargetloc").use { p -> + p.location = ServerConstants.HOME_LOCATION + val npc = NPC.create(0, NPC_TEST_LOC) + npc.setLocation(null) + + val pulse = object : MovementPulse(p, npc) { + override fun pulse(): Boolean { + return true + } + } + + Assertions.assertDoesNotThrow { pulse.update() } + } + } + @Test fun entityTargetMovementPulseShouldNotStopOnSameTileAsEntity() { TestUtils.getMockPlayer("entitystoptest").use {p -> p.location = ServerConstants.HOME_LOCATION @@ -257,4 +273,4 @@ class PathfinderTests { Assertions.assertEquals(true, npc.location.getDistance(ServerConstants.HOME_LOCATION!!) <= 5) } } -} \ No newline at end of file +} diff --git a/Server/worldprops/default.conf b/Server/worldprops/default.conf index 308db7417..645811200 100644 --- a/Server/worldprops/default.conf +++ b/Server/worldprops/default.conf @@ -22,7 +22,7 @@ noauth_default_admin = true #NOTE: If we are not using auth, this determines whe #------------------------------------------------------------------------------------------------------ #The limit on how many different accounts a player can log into per day. daily_accounts_per_ip = 3 -watchdog_enabled = true +watchdog_enabled = false connectivity_check_url = "https://google.com,https://2009scape.org" connectivity_timeout = 500 # Enables a websocket listener for browser clients. The websocket stream carries the From 87e1b5e74c5fe405d57c2e7c127fa3cc1c0c91aa Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 30 May 2026 18:37:19 +0200 Subject: [PATCH 02/94] Can remove the typos now --- Server/src/main/core/game/world/map/RegionManager.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index b58cb17f6..5586549f2 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -452,8 +452,6 @@ object RegionManager { @JvmStatic fun getSurroundingPlayers(player: Entity, maximum: Int): List = getLocalEntities(player.location, 1, maximum, null) @JvmStatic fun getSurroundingNPCs(npc: Entity, maximum: Int): List = getLocalEntities(npc.location, 1, maximum, null) @JvmStatic fun getLocalPlayersBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum, null) - @JvmStatic fun getLocalNPCBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum, null) - @JvmStatic fun getLocalEntitys(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) //typoed version to avoid merge conflict with !2269 /** * Gets a random teleport location in the radius around the given location. From 94fd11a07b64487ac0fc5f52333e5f83f78968d8 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 31 May 2026 12:08:52 +0200 Subject: [PATCH 03/94] Incorporate changes from !2373 --- .../minigame/vinesweeper/Vinesweeper.kt | 164 +++++++++++------- 1 file changed, 99 insertions(+), 65 deletions(-) diff --git a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt index bf7c42467..d4461b424 100644 --- a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt +++ b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt @@ -32,6 +32,8 @@ import core.game.system.task.Pulse import core.game.world.GameWorld import core.game.world.GameWorld.ticks import core.game.world.map.Location +import core.game.world.map.Region +import core.game.world.map.RegionChunk import core.game.world.map.RegionManager import core.game.world.map.zone.ZoneBorders import core.game.world.update.flag.context.Animation @@ -50,27 +52,26 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { } override fun areaEnter(entity: Entity) { - if(entity is Player) - { + if (entity is Player) { openOverlay(entity, Components.RABBIT_OVERLAY_689) sendUpdatedPoints(entity) } } override fun areaLeave(entity: Entity, logout: Boolean) { - if(entity is Player) { + if (entity is Player) { entity.interfaceManager.closeOverlay() - if(!logout) { + if (!logout) { sendMessage(entity, "Winkin's Farm thanks you for your visit.") sendMessage(entity, "Leftover ogleroots and flags have been returned to the establishment.") sendMessage(entity, "You have been reimbursed at a rate of 10gp per ogleroot and the flags have been collected.") val flags = entity.inventory.getAmount(Item(Items.FLAG_12625)) - if(flags > 0) { + if (flags > 0) { entity.setAttribute("/save:vinesweeper:stored-flags", flags) entity.inventory.remove(Item(Items.FLAG_12625, flags)) } val roots = entity.inventory.getAmount(Item(Items.OGLEROOT_12624)) - if(roots > 0) { + if (roots > 0) { entity.inventory.remove(Item(Items.OGLEROOT_12624, roots)) entity.inventory.add(Item(Items.COINS_995, roots * 10)) } @@ -96,7 +97,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { return@on true } on(HOLES, IntType.SCENERY, "dig") { player, node -> - if(!player.inventory.contains(Items.SPADE_952, 1)) { + if (!player.inventory.contains(Items.SPADE_952, 1)) { // TODO (crash): authenticity player.sendMessage("You need a spade to dig here.") } else { @@ -113,7 +114,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { on(HOLES, IntType.SCENERY, "flag") { player, node -> val hole = node as Scenery var count = 0 - if(player.location != node.location) { + if (player.location != node.location) { plantFlag(player,hole) return@on true } @@ -149,7 +150,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { 1 -> "You get some mud in your eye and it stings! You have no idea what is in the hole." 2 -> "The mud seems to be too thick to see what is there." 3 -> "A slimy worm wriggles out of the mud, making you jump and lose concentration. You're not sure if there is a seed here or not." - else -> if(isSeed(node.location)) { + else -> if (isSeed(node.location)) { "You notice a seed hidden in the dirt." } else { "You are certain there is no seed planted here." @@ -260,7 +261,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { data class SeedDestination(val player: Player, val loc: Location, val alive: Boolean) { override fun equals(other: Any?): Boolean { - return if(other is SeedDestination) { + return if (other is SeedDestination) { loc == other.loc } else { false @@ -272,8 +273,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { } } - companion object - { + companion object { val AVACH_NIMPORTO_LOC = Location.create(1637, 4709) val SIGNS = intArrayOf(Sceneries.INSTRUCTION_SIGN_29461, Sceneries.INSTRUCTION_SIGN_29462, Sceneries.INSTRUCTION_SIGN_29463, Sceneries.INSTRUCTION_SIGN_29464) val HOLES = intArrayOf(Sceneries.HOLE_29476, Sceneries.HOLE_29477, Sceneries.HOLE_29478) @@ -332,9 +332,9 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { val reward = REWARDS[buttonID] ?: return val cost = amount * reward.points val points = player.getAttribute("vinesweeper:points", 0) - if(cost in 1 until points) { + if (cost in 1 until points) { val item = Item(reward.itemID, amount) - if(!player.inventory.add(item)) { + if (!player.inventory.add(item)) { GroundItemManager.create(item, player) } player.incrementAttribute("/save:vinesweeper:points", -cost) @@ -345,7 +345,6 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { } } - val TUTORIAL = 685 val INSTRUCTION_SIGNS = hashMapOf( @@ -360,52 +359,87 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { val MAX_SEEDS = 300 val FARMER_CLEAR_RADIUS = 3 - val VINESWEEPER_BORDERS = ZoneBorders(1600,4672,1663,4735) + val VINESWEEPER_REGION = RegionManager.forId(6473) + var SEED_LOCS: HashSet = HashSet() fun sendUpdatedPoints(player: Player) { val points = player.getAttribute("vinesweeper:points", 0) setVarbit(player, 4449, points) } - var SEED_LOCS: HashSet = HashSet() - fun isSeed(loc: Location): Boolean { val scenery = getScenery(loc) return scenery != null && SEED_LOCS.contains(scenery.location) } - fun populateSeeds() { - val holes = countHoles() - val seeds = min(1.0 * MAX_SEEDS, holes * 0.13).toInt() - var tries = 0 // Prevent the while loop from crashing the server - while(SEED_LOCS.size < seeds && tries++ < 1000) { - val loc = VINESWEEPER_BORDERS.getRandomLoc() - val scenery = getScenery(loc) - if(scenery != null && HOLES.contains(scenery.id)) { - SEED_LOCS.add(loc) - } - } - } - - private fun countHoles(): Int { - val northEastX = VINESWEEPER_BORDERS.northEastX - val northEastY = VINESWEEPER_BORDERS.northEastY - val southWestX = VINESWEEPER_BORDERS.southWestX - val southWestY = VINESWEEPER_BORDERS.southWestY - var holeCount = 0 - for (x in southWestX .. northEastX){ - for (y in southWestY .. northEastY){ - val scenery = getScenery(x, y, 0) - if(scenery != null && HOLES.contains(scenery.id)) { - holeCount++ + fun resetChunkIfBarren(chunk: RegionChunk) { + val wipedHoles = ArrayList() + for (i in 0 until chunk.objects.size) { + for (x in 0 until 8) { + for (y in 0 until 8) { + val obj = chunk.objects[i][x][y] ?: continue + if (obj.id in HOLES) { + return //this chunk is not barren and hence should not be reset + } + if (obj.id == NUMBERS[0]) { + wipedHoles.add(obj) + } } } } - return holeCount + for (scenery in wipedHoles) { + SceneryBuilder.replace(scenery, scenery.transform(HOLES[0])) + } + } + + fun countFieldState(chunk: RegionChunk, emptyHoleList: ArrayList, seedHoleList: ArrayList) { + for (i in 0 until chunk.objects.size) { + for (x in 0 until 8) { + for (y in 0 until 8) { + val obj = chunk.objects[i][x][y] ?: continue + if (obj.id in HOLES) { + if (obj.location in SEED_LOCS) { + seedHoleList.add(obj) + } else { + emptyHoleList.add(obj) + } + } + } + } + } + } + + fun populateSeeds() { + // First, see if there are any chunks that have been completely wiped out. These need to be restored first (GL #2400). + Region.load(VINESWEEPER_REGION) + for (cx in 0 until 8) { + for (cy in 0 until 8) { + val chunk = VINESWEEPER_REGION.chunks[cx][cy][0] + resetChunkIfBarren(chunk) + } + } + // Next, get the state of the field + val emptyHoleList = ArrayList() + val seedHoleList = ArrayList() + for (cx in 0 until 8) { + for (cy in 0 until 8) { + val chunk = VINESWEEPER_REGION.chunks[cx][cy][0] + countFieldState(chunk, emptyHoleList, seedHoleList) + } + } + val target = min(1.0 * MAX_SEEDS, (seedHoleList.size + emptyHoleList.size) * 0.13).toInt() + val seedsToAdd = target - seedHoleList.size + if (seedsToAdd < 1) { + return + } + emptyHoleList.shuffle() + for (i in 0 until seedsToAdd) { + SEED_LOCS.add(emptyHoleList[i].location) + } } fun plantFlag(player: Player, hole: Scenery) { - if(player.inventory.remove(Item(Items.FLAG_12625, 1))) { + if (player.inventory.remove(Item(Items.FLAG_12625, 1))) { player.lock() player.visualize(Animation(Animations.HUMAN_PLANT_FLAG_8711),Graphics(Gfx.VINESWEEPER_PLANT_FLAG_1541)) player.sendMessage("You add a flag to the patch.") @@ -425,9 +459,9 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { fun feedRabbit(player: Player, rabbit: NPC) { val respawnDelay = 50 - if(rabbit.isInvisible || DeathTask.isDead(rabbit)) { return } - if(rabbit.getAttribute("dead", 0) > ticks) { return } - if(player.inventory.remove(Item(Items.OGLEROOT_12624, 1))) { + if (rabbit.isInvisible || DeathTask.isDead(rabbit)) { return } + if (rabbit.getAttribute("dead", 0) > ticks) { return } + if (player.inventory.remove(Item(Items.OGLEROOT_12624, 1))) { rabbit.setAttribute("dead",ticks + respawnDelay) player.skills.addExperience(Skills.HUNTER, 30.0) rabbit.sendChat("Squeak!") @@ -447,36 +481,36 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { } fun dig(player: Player, loc: Location) { - if(isSeed(loc)) { + if (isSeed(loc)) { val oldPoints = player.getAttribute("vinesweeper:points", 0) player.setAttribute("/save:vinesweeper:points", Math.max(oldPoints-10, 0)) sendUpdatedPoints(player) player.sendMessage("Oh dear! It looks like you dug up a potato seed by mistake.") scheduleNPCs(player, loc, false, false) val scenery = getScenery(loc) - if(scenery != null) { + if (scenery != null) { SceneryBuilder.replace(scenery, scenery.transform(Sceneries.DEAD_PLANT_29456)) } } else { player.incrementAttribute("/save:vinesweeper:points", 1) sendUpdatedPoints(player) var count = 0 - for(dx in -1..1) { - for(dy in -1..1) { - if(isSeed(loc.transform(dx, dy, 0))) { + for (dx in -1..1) { + for (dy in -1..1) { + if (isSeed(loc.transform(dx, dy, 0))) { count += 1 } } } val scenery = getScenery(loc) - if(scenery != null) { + if (scenery != null) { SceneryBuilder.replace(scenery, scenery.transform(NUMBERS[count])) } - if(count == 0) { - for(dx in -1..1) { - for(dy in -1..1) { + if (count == 0) { + for (dx in -1..1) { + for (dy in -1..1) { val newLoc = loc.transform(dx, dy, 0) - if(isHole(newLoc)) + if (isHole(newLoc)) dig(player, newLoc) } } @@ -505,9 +539,9 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { fun scheduleNPCs(player: Player, loc: Location, alive: Boolean, rabbit: Boolean) { val dest = SeedDestination(player, loc, alive) - val ids = if(rabbit) { RABBITS + FARMERS } else { FARMERS } - for(npc in findLocalNPCs(player, ids, 30)) { - if(npc is VinesweeperNPC) { + val ids = if (rabbit) { RABBITS + FARMERS } else { FARMERS } + for (npc in findLocalNPCs(player, ids, 30)) { + if (npc is VinesweeperNPC) { npc.seedDestinations.add(dest) npc.resetWalk() } @@ -599,7 +633,7 @@ class VinesweeperNPC : AbstractNPC { } override fun getMovementDestination(): Location? { - if(seedDestinations.size > 0) { + if (seedDestinations.size > 0) { seedDestinations.sortBy { a -> a.loc.getDistance(location).toInt() } return seedDestinations.first().loc } else { @@ -608,7 +642,7 @@ class VinesweeperNPC : AbstractNPC { } fun handleRabbitSeed(scenery: Scenery, dest: Vinesweeper.SeedDestination) { - if(SEED_LOCS.contains(dest.loc)) { + if (SEED_LOCS.contains(dest.loc)) { val replacement = Sceneries.DEAD_PLANT_29456 lock(4) animate(Animation(Animations.RABBIT_EAT_SEED_8718)) @@ -688,10 +722,10 @@ class VinesweeperNPC : AbstractNPC { } fun farmerClear(dest: Vinesweeper.SeedDestination) { - for(dx in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) { - for(dy in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) { + for (dx in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) { + for (dy in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) { val toClear = getScenery(dest.loc.transform(dx, dy, 0)) - if(toClear != null && intArrayOf(Sceneries.DEAD_PLANT_29456, *NUMBERS).contains(toClear.id)) { + if (toClear != null && intArrayOf(Sceneries.DEAD_PLANT_29456, *NUMBERS).contains(toClear.id)) { SceneryBuilder.replace(toClear, toClear.transform(HOLES[0])) } } From a197d7cb2cc7064e3ad5c592cf9bc9b19a2b51da Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 2 Jun 2026 18:26:58 +0200 Subject: [PATCH 04/94] Undo space/tabs correction to fix compatibility with Castle Wars --- Server/src/main/core/game/world/map/zone/ZoneMonitor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Server/src/main/core/game/world/map/zone/ZoneMonitor.java b/Server/src/main/core/game/world/map/zone/ZoneMonitor.java index 1fe68e486..a7176dd04 100644 --- a/Server/src/main/core/game/world/map/zone/ZoneMonitor.java +++ b/Server/src/main/core/game/world/map/zone/ZoneMonitor.java @@ -160,9 +160,9 @@ public final class ZoneMonitor { } if (entity instanceof Player && target instanceof Player) { if (!((Player) entity).getSkullManager().isWilderness() || !((Player) target).getSkullManager().isWilderness()) { - if(message) { - ((Player) entity).getPacketDispatch().sendMessage("You can only attack other players in the wilderness."); - } + if(message) { + ((Player) entity).getPacketDispatch().sendMessage("You can only attack other players in the wilderness."); + } return false; } } From 0499c226779faba66aed907b5cf42b421c8127be Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 9 Jun 2026 09:10:05 +0200 Subject: [PATCH 05/94] Revert bot name changes in anticipation of the same in 2274 --- Server/data/botdata/botnames.txt | 2589 +++++++++++++++++++++++++++++- 1 file changed, 2573 insertions(+), 16 deletions(-) diff --git a/Server/data/botdata/botnames.txt b/Server/data/botdata/botnames.txt index e16423b0c..22c5715a8 100644 --- a/Server/data/botdata/botnames.txt +++ b/Server/data/botdata/botnames.txt @@ -1,22 +1,43 @@ -Kevo +-Kevo +0 S O +0 4 1 1 +0 4 7 +0 HBK 0 +0 Khan 0 +0 LM 0 Quest Ptz 0 Undead 532 0 hits +0 s m a n +0-0000000000 +00 zarour 00 +000eggs +004 n 007 Double O 007Banshee 00eeeee58 00eeeeeHC 00oo00oo00z 010elpibexx0 +014ankh +01690 017Lucas 01Ares 01eon 01ogre +020893 024elyograG 02RS 02homestar +031 +0315 +0416347345 +054 +055027584 05miller5 05venom04 +06 59 +0600 06sz 07 Account 07 Adept @@ -29,9 +50,11 @@ Kevo 07 Officer 07 Rz 07 Sicario +07 T Bone 07 iron 07 kiero X 07 nice jake +070623 07Ashley 07Ben 07Geno @@ -43,10 +66,18 @@ Kevo 07Rockysbudy 07coco 07guthix07 +07wan +080 +0800 +0800952449 +0837 +09 +0920 09Ash 09Ashley 09Ato09 09Chris +09Dans 09Paul 09Reaper 09Rhys @@ -55,29 +86,42 @@ Kevo 09TroyScape 09milo456 09scaping +09wan +0BAMA 0Behind0You0 +0CdanC0 0G 0GCore 0Giesel42O +0IIll0llIIII +0JL 0Joker0 0KAT +0LKI 0MEGA PVM 0MG ST3PSIS +0MW2PVM 0Manbearpig0 +0MrJ 0PC 0Pwnseason 0S Iluvatar 0SFX 0Tempest0 +0WEK 0X010 0_BADASS_0 0anabanthis0 +0bD0G 0bankspace 0bby +0bby Man 0belix 0bscure0ne 0ctopus +0dds r u win 0desza +0dexy 0dyssey 0ff Task 0ffline @@ -93,6 +137,8 @@ Kevo 0im2old4this 0inke 0k +0l +0l m 0ld Mate 0leaguespace 0li @@ -116,9 +162,11 @@ Kevo 0neski 0netruememe 0niichan +0njon 0nlyClouds 0nmy 0ops +0oqs 0pSe 0pen 0pen Al @@ -129,9 +177,13 @@ Kevo 0rl 0rnstein 0rphaned +0samaBdabbin +0sc4r +0smasher0 0so 0ssimpwner 0syb +0t 0taku 0taylor 0verHyped @@ -152,15 +204,35 @@ Kevo 0xocube 0xp Fail 0xygen +1 +1 0 1 0 +1 1 4 +1 2 2 +1 337 +1 3s +1 4 11 +1 54 +1 9 7 +1 A M O R +1 A N D 1 1 Account +1 Corin 6 9 +1 DC +1 Flicki Boi 1 Free Ryde 1 Ham 1 K0 Is Back 1 Line 1 Lion Tell +1 P P 1 1 Percent +1 Waffle 1 and only -1st Blood +1 is ln of e +1 kc 1 pet +1 parhaista +1 s t Blood +1-800DILLDOE 1-GrayStone 10 Four 100 Duke @@ -169,26 +241,57 @@ Kevo 1000 Ways 10000Fists 1000PingOnly +100Cl 100Grabb +100g 100kyews 100m gp 100xcoin +101000101010 +1017Trev +101e 101evil101 101rootbeer +104512 +105 +107M +1085 +1099s +10Hz +10R80 +10b +10cc +10lachs 10mm mafia 10th Reaper 10v10 10v10v 10v10v10v 10x Brew +1101953119 +1111 +11111111111d 111fishkite1 112OceanAve +116 +116 123 +1183kenny +118s 11inchlimp +11l1 +12 +12 49 12 XP 12 hours +120u +1212ajs2 123 Zeus +123456205 123Four 123bear5 +123tseemijni +1272172 +1288 12bar 12bar_ty 12blackeagle @@ -196,6 +299,24 @@ Kevo 12earlycob 12in 12millionGP +12oss +12oz +12th +13 37 +13 Daas +1300 +130SS +130rk +1312AFCA +1313 +131kg +1337 af +1337Trevor +1350 +138hans +13D +13LACK0N3 +13O 13alerion 13ayek 13ehh @@ -207,44 +328,98 @@ Kevo 13purecs 13ruce 13th Witness +14 wides +1400 +14060M +144 +1441 +144forever +1453 FSM +149122089147 +14Fre-e +14GT +14Words 15 min Break 150 kilos 1520sedgwick 15b name -16 FlyTell +15mg +16 Fly Tell 16 Fps +1602 16bumpysnow +16lB +16le +17 76 +170 IQ +17222 +1780 +17Kc +17_FLHXS 17rune2277 18 Or Older 18 Points 18 girlll +18-06-2022 x +1800BetsOff +1802M +180555 +181 +1817 +1827 +1845 +184910381412 +187 +187 781 +1877 187PIGMORGUE 187er +1889 18cast1935 +18hr 18killz +18s 19 KAPLAN 05 +19088ml +1942 +1948 +199 +1992 +1994 +19O7 19edgebee 19puxx +1AB 1After909 1Alfa +1Ali1Plane +1BGP +1Bio 1Buck1Love +1C2R 1C3 W4RR10R 1CuteBot +1Fbs +1G1D 1GramIronMan 1Hit2Lum 1Hunnid +1I1I1IIll1l 1InchWalrus 1Iron Reborn 1Kyle 1Lank 1ManGangBang 1Mayze +1NANO +1NU 1Nikolai 1Nut Dude 1O1Barz 1Ogp 1P Game 1Parthannax2 +1RlE 1ST KC 1Shadow9Fist 1Shark @@ -256,6 +431,7 @@ Kevo 1TickShit 1Unforgiven8 1_BLEED_BLUE +1ars 1badprogram 1bankingnoob 1blackhawk17 @@ -274,6 +450,8 @@ Kevo 1imp1jar 1isa 1itemtbow +1jbone +1john 1k no zik 1kDuramax 1kMaster QXD @@ -291,9 +469,11 @@ Kevo 1nVaSioN 1ndy 1ne life +1nfiniti 1nsane str5 1nv1s 1nvercargill +1o 8 1ocation 1please 1powerhydra @@ -304,31 +484,46 @@ Kevo 1st ed mint 1st son 1stHCwasPKED +1stlrfan 1stnoob7 1t8w 1tapaturma 1tickspecwep 1trueMortyy 1ucif3ro +1v1d a sedan 1w1lll0se 1wayEscape +1wwdwd2e21ed 1yfe +1zet +2 0 1 4 2 1Savage +2 2 7 7 +2 2 8 9 +2 3 7 5 +2 9 2 Big tities +2 Brothers 2 Much Tuna +2 P A C 2 Rich 4 Dis 2 Silent 540 2 Smooth 2 ball cane 2 funny bro 2 grls 1 Jad -2 hp +2 h p +2 in 2 kups +2 lN 2 more min 20 20 vision 20 Agi irl 20 On Pump 3 +200 200 Cook +2000 2001Arwen 2006nope 2007scape @@ -341,35 +536,94 @@ Kevo 200mslay1day 2011Turmoil 2013 Rt +20130406655 +20136 2027Parzival +202o2 +204 Wootang 205alphago +208 +209th +20Four +20I0 +20JuanSavag3 +20ms +21 5 21 Average 21 Musketeer 21 Savage 2137 gp +215O +2173 +21JJ 21SavageX2C 21unit +22 69 +22 Geese +22 Gz +22 darnoc 22 +22 day fury +220mg +226559 +227 7 +2277 2277 Beast 2277 Soon TM 2277MaybeNvr +2277kg +22O5 +22X7 22btc 22harry 22mario 22whitewolf +23 x 3 232o2oo +234071973416 +23463564 +235iii6i666i +2376Total +2376ed +23847239571 +23CD +23I 23coalcare 24 Hour +24000 +241 +241196 +2424 +245 +247 365 +2488 +24YO +24l7 +24w +25 S 25simulator +26 th 260sheepdog +265344626546 +26ll98 26pandas 26th +27 5 +27 M +271MPN +27ml +2841280 28BagsOfSalt 28goldpieces +290x +29384652 +2996 29Pons30 29enchant821 29robdead 2B Nier 2Broke4Coke +2C-T-2 +2D E F2 2D pantsut 2Edgy4Meme 2Far @@ -380,11 +634,21 @@ Kevo 2Goblins1Jug 2Guys1Wyvern 2Guys1dds +2I40 2InchLift 2InchPnisher +2JZ GTE +2JZ Soup +2JZ-GTE Mk4 2Jerry 2Lit +2M0X1 +2MIN +2Men 2MinNoodles +2O xp +2O07 +2OO7 2QC 2Rare2Die 2Secs @@ -411,12 +675,14 @@ Kevo 2girls1Tbow 2girls1bed 2girls1troll +2girlz1jbird 2gurls1tick 2h ur azzzzz 2hopp 2hot2touch 2hot2touch2 2hs +2id 2kav 2late2team 2logx @@ -430,61 +696,120 @@ Kevo 2pacs 2plush 2sm0keyyyyyy +2steps +2th7 2tickin 2tti +2two77 +2uBz +2ual +2ugi 2woke +2x92is99 +2ze 2zick1zussy +3 Hit V +3 5 P +3 50 +3 77 3 Moons -3 SIXES +3 S I X E S 3 SwordStyle -3 arcanes +3 T C +3 arcanes ty 3 me0 3-age 30 yo b00mer 300m MPS +3019 +30FF 30SHOTFOCUS +30XY 30thNovember +30zl +311s +3155 +315lbs 315squatreps +3160 316Austin 32 kay +320m 33 Dust Cat +335K +33jf +33zero2 +3400 +341all +34241245321 +345138 +34HL6432G6L2 +34T +34rj394thgro +351329 35ankoumoon 35cm bicep 360 Labels 360backhand 365 day 369x +36ACT 36answersay +379 +37Kg +37kg +381N 38CoolestMan 38drivelift 39 PETS 3BigDoobie 3D AnimeTits 3D Dorito +3E8 +3G +3III +3L1QZaD 3LetterName 3Miller3 3TicYaMum 3TickEat 3Ticks 3WordName +3a B0ng +3aly +3amf 3arbeed 3ash 3awe +3b 3bay +3bobyshmurda +3d age boots +3d354 +3dderino 3erzerk 3h scimitar +3ibal0e9 3inchsoft +3ioc 3iron5u +3km 3lPatron 3lack 3litz 3lilbirbs +3lit3 3liteSupreme 3lven 3lyrie 3lys +3niZ +3nosedmonkey +3nps +3oh5 3pic 3ragesave 3rd Age Ryan +3rd Age THC 3rd Age Toes 3rd Age Wife 3rd Hunter @@ -494,21 +819,38 @@ Kevo 3rdAgeHunt 3rdAgeSlayer 3rdMistake -3d age boots +3sd +3sl 3stripe +3uck +3uzi +3verD3ad 3vil 3vil Giraffe 3vil Lawyer +3we 3x3i 3xDestroyer 3xtra-1arge 3yes +3zR +3zi 4 Bros Info 4 Man Nex 4 inch demon 4 inches now +40 IQ +400L +400s +403 b +40699 Crabs +40Atk +40ms +40oz +412087542131 413 JokeR 416MiIf Jade +41O 42 Mime 2462 42 Reasons 42 skankhunt @@ -526,11 +868,27 @@ Kevo 420licious 420michael13 420tarmslyng +42342343342 42Def +42O42O +42nd 432andone 43technetium +44 bot +4400 +44444444444 45 fail +4500c +4564 +457 45smith2345 +478k +47an +47th +48H +48hour +49 r +492117837813 49forcerage 4ALLYaYa03 4D Entity @@ -541,6 +899,8 @@ Kevo 4K MrKrabs 4KT Youngboy 4Kath +4L O K O +4LDO 4LeafCIover 4Lt Goon Bag 4MoistScoops @@ -555,12 +915,15 @@ Kevo 4are 4asphalt4 4biddin3 +4cof +4dan2 4dapigs 4dosemonster 4ever 4everdry 4got2pull0ut 4gottenvoid +4hQ 4hit pl0x 4holyhydra 4iend @@ -574,32 +937,63 @@ Kevo 4rKsTon3 4sen 4th lesson +4th8 +4the 4themininoob 4thunderbolt 4ur Elise +4werty4 +5 56 +5 Nine +5 Oh +5 mil +5 ms 5-Bet Fold 50 DKP Minus 500 BJ +5000men4 +505 50Dkp_Minus 50TintenUwMa 50bitsnka +510 51Highlander 51xp 528racklover +5304 530pm 53R10U5 53m0g 54 Slayer +548 +55mg +562 +5639 +56667 +56771910 +56O +570215 +5771 57tallfred 57wraith2076 +5876 +58th +59OG 5ADx 5Aces +5BY5 5G fries 5GCovidTower 5H4NKS 5IRLOIN +5Id3Track +5M3H +5M9SNH31KAOI +5NAX +5OP 5Orudis5 5UBLlME +5a9 5alood 5alve 5ammito @@ -607,28 +1001,69 @@ Kevo 5eekingdeath 5eizures 5g Internet +5gum 5harp5hoota +5hauny +5hayWh1te 5head 5inch Floppy +5is +5j5 5kc Zulrah +5l9 +5lNS 5lap 5nis 5parrow 5quid +5st +5t h 5th Blessing 5th hcim LUL +5trm +5wan 5wattia +5x3 +5xr2 +6 57 6 9buttholes 6 Donuts 6 Drive Fox +6 Foot 5 +6 I X GOD +6 M 6 Mil 6 Qp +600 Years +605 +60min is 1hr +617 +61V +6264 +629fm 62steeplist +6384 +647 +64DD +64th +6535 +6620 +666 317 +666 J +666 is leet +666Ds +666Duuvel666 666drkwizard 66Cute 66sick +675 +67M +67jj6j7 68 savage +6822ii 68pickleman +69 L OR D 69 +6942O 69KolaOlli73 69Skrrt420 69bbygurl @@ -637,10 +1072,17 @@ Kevo 6ESkarmory 6LACKY 6PaperJoint +6R6 6T9sofine +6TMG 6Tilbud +6UGG 6cansOfBeer 6cythe +6dr3w9 +6e +6enny +6ess 6et Schwifty 6h Logout 6in9 @@ -648,25 +1090,72 @@ Kevo 6ixty 6ixx 6jadkiller +6km 6lb brownie +6mat +6ong +6p8o6 6pathsofpein +6qp 6shooter 6uapo +6uh 6utt9lug +6y6y6y2 +7 7 MAFIA +7 Curry 7 DeadlySins +7 Fat Drake +7 Of Nine +7 Trouts +7 pets chimp +7 seconds +7042 70Point1 lol 70rangeboy +70to120 +710 710 710 +716 +718m +71rc +72005sc +73 and Kree +734590325839 +737 73Head 73HoundKey +73gp +742617OOOO27 74ChaosLTUU 75 IQ +76frozen44 +76ms +7738 777slayer777 +77Dunamis77 77Stingray +77ms +782 +784162 79giantfoot +7AYL0R +7D9 7Esconar7 7Ethereal +7F9 +7GB +7God +7H3 +7J4FXEL7YFW5 +7Lazy7 +7RAC +7T +7TF 7Vick 7Viggie +7ZP +7abibi +7amowdahli 7aq 7asty 7ate9 @@ -676,13 +1165,20 @@ Kevo 7ckng Mad 7claudia7 7crypto7 +7emo +7emp 7emptest 7fisherdog 7havage +7min +7mins +7mni +7om 7ourney 7out 7rad3 7raphouse +7rev 7ridley 7scaryfire 7th Chamber @@ -690,45 +1186,104 @@ Kevo 7uP joAo 7wizard10 7xshadowx7 +8 1 O +8 3B +8 Sue Build +8 alien 8 +8 bit bling +8 oh 8 8008tator 808Southside 80leavefox 82 Sue Say +8282 831pride +832arba +8485 +849 84Bandit +85 N +8502 +852K +858 +85U +85dakota85 +88 Odd Wand +8800 +8885 +88gg +89devoid1329 8ASS 8BootRaw6220 +8ElMandinga8 +8J8 +8O8O8O8O8O8O 8ass 8balknowsall 8balled 8eauty 8h of sleep 8ind +8l0wm3 +8lackMamba24 8loodrune 8lue Phat 8owser 8qxkf02v 8tail 8uD -99 Problems +8yrs +9 9 Problems +9 B 0 +9 DUIS +9 Tick Brain +9 mb 900mexp 901Grizzlies +90804 +9092514 90tegguy +91 91 Tin Idea 911_Nate +91414 91CAL 91flip 92 way there 920 Bdops +9227 +9297 +92t 92times2is99 +94 xp 94AR BTW 95EliasAw +95LH +95p7 96 WINDSTAR +9687 96fastfrog +97DEF 97ccman97 +97fsh +98 BEDARD +98 Civic +982 +98Bn 98max1 +99 Doobies +99 Grill +99 Grinding +99 Mage +99 Rats +99 StaKe LvL +99 Steeze +99 oz +99 rwt 991atatime +9991499 99BnkStnding +99Juuling 99Lives 99S2HP 99Scents @@ -739,24 +1294,40 @@ Kevo 99_Maxed 99bottin 99charming +99hh 99moretimes +99ox 99problems4 +99ss 99sweatlvl +99wc500m 9Bar 9Barr +9CX 9D9Skillzz 9Dimensional 9GAG Reflex +9JR 9KL00AZIIZ9K +9O 9 9PetsSoFar +9T3 9TY9_Sailing +9UNIT 9cansRavioli +9ieman 9inchStepBro +9mm ko 9mmlesah +9ne +9ond 9till5slave 9ussy 9yearoldpops A 2 The Aron +A 3 +A 45 +A 7 F O L D A Articuno A Bad IGN A Bad Meme @@ -775,12 +1346,15 @@ A Cityzen A Claptrap A Classy Boy A Crazy Cook +A Crisp Sock +A Curry A Cute Snail A Dreamer A Drunk Beer +A Du Ma A F K Scape A F KING -A F Scape +A F M Scape A Fat Deer A Fat Pike A Fat Swede @@ -790,10 +1364,20 @@ A Godsword A H Fire A Half Fool A Hofasho +A I D E N +A I I e n +A II D A Iron Yoshi +A J +A JJug A Jack O Lit A Jug A Kimura +A L 3 X +A L C A P WN +A L E K S +A L I S H A +A L T A Lava Lamp A LifeTime A Lilypad @@ -823,6 +1407,8 @@ A Pot Head A Psy A Quest God A Quickie +A R H +A R Z A Raccoon A Random 4nr A Real Bamf @@ -851,44 +1437,64 @@ A Wise Sloth A X Y S A Yang A Yep +A Zee +A Zeer A Zoo Keeper +A Zuk +A Zuzakini A aron A bit north A broke 126 A capybara A cclimation -A deby +A d e b y A dam A damm A dammmm -A edo -A esir +A e d o +A e s i r A f r a i d +A gg +A lba +A ll F A llan A llstar A ltar A m a nd a A n d re +A nz A rdy A rmin A rmoa A rrow A stoner guy +A to teh Jay +A ug A y s a A z k e n A z t e r A-Chronic A-F-Kaveman +A123 A13X +A15 A1KMAN A1nz00alGown A1rhook +A2 +A22Y A47 Soldier +A543 +A7MED +A84 +AAA GG AAAAAFK AAAAAddy AAIGHT AAsamba AB Dash +AB84 +ABEC ABG Huntr ABILITEETTI ABearCat @@ -896,6 +1502,8 @@ ABlazys97 ABlueShirt AC Dicing AC TEMP IQ +AC0T +ACDC ACatGirl uwu AColdBeer AComp @@ -932,8 +1540,11 @@ AFKspiracy AFTW AFX64 AFrickinLion +AGIT8 +AGP3 AGRONOMlST AGSpec +AGWA AGlassOfH2O AGorski AH Energy @@ -945,6 +1556,7 @@ AHarmlesKitn AHlager AHriMTaLeZ AI Fighter +AI0 AII 99 AIchemyz AIecko @@ -954,14 +1566,26 @@ AIixs AIlByMyself AIm23ARDesti AIways sm1le +AJ R +AJ Skills +AJ4J +AJTracey +AJ_24 +AJisHere93 +AJsk AK Alpha AK Sam +AK47 +AK4LF +AK5C AKI-47 AKK1E +AKM AKSpring AKinkyMonkey AL-Trojans AL3CX +AL7 ALBlNO ALEXppresso ALLCAPS @@ -978,14 +1602,18 @@ ALonelyKurt ALonelySpoon ALonelyTaco ALv3Magikarp +AMAWM AMC Millions +AMD352 AMDOSRSIRON2 AMGS65 AMRSY +AMST AN07HER AN0NYM0OOOUS AN1MAL1ST1SK ANDERDAPLUG +ANDR3 ANDREVVTATE ANDROlD 18 ANGL0 SAX0N @@ -1002,8 +1630,14 @@ AOT GOAT APC L000000L APTZ27 APrince +AQ COCUGU +AQMD +AQUAMARROCKZ +AR Brah AR Fifteen AR15ONA +AR1F +AR53 ARCANO RS ARCHER ARCHIT3CTS @@ -1036,6 +1670,7 @@ ATastyPastry ATurboVirgin AU6URY AUD1O +AURl AUSLANDER AUSTlN AUTOart @@ -1054,6 +1689,8 @@ AXL gun ROSE AYRI DMM AZER AZNPanda +A_G_4 +A_Wuh AaaBiiCee Aaalmost Aadalyn @@ -1075,12 +1712,35 @@ Aaron Btw Aaron Quiz Aaron Samuel Aaron11700 +AaronJMLP AaronPVM +Aarsworm +Aarti +Aary +Aaryn +AashUnce Aastradsen AatroxLife Aauburn AavikonGaara +Aayraz +AbInito +Abaay +Abacraumbii +Abaiz +Abaker +Abaqus Abariel +Abbas Elect +Abbey +Abbey Ruins +Abbo baker +Abbyscimmy +Abc easy as +Abdallah6 +Abdirahman +Abe lnnkon +Abe numse AbeTheHobo Abengers Abernasty @@ -1088,6 +1748,7 @@ AbiChillii Abide Abido Abigayyl +Abismaalinen Abito Abiuro Ablazin @@ -1135,6 +1796,11 @@ Abstractable AbsurdGreek Absurdly Gay Absynthial +Abu Chungus +Abu Salih +Abuk +Abulssoni +Abuv Abyission AbysmalGrind Abyss Laps @@ -1184,6 +1850,7 @@ Aces Aces x3 Acesuke Acesupersoak +Acetazolamid Acha9 Achaeos Ache @@ -1195,6 +1862,7 @@ Achilles Low Achilles XXI AchillesFist Acholight +Achuu11 Acid Acid Cat420 Acid Christ @@ -1209,7 +1877,9 @@ AcidHouse Acide Acidic Acidylia +Acir Ack Varmland +Acke AckeSSBM Ackman67 Acko @@ -1401,6 +2071,11 @@ Aeugh Aev Aeyriex Aezolix +Aff it +Affaires +Affan Khan +Affect +Affectie Affidra Affinivax Affirmed @@ -1426,6 +2101,26 @@ Afkin Afkoelen Afkstar Afkwarrio6 +Aflamed +Afnacho1 +Afonso +Afperser +Afrecan +AfricaSavior +Africagamer1 +AfricanMelon +Afrie +Afrikka +Afriquee +Afro +Afro Deagle +AfroFishh +AfroShay +Afrojofe +Afroman +Afromann +Afromouse87 +Afrothunder Aft3rmath After Dark After3Scoops @@ -1509,6 +2204,10 @@ Ahriah Ahrim Job420 Ahrou Ahvexx +Ai Haibara +Ai activated +Ai u +AiMienOortje AiNebesvaik AiXiao Aiai8 @@ -1556,6 +2255,11 @@ Airstone Airstrike Airstrikes Airwalk +Airwipp +Aishi owo +Aisyah +Aivery +Aiwe Aixaa Aixleft Aiyaaaa @@ -1563,6 +2267,21 @@ Aiyzer Aizor Aizzz Aj Blitz +Ajamian +Ajarn +Ajaxius +Ajdj +Ajeh +Ajeti +Ajikk +Ajinz +Ajt141 +Ajushox +Ajuus +Ajx +Ak 4854 +Ak5u +Aka God AkaSpecs Akadian Akagi @@ -1573,6 +2292,13 @@ AkaseAkari Akasha Akashy Akatsuki +Akaza +Akduman +Akeno +Akhasa +Akhavan +Akhotha +Akiha Akihiko Main Akilled Akimbo Gmaul @@ -1606,6 +2332,17 @@ Akustic Akvarij Akyba Akyle +Al Go Rhythm +Al e x x +Al ex G +Al-Kimiya +AlCaponee +AlFromOhio +AlIigator +AlMusallam95 +Alabandus +Alabarce +Aladfar Alak4zam Alakazoom Alakazzaror @@ -1634,6 +2371,9 @@ Albertttt AlbiBambi Albin0z Albinos10 +AlboBloodZ +Alboy +AlbusTheDood Albuun Alc1 Alcadeias @@ -1724,6 +2464,27 @@ Alexx2G Alexxandraa AlexxisTexas Alexzilla +Alf11 +AlfaAleksi +AlfaQ +Alfahane +Alfahanne +Alfication +Alfie 96 +Alfonga +Alfonso +AlfonsoKhan +AlfredTB +Alfrid +Alfuh +Algiebeer +Alharbi +Alhyrr +Ali Shuffle +AliThePvmer +Alibaba +Alicander +Alicc Alice Alice x AliceOMalice @@ -1737,6 +2498,7 @@ AlienVoucher Alienmage Aliens Aliii33 +Alijr AliksOh Alioman AlistarTb21 @@ -1866,10 +2628,21 @@ Alrite Alry Alsatian Alsatians +Also +Also Jack +Also Luci +Also Lucky +Also Nexxtar +Also Noexi +Also Schlak +Also kawkky +AlsoAlso AlsoRabbit Alst Alston Alt Ctrl +Alt G boys +Alt Juana Alt Redshok Alt prepot Alt3rbridg3 @@ -1925,6 +2698,12 @@ Alwin S Alxs Alyks Alysanne +Alyv +Alzad +Alzuraak +Alzz +Am eer +Am ity Am ln Danger AmCatWhatDo Ama zon @@ -1972,6 +2751,22 @@ Amend Amenity Ameno l Americlaps +AmiableDingo +Amibis +Amida +Amigeau +Amigo +Amigos +Amillie +Amin +Amir Psycho +Amis +Amitwin +Amityz +AmixBeast +Amjad +Amjar +Amka0s Amkings Amlodipinee Ammastian @@ -2057,6 +2852,8 @@ Ancientz pal Ancitif Ancona Ancow +And e +And r ew AndSo AndYetISmile Andardenn @@ -2073,6 +2870,7 @@ Andiamo98 Andipyrus Andirath Anditre +Andj Andoyen Andrade149 AndreasBL5 @@ -2159,6 +2957,15 @@ AngryNachos AngryPickle AngryScape AngryWizard +Angsti +AngusM +AnhTaDuong +Anhedoniaa +Anid +Anida Hanjab +Anidien +Anieli +Aniheyu Anim Anima Animal @@ -2324,7 +3131,15 @@ Anzie Anzied Anzu Anzypoo +AoA Jammer +AobaJohsai +Aog +Aoh +Aohc +Aohu Aoi Tetsu +Aokijahr +Aokijii AonEne Aonyx AoooA @@ -2335,11 +3150,16 @@ Aozaa Ap0logy Ap0phis Ap3x +Ap870 +ApRoMn +Apaat +Apaatje Apache Apache30 Aparlo ApartAbyss Apathetik +ApdoJ Apdomine Ape Cape Ape Dos Mil @@ -2349,6 +3169,7 @@ ApetimusPrym Apex Apex Pro Apex-scaper +ApexGT Apexflashy Apexist Apgujeong @@ -2674,6 +3495,14 @@ Arrowtower Ars Nova Arsaydar Arsenals +Arsene rar +Arsenic +ArsenicEyes +Arsenn +Arshal +Arsi +Arslen +Arson ArsonScape Arst Arstan Selmy @@ -2938,13 +3767,17 @@ Atvinnulaus Atylos Atza Au 0srs +Au 1 +Au Bar Au Barrett Au Joel Au Shooty +Au92 AuRoyce AuStarZ Aubrey Aubrey UIM +AubsG Auburn Lax Aubzzz Auclaw @@ -2967,6 +3800,8 @@ August AugustAmes Augustiner16 Augutis +Auhdy +Auja3 AuksoAlt Aulono Aumoki @@ -2993,6 +3828,7 @@ Aurtle AurumFoxfire Auryn Aus +Aus 2277 Aus Shizam AusBruto AusGram @@ -3169,6 +4005,9 @@ Ayenull Ayetg Ayfi Aylia +Aylward +Ayman +Ayo4Yayo AyoSteeze Ayoe Ayonikz @@ -3177,11 +4016,41 @@ Ayri Ayrton Aysuu Ayveros +Ayy Nakana +Ayy bae bae +Ayy q p +Ayyye +Ayyyon +Ayzo +Az PVM +Aza zel +Azad +Azad Kashmir +Azala +Azami +Azandari Azathor Azathoth26 Azathrir Azazel OSRS Azeenil +Azemu +Azerma +Azez +Azimut +Azimuthaal +Aziz +Aziz7 +Azkaton +Azken +Azkybot +Azlo +Azmataz +Aznbabe +Aznmixboy +Azom +AzorAhaiBTW +Azotize Azoxy Azpa AzraelReaper @@ -3213,8 +4082,69 @@ Azzanadraa Azzax Azzgarnia Azzz -B0BS -B0SS +B 0 B S +B 0 S S +B 0 U J E E +B 3R +B 58 +B A F F E Y +B A MF +B A U W S +B B Bouncy +B C 2 +B C M +B CA +B D Y +B E E G +B E R T A +B E R t I 3 +B ELA +B Gates +B Gonkeybron +B I G G L E +B I R T +B Ian +B J O R N +B L 4 N K +B L A D E Z +B L A N E +B L A Y E D +B L ANK +B L I X T +B Milesy +B Minor +B O G S +B O O T H +B O Y E A +B R A l N +B R II A N +B R l C E +B S +B SlDE +B T J +B Victor B +B W 1 +B W A K +B aylor +B aze +B ecky +B eeez +B iggles +B la z e +B las +B r a g g +B r eezy +B rads +B raes i +B ruised Lee +B u bs +B ug +B un +B utt +B w +B-0-SS-M-A-N +B-Dollaz +B-Lal B00 KAW KEY B00Lici0us B00MERAT3R @@ -3257,7 +4187,14 @@ B1gTTgothGF B1gd0wg B1ink B1mboBambi +B1zrme +B2AD +B2F +B2J3 B2bZeroSpecs +B2rad +B3A5T +B3CK B3NJAMOON B3NT D0ver B3TTERLUCK @@ -3265,6 +4202,15 @@ B3Y0ND B3njamima B3njamin B3nny Blanco +B46 +B4RR +B4S +B4llista +B6a +B6i +B70 +B747B +B8 H8ER BACKURBOI BACONisgd4me BADASS @@ -3283,12 +4229,17 @@ BASEDQwert BATATUNGA BATH0RY BAYLlFE +BBBBBONKA +BBGL +BBK BBKwenie BBL RIZZY BBQs BBW Pizza BBarnzeyy BBeepLettuce +BBoys Father +BCBDestroyer BCC YT BCDOJRP BCK CigButts @@ -3304,6 +4255,7 @@ BEEA BEG0N BEG0NE BEINGMAXDSUX +BELSJ BEMBOU BEST BET5 @@ -3319,6 +4271,7 @@ BIGD05 BIGDROPHUNTR BIGFERGLOAD BIGHEADSMASH +BIGJP BIGMINK BIGSITUATI0N BIKlIllIlIIE @@ -3326,11 +4279,14 @@ BILR0Y BIOATED BIRD SHlT BIRP +BIRWAAA BIS Monster BIaded BIadet BIapa BIood Prince +BJ Applegate +BJ M BJPlaysRS BKBB BKK @@ -3342,6 +4298,7 @@ BLACK DOG NI BLASE BLGesus BLICKYSTIFFI +BLOBi WRX BLOOD BLUEPIZZAMAN BLXCKPINK @@ -3351,6 +4308,10 @@ BMEUR BMooldijk BMrgn BO0MERSO0NER +BOA Liger +BOBGIGALUCKY +BOBYAHMDGECI +BOER KAMIEL BOGOBoneless BOL0CKS BOLSOONARO @@ -3368,8 +4329,11 @@ BOlNEXTDOOR BPNS Hawk BPTheIronOne BPrimitive +BR0 BRO BR00KES BR0CE +BR0ER +BR0THERS BR3AKABLE BRA71L BRACULA @@ -3381,6 +4345,7 @@ BRUTAL BRabbit25 BRlOCHE BSB Howie +BSNR BST Steve BSickler BSven-B @@ -3391,9 +4356,13 @@ BTW Beirre BTW idgaf BTW vs RNG BTWSaberlion +BTWsanta BU1MER +BUHLL +BUILD BUILD PONYS BULLlSH +BUNDHA BUNStheGOD BUR13D AL1VE BURYT0MORROW @@ -3402,11 +4371,33 @@ BUTTB0NERED BUTTCOlN BV Martyr BWheatZ +BYEq +BYOBOOZE114 +Ba1i +Ba5b0y +Ba6y +Ba77erY +Baa m +Baaaats +Baal157 +BaalZvuv Baals Baalthas Baamf Baami Baandos +Baarb Lahey +Baas +Baba +Baba Booey9 +Baba Borgar +BabaLovesKos +BabaSlaaf +BabaSleep +BabaTarzan +Babafasa +Babayaga-9 +Babayaga2121 Baberrandrid Babica Mraz Babiez @@ -3528,11 +4519,26 @@ Baekah Bag it Bag of Yay BagFryLife +Bagadigi +Bagan +Bageera +BagelSpanker +Bagels +Baggyshaw +Baghdad +Baginga +Bagis Bagokk Bags Bags n Beer Bagsnacks Bagz +BahRitTanEe4 +BahamutLimit +Bahn +Bahnzeen +Bahp +Bai Ningyang Baib Bail Jait Baileys @@ -3545,6 +4551,22 @@ BainoLad Bainz Bairac Baites +Baja Baja +Bajan +Bajart +Bajcolado +Bajela +Bajere +Bajhole +Bajista +Bajji +Bajkami +Bajsanus +Baju +Bak cornet +BakIron +Baka Mop +Baka Prase BakaOsaka BakaPho Bakazuro @@ -3582,7 +4604,12 @@ BalazinGIM Balboa Park Balbuli Bald +Bald Arab +Bald Male +Bald Shupa +Bald Sicknez Bald To Bold +Bald Wookiee Bald at 29 BaldKnees BaldMansKenn @@ -3619,23 +4646,36 @@ Balob Balontra Balou Balrogs Hell +Balthazar BL +Baltimohr +Baltimore MD Baltoth +Baltramiejus Baltzerboii Balu Balu Titan Baluk Bam Achilles Bam Grizz +Bambi0326 BambiSlayer Bamboo Bamboo James BambooPandas Bambuliuss Bamf +BamfJoe +Bamfbeav +Bamiman +Bamse +Bamztile +Banan Banefish Banerz Banio Bank Stander +Bankaiz +Banki 1 1 Banzu Bape BapeNation @@ -5106,6 +6146,7 @@ Bmoot BmwNerd BnB Bnaar +Bo Ed Bo Selecta Bo0nies BoBgss126 @@ -5130,15 +6171,29 @@ Bob44th BobBojangles BobCatMilk BobGuenille +BobNegao BobRossDied BobTheDaddy BobaNeZmogus Bobakadush BobbaStanley Bobbanxd +Bobbiie +Bobby +Bobby Brawl +Bobby JoJo +Bobby Lash7 +BobbyBigLips +BobbyBonk +BobbyShurda +BobbySmooth +Bobbyccf Bobbydrake09 +Bobbysweggg BobbyyHill +Bobi Bobicles2 +Bobidabob Bobite92 Bobo Bagins Bobrobber @@ -5549,16 +6604,22 @@ Boze Worm Boze mol BozeOog Bozut +Br ay +Br ibb +Br yan Br00dje Br0ox Br0wnSpit Br3ws Br4dders +Br4w Br5andon BraBraBrad Braaamps Brabbss Brad +Brad RS +Brad T King Brad017 BradIsAChad BradIsChad @@ -5619,6 +6680,7 @@ Brando23x Brandog Brandon Brandon 126 +Brandon TJ Brandon9250 BrandonLarge Brandonp32 @@ -5656,6 +6718,7 @@ Brazeheart Brazzerker Brb Delivery Brblol +Brdy Breaches Bread Bread Again @@ -7168,7 +8231,9 @@ Cewl Cewl Hwip Cexilius Ceyyl +Cf b4 Cfretz244 +Ch i Ch i c k en Ch ief Ch00bies @@ -9031,6 +10096,11 @@ Cvanz Cvbgn Cvrkster Cvrsn +Cw90 +Cwab +Cwazza +Cweavy +Cwer Cwick Cwioktopus Cxffee @@ -9041,6 +10111,7 @@ Cyal8rnub Cyan Cyan Ablaze Cyasoon +Cybb Cyber Mind Cyber n Bug Cyber172 @@ -9109,6 +10180,78 @@ Czechmate Czha Czivend123 Czk +D A I J I N +D A L M +D A M 0 +D A M I A N +D A M N L0L +D A N G I T +D A N N Yy +D A T H I T +D B A +D B Z pker +D Blo +D Clawz +D Darkblader +D Derbles +D Dragon124 +D Duberstein +D E C O +D E F Q 0 N +D E F Q O N +D E R P +D E V I N +D F U Q +D I Q +D I R T Y Ko +D J Diddles +D Long +D M T Elves +D O D +D O M M E L +D R 6 K E +D R l Z Z T +D Rack4 +D S A V +D Squarius +D U R K +D Wilson +D Wreck +D a mo +D a r t s +D a rk +D a u t o +D a v i d +D amz +D arking +D arkoz +D as +D ashing +D avey +D axe +D db +D ebol +D ecimate +D eej +D eek +D eep +D eez +D en +D enial +D entist +D i l a n +D i x o n +D i zz y +D iesel +D iizzy +D imi +D imitri +D onda +D onger +D oo l ey +D op e +D utchgr +D-D-A D00DLES D00dey9 D0CTOR @@ -9158,9 +10301,16 @@ D4nnyy D4rels D4rk D4rth +D7NNY +D9 +D9R DA ODB KIDZ DA0IST DA3N33RY +DA4N +DAD563884271 +DADDYS IR0N +DAHDB DARCHANG3L DARGON DASH @@ -9168,10 +10318,14 @@ DAWGPOUND DArtspret DBA Paulo DBKangaroo +DBO90 DBOL TRICEPS DBUZZ DC Flubber +DC-8-51 DCreek +DD 214 +DD G DD2I4 DDAlt DDSurWrists @@ -9187,12 +10341,17 @@ DESPA SIITTO DESPAlRGE DESTYLAT DFez +DG 00 DGAF DH Marker +DH btw DHIBZ DHSC4EVER DHally +DHlN DHoShow +DIDZZ +DIETDRDIET DINGO SCUM DIORITIC DIORITlC @@ -9221,9 +10380,19 @@ DJMileyCyrus DJMuscleBram DJOFULLIN DJSeinfeld +DKHo +DKJN +DMM 2 07 +DMM Gp Swap +DMM Ryu +DMT Dad +DMT Satan +DMTDAN +DMTe DMagnum 10 DMessengerS DN Atro +DN20 DNFL DNLD DO0FY @@ -9236,10 +10405,12 @@ DONJOHNNNY DOOMBRlNGER DOOMSlayer DOSNE +DP776 DPRNS DPS Disciple DPvM DPvM Jordan +DQ9 DR PAAAK DR VABA DRAEG0 @@ -9282,6 +10453,9 @@ Da Nils Da Puppy13 Da Sniper007 Da T Virus +Da d dy +Da t +Da then bh Da1ton DaBears DaBoz @@ -9345,6 +10519,9 @@ Dachowski Dackel Dackenerino Dacune +Dad Goals +Dad Sean +DadBurrys DadGoingMad DadLeft DadRanarrWay @@ -9352,6 +10529,8 @@ DadamoSte Dadbackward Dadbackwards Dadbod4lyfe +Daddaforce +Daddy Daddy Bundy Daddy Chaman Daddy Chubs @@ -9383,6 +10562,7 @@ Dadfield Dadi415 Dadorii Dadosaur +Dads Dadukez DadurQa Dadyankee3 @@ -9430,6 +10610,8 @@ Dahlareen Dahls Dahlson Dahmonkey +Dahrmata +Dahrr Dahumbug Daijoukay Daiju Spede @@ -9596,11 +10778,15 @@ Daniella DanielleOfc Danielmcken1 Daniels +Danielwat +Daniiieell +Danijenn1211 Danilin Danimal DanisH96 DanishAdonis DanishGoat +Danje Dank Dank Chef Dank Exp @@ -9884,6 +11070,14 @@ DavidPH Davidisiscoo Davidopathy Davis751 +Davlan +Davo +Davord +Davoron +Davros70 +Davshing +Davu +Dawaj Lama Dawg Dynasty Dawkins Dawn @@ -9926,7 +11120,13 @@ Daze DazedDave DazednConfsd Dazzler95 +Dazzz +Dbeatz +Dbewt +Dbmx +Dboot Dbricke +Dbz Pride Dc B L I N D Dc Hakkarn Dc IronMan @@ -9939,6 +11139,8 @@ Dday6Jun1944 Ddestroyer56 Ddos Dds4theko +Ddsing +Ddsme De Algerijn De Baardman De Eryngy @@ -9956,6 +11158,7 @@ De Redacteur De Sam Matie De monic De stoutsten +De us De1icioso DeAndre DeDawgTubb @@ -9967,6 +11170,7 @@ DeHijskraan DeIronMan DeIronedMan DeKawika +DeLL DeLooter DeLouuu DePope @@ -15566,15 +16770,20 @@ Fyrox Fyszz Fyzio Fziaa +G G 0 A T G A F F E R G Alfansos G Ape +G B S G Check G Fruit G GAMER GIRL G I M Danny G Iron Adam +G L E N +G L H F +G M B G Man9822 G Mauls G O O D @@ -15582,21 +16791,36 @@ G O O S E Y G R E E N G R I L L O G Terminator +G X F C G Zus G a r t y G a t t s u +G ante +G dot C G e n g a r +G eeb +G i j s G i l b o +G iG G imme +G iooo G l R L G laze +G no Z +G o G G u +G o h o +G o th i X G oldd G oldeen G oofy +G ozz G rafix G ronimo27 G root +G shi G u a m s +G unitt +G-F-M G-IronKuv G-Thug Nasty G-knowww @@ -15840,8 +17064,15 @@ GTRKingZilla GUBIDUBII GUCCI SENPAI GUCCl +GUJ0 GUNMAN683 +GURRD GUUMBY +GVSU +GYDtown +GZA +GZX +Ga l Ga7ba Gaara Gaara Sand @@ -16039,6 +17270,7 @@ Gastje888 Gastronaught Gate Gateofdoom +Gath Gato GatoNaranja Gator @@ -16065,7 +17297,9 @@ Gavy Gawd Bodi Gawk5000 Gawkes +Gawkss Gawt +Gawz Gay 4 Guthix Gay Bear Gay Bear Cub @@ -16323,11 +17557,23 @@ Geuld Gew Gewoon Gezang +Gf g Gf4tiuser GfRsIGotAGf +Gfi +Gh3t0 T4nk3r +Ghafir +Ghaipol +Ghandizy +Ghandy +Gharron +Ghckkrchkrer +Ghda +Gheed Ghentiana Gherkins Ghetto +Ghhjgwsr Ghidorah Ghillie Suit Ghilly @@ -16547,6 +17793,10 @@ Gixerikan Gizmoed Gizmoo247 Gizzy-71 +Gj nice +Gjerloew +Gjonunaki +Gktr Gl Bob Gl Im Dandy Gl Im Tom @@ -17655,6 +18905,36 @@ Gytisr9 Gyts Gyym Gz Parsec +GzBs +H 0 U N D +H 2R +H A D O +H A I D E S +H A M M E H +H A R L S +H A T +H A X 3 D +H D M P +H E A L E R +H E J S A N +H O L M E +H Q Killer +H S 7 +H U L K K +H U N A J A +H a t y +H a w n y +H abs +H alo +H ch +H e c t o r +H i n e s +H l E U +H obbs +H owl +H rekDoer +H uff +H-tsi H0B0 H0DEX H0LINESS @@ -17662,6 +18942,8 @@ H0NA H0PES H0RSEFIGHTER H0RY +H0j +H0j00 H0lyPorkyPig H0me H0nestyBe @@ -18838,7 +20120,7 @@ Hislordship HisokaX4 Hispeeed Hissi-Timo -Hit U +Hit U Hit By Car Hit Points Hit The Guam @@ -18871,6 +20153,7 @@ Hldz Hlep Hlnub Hm +Hmg Hawj Str Hmm Fr Bruh HmmKoekjes Hmmer @@ -19014,6 +20297,8 @@ Hompski Hon Honaz Honchcrow +Honda Coupes +HondaXJ20 Honden Hondo Ohnaka Hondsvot @@ -19515,7 +20800,9 @@ Hyun Hyxbe Hyze Hyzers +I M I Skilz I +I ADK I I AM DROID I Am Arun I Am Calysto @@ -19530,6 +20817,7 @@ I Am Vexed I Am Vono I Am Xyience I Am Yesac +I B Z I Barak I I Be Vibing I Be Yankin @@ -19572,9 +20860,12 @@ I Heal DHers I Herb Store I Hunt Pets I Hustle Man +I I ODIN I I I JANGLER I I Judgee Yu +I Ko U Lol 1 I L0ve Lolis +I LOTR I I LV PEACH X I Lezima I I Liam I @@ -19591,6 +20882,8 @@ I Luci I Luhhya I Luv tSwift I M A P nuss +I M Ket +I M S N Y I M The Weed I Maxed OSRS I May Be @@ -19601,7 +20894,10 @@ I Need 1M I Need Succ I Need aBeer I Novato I +I Nz I +I OX I Owning +I P0 I P0KY I I Parry I I Peter I @@ -19610,6 +20906,10 @@ I Plank Lots I Play Aegis I Pod335 I Pri +I Q T +I R N B R U +I R O N 99 +I RC I ReAPeR I I Roll Need I Ron Man @@ -19681,6 +20981,7 @@ I sak I smell zaza I so pale I squared R +I t I s I tbag cows I used to Rc I van @@ -19688,6 +20989,11 @@ I vinrox I w4ste xp I wana dew u I want wings +I-IEEBO +I-Iulk +I00OOOOOO00I +I2P +I2m I2ocky I2ossiiii I3ET @@ -19698,7 +21004,9 @@ I3ox I3rucex I3ubbles I3ulow +I7I I7iablo +IA IAM HARDWELL IAMBillNye IAMDouble_C @@ -19727,7 +21035,10 @@ IBloodwing IBuyGF5GP IBuyPowers IBuyShungite +IC 3 +IC XC NI KA ICE GIANTT +ICNK ICantFit ICauseRage ICrazyCamelI @@ -19739,6 +21050,12 @@ IDiabloI IDustie IEATEDYU IFALL3NI +IFIFIFFIFIF +IFIFIFIFFIFI +IFIFIFlFIFIF +IFRC +IFRS +IFRS 9 IFartOnBaby IFernedYou IFistBonk @@ -19757,19 +21074,31 @@ IHuntKoalas II Fabi II II Gots Piie II Mossy II +II TurMz +II0III +II0v0II IICyRaNoKII III SLAYR +III jin III +IIIBCIII IIIGavinIII IIIel0n IIIusionist +IIKOO +IIPAC IIPrincesaII II_Blanx_II IIamaman IIflemishII +IIlIIAS +IIlIIoIIlII +IIllIll +IIlllllIIlIl IIndy IIrisviel IIsaac IIx Link xII +IJzer Bal IJzermeneer IK Pegasi IKotol @@ -19859,7 +21188,9 @@ IMAEATURASSS IMAFKNNONCE2 IMGOKU1 IMHankey +IMHky IMJeffG +IMMezzo IMNagrom IMPERlO IMPlayerjohn @@ -19933,11 +21264,18 @@ ITIajestic ITIallen ITIasKilleR ITIassacre +ITIatty +ITIerica +ITIiko +ITIoj +ITIoosh +ITIr ITSPYRO ITV X IThe Beatles ITrimGlories ITurtlekunI +IUR IUntradeable IV Luke IV skin @@ -19958,6 +21296,8 @@ IVIush IVIxtthew IVOXYGEN IW Lytheria +IW4M +IWGP I_Eat_Ass04 I_Inity I_Noodz_I @@ -20154,6 +21494,8 @@ IkkleHorvick Il Il MrBorn lI IlIBooieIlI +IlIIIIlIIIlI +IlIIlIllIlII IlINard0IlI IlRisklIlIlI Ileeze @@ -20227,10 +21569,12 @@ Im Hawkward Im Hersh Im Huck Im Hunta +Im Hussain Im Iron Im Iron WTF Im Jags Im Jokers +Im Jovian Im Just Ken Im Krazy Im Kyle Btw @@ -20371,6 +21715,7 @@ ImVanilla ImWargasm ImWilbur ImYourDadBTW +ImZe ImZorp Im_Stone126 Ima Guy @@ -20447,6 +21792,8 @@ Improv Improved Impulsive Au Impurest678 +Imql +Imre Imsain Imsokwtie Imstratss @@ -20679,6 +22026,7 @@ Ionia Iono Iou689 Iowa146 +IowaCJ Ioyal Ioyins IpeeInTheSea @@ -20696,6 +22044,9 @@ Ir0nMammoth Ir0nMish Ir0nPuma Ir0nRagnarok +IrDA +Iralimir +Irha Irid Irie IrieLuDa @@ -21568,6 +22919,95 @@ Izvorul Izzy IzzyBigBoy Izzyboy300 +J 0 S H Y +J 0 S H l +J 4 6 +J 4 K E +J 6 +J A B S +J A I D A N +J A M A L +J A N K I +J A U N U S +J A W D +J Breezi +J C Trousers +J D +J D Ballew +J Dahmer +J E E V E 5 +J E T +J F +J Fred Run +J I M M +J I MM Y +J Kole +J Kribzz +J L A +J MF B +J Neat +J O E G +J O L T I K +J O T A +J O3Y +J R O C +J R V +J Rat Cow +J S 2 M +J S Z M +J Saints +J Suave +J U S T A S +J U Z +J a c k a l +J a c k son +J a c k y +J a mie +J a n i +J ackal +J al +J ameper +J anii +J appie +J asnah +J ason +J asyra +J ayson +J bellfortt +J bird shady +J e sse +J eff +J effy +J ensen +J esse +J essica +J imme +J imy +J imz +J ipr +J lMM Y +J o b e +J o e +J o ey +J o f +J o s h y +J oep +J ohannes +J ointz +J oke R +J or G +J oshh +J oshhh +J osie +J u wu +J ung +J unko +J utch +J uun +J uwu +J x B +J yy +J-2tha-R-O-C J-Man 93 J-Turn J-Yeezy @@ -21594,7 +23034,22 @@ J0seph J0shh J1MB0H J1NBE +J1ub +J2TR J2caine45 +J2ck +J328 +J3Ciron +J3JU +J3S5E +J3rkkuHD +J41AL +J45e0wns +J4QS +J4S +J4gga +J4my +J95 JAABASNABBA JACK3DJOHNNY JACKYOUNG93 @@ -21606,30 +23061,79 @@ JAVON 9-INCH JAYJ51 JAYR0CKBABY JAlDYN +JB 2K +JB87 JBGard JBrody JBuck057 JBux +JC-1989 +JCS07 +JCole +JCon +JCutler +JD MD +JD4 +JDBass +JDEP +JDFlaSh +JDJM +JDez +JDlion +JDredd66 +JDuck +JE B JEEZE JENNY JENNY DEATH JERN SVIN TO JETSNBEERS JF Kennedy +JFB +JFCK JFK gone AFK JFKautopilot +JFL JField JFrog JFryGuy JGIRONTG +JGIV +JGlen97 +JH3305 +JH91xx +JHINitalia +JIGGYWIGGY +JIIVEE94 +JJ-M +JJ23 +JJAAKKO +JJBW +JJPowers +JJROCKETS +JJRicky +JJS BBQ +JJSM_Dulker +JJchris66 +JJoe +JJumalwelho JK Rowling +JKMi +JKTimbo +JKUR ON 40S +JKeM +JKingJ777 JKrollin JKuyaa +JLG JLowe JLsone +JMI NG JMTaipei JMack JMiddd +JOBBO +JOCKO00O0O0O JOE EROTIC JOKER 709 JON3ZYY94 @@ -21645,6 +23149,9 @@ JPantless JPatness JPence JPountney +JPudz +JR05E +JR0D JRBeast JRC Crypto JROGU @@ -21660,12 +23167,32 @@ JSilvester08 JSlice94 JSplash JStepho +JT5 +JTAG +JTCS +JTI ain +JTIAIC +JTM33 +JTscape +JUGIB +JUIBE JUICEWRLD9 9 JULlAN JUST JUST A HlPPO JUST Nikk JUSTICE +JWRLD +JXJ +JZB +JZX1O0 +Ja k ey +Ja m e s +Ja mes A +Ja se +Ja sn +JaBouris +JaDig JaStraater Ja_Fireking Jaaaakkoooo @@ -21773,11 +23300,32 @@ JadsVag Jaecob JaegerBoom Jaeson +Jafacakeman +Jafanto +JafarTooHigh +Jaffa Jake +Jaffar +Jaffywaffy +Jafsx +Jagdpanther JagerBombski JagerIron Jagermeister Jagged Jaggen +Jaghatai K +Jagoodiii +Jah toch +JahIthBer +Jahaerhys +Jahaok +Jaharred +Jahbby +JahgexPlzzz +Jahmay +Jahmerica +Jahngles +JaiSiaRamJai Jaiden184 Jailbreak455 Jaime 427 @@ -21806,6 +23354,13 @@ Jakey Jakey C Jakeyosaurus Jakeyz +Jaknop +Jakrem +Jakrojan +Jakuli226 +Jal-Nib-Jmal +JalNib +Jalduii Jaleesa Jales Jalim Rabei @@ -21839,17 +23394,24 @@ James Kelp James Poncho James PvE James Rolfe +James c James osrs James1087 +James2709 +James9 +James945848 +James9520 JamesBondss JamesCUFC JamesDaWizar JamesHaliday +JamesJ2019 JamesLango JamesMaynard JamesNI JamesPratt94 JamesShotGG +James_22 Jamesay Jamesbombom Jamesrb1 @@ -21878,6 +23440,9 @@ Jamosbondos Jamppa Jampy Jampyre +Jamuli +Jamurazi +Jamwa Jamyroo531 Jamzylockz Jamzz @@ -21914,6 +23479,21 @@ Janne JannpajII JanoPotato Jansky +Jansz101 +Jante +Jantex +JantheBear +Jaooa +Japanese +Japhur +Japiohh +Japles1 +Japoolie +Jappieee +Jappieness +Jappo +Jaqen +Jaqquu Jar Of Pets Jar Uh Dirt Jar of Pukes @@ -22042,8 +23622,47 @@ Jayster Jaytea Jayteaf Jaytee1262 +Jaywub +Jayy +Jayy Slays +Jayy x +Jayzar +Jaz Coleman +Jazo +Jazpurs +Jazz +JazzFlap +JazzMaster09 +Jazzeh +Jazzjr89 +Jazzly +Jazzy +JazzyFlips +Jb Godranger +Jba123 +Jbevzzz +Jblieves88 +Jbob72 +Jbt +Jbvff +Jc_TheCops +Jcb4646 +Jcdelavici +Jchn +Jcmalone23 +Jcolts20 +Jcourt1 +Jdaws +Jdidy +Jdoggy2018 +Jdp3 +Je nny +Je pppe +JeBoyHiddema JeIlo JeIly Man +JeJoat +JeK0 Jean Jean belette Jean man @@ -22120,6 +23739,7 @@ Jelen Jelenner Jelior Jella +Jelle Jelle Bouma Jellie40 Jellisme_99 @@ -22135,9 +23755,12 @@ JellyBeanRs JellyGenix Jellydonuts Jellyfishes +Jelziin +Jelzini Jemades Jemelope Jemile +Jen na Jen0va JenaTulwarts Jenessa @@ -22203,6 +23826,128 @@ Jerry Maine JerryChinger JerryMina Jerryy +Jers +Jers Knot +Jersh +Jershawerr +Jersion +Jertz +Jeru +Jerunox +Jerusalenm +Jerziii +Jerzy +Jes2x +Jeseeka +Jesh g +Jesh-mar +JeshusChrist +Jesiah +Jesk +Jesliq +Jesper Bratt +Jesper135 +Jesperyo +Jess +Jesse +Jesse Top +Jesseq +Jessica +Jessie +Jessie Jones +Jesspresso +Jessy +JessyTrip +JessycaOSRS +Jester Head +Jesterbubba +Jesus +Jesus I love +Jesus MPhys +Jesus Saved +JesusComing +JesusRedeems +Jet Jaguar8D +Jet3010 +JetFlame +Jeththe +Jetlag +Jetma +Jetridder11 +Jetski +Jetsmoke +Jettiesimp +Jettrider +Jeugd +Jev21 +Jevel +JewFroBro +Jewbaaca +Jewbakah +Jewbang +JewishRob +Jewy +Jexlad +Jexlo +Jeyos +Jeyzuz +Jezeus +Jezkoz +Jezuux +JezzaripHD +Jezzie +Jezzx +Jf-n03 +Jfleeze +Jfrith +Jfuzzy +Jglove +Jgus88 +Jgy1889 +Jhackal +Jhb +Jhebs +Jhny +Jhonlovin +Jhoocy +Jhoocy Moot +JhormanCovid +JhosS +Jhow +Ji bs +Ji m m +Jia Lissa +Jian +Jiara +Jibajaba +Jibberflexed +Jibbllyy +JibinSui +Jibneh +JibrilMaster +Jiffee +Jig Bugs +Jiga Chad +Jiggalagg +JiggerJoe +Jiggity +Jigglyboy +Jigglywoo +Jiggypufff +Jignite +Jigoogly +Jih +Jihe +Jihne +JiiU +Jiiko +Jiim Lahey +Jiiraiiya +JikdarShark +Jikkurr +Jiklim +Jill Hyde +Jille Man Jim Jim Sauce Jim Shorts @@ -22261,7 +24006,9 @@ Jims Ironing Jimsterjim Jimver Jin Oh +Jin R n G JinDoritos +JinJ0 nJuice Jinb JingleBiloba Jingy @@ -22299,12 +24046,22 @@ Jixr Jixx0x Jiyool Jizt +Jj Dynomite +Jj Jerk2 +Jjar127 +Jjjjjj210 +Jjozzie Jk Esq Jkdogg Jkhby Jkl Kalja Jkolrur Jkrexx +Jku45 +Jl-SOO +JlGA +JlLLY +JlMMB0 JlZZB0SS Jlarge Jlova @@ -22324,9 +24081,27 @@ Jmz Jnas JnrSeneca Jnsthenx +Jnup +Jnwp +Jo Pain +Jo de Coeckh +Jo h 2 +Jo iron +Jo rd an +Jo shua +Jo we +Jo0l +Jo3 H +Jo3p +Jo5p +Jo6p +Jo711 JoE ShMoee JoEiSaFiShEr +JoJi +JoJo JoJo Skriver +JoJo79 JoJoJoUrBoat JoKerRtheGOD JoMoe @@ -22381,6 +24156,7 @@ Joee P Joeholding Joekle Joel +Joel 9444 Joel In Pain Joel Lobster JoelBtw @@ -22470,6 +24246,16 @@ Johnsters4 Johny Johny Aus JohnyLocoo +Johnyy +Johuab +Johzyn +Joizz +Jojis +Jojj +Jojkan +Jojo Rabbit +Jojora +Jojy Jok Jokar Joke @@ -22646,6 +24432,46 @@ Josh x Josh013 Josh2Godly JoshD +JoshDagainz +JoshGymnast +JoshMarksman +JoshYewAhh +Joshalog +Joshan +Joshery +Joshh +Joshhhh +Joshii +Joshimitzu +Joshism +Joshjoshin +Joshmaster31 +Joshpaul +Joshua +Joshuaaaah +JoshyCii +Josiah Higha +Josiahs +Josoust +Joss +Josse +Jostavo +Josti O_o +Jostle +Josue +Josukes +Josylvio +Jota_420 +Jote +Jothha +Jotjemenotje +Jotq +Jottini +Jotunheimar +Jotwe +Joueur4376 +Joulaha +Jovial Jovilius JovyGaming Jowah @@ -22665,9 +24491,21 @@ Jpan1 Jpellican Jpq Jqwss +Jr Metro +Jr Muffin +Jr Stigel +Jr2k13 +Jrabbat +Jrby +Jrdn Jreppks Jrey Jroanirr +Jrodjok +Jrogo +JsJays +JsN4 +Jsag Jsi7111 Jsnn Jsony @@ -22757,6 +24595,18 @@ JuicyTigr JuicyWetNut Juicy_Newfie JuiicyAF +Juikki +Juint +Juipp_Iron +Juisy +Juk e +JukeLess +Jukebot +Juked +JukeduM +Juko +Juktes +Jul es Jules Julesbak Julia @@ -22914,9 +24764,100 @@ Juun Solo Juuna Juunaz2chips Juustis +Juuzo +Juvi +Juvian +Juzzy +Jvzy +Jwad +Jwcsg +Jwd +Jwett +Jwu +JxJxV +JxcelD +Jxck +Jxcx +Jxdidiah +Jxdooo +Jxhnn +Jxke +Jxmeson +Jxnas +Jxni +Jxstxn +Jxxst +JxyStorm +Jy +Jybais +Jyeronese +Jygers +Jyhlln +Jyhy +Jype +Jyppedi1992 +Jysk +Jyura +Jyy +Jyypy +JyzzBrah +Jz +Jzbeta +K 1 L L A +K 1 P +K AMI +K B D autism +K E K E B +K E L A +K E T CHUM +K E V 0_O +K Hades +K K Boef +K NW +K O L L I +K O M P I S +K OOOOOOOOOO +K P N +K P Sweet +K Smalls +K W +K W A L A +K Y Y +K a l e w i +K a z a +K aarel +K ayyla +K eller +K elvin +K en +K etaminer +K ev +K iNG IRON +K idd +K ilo +K im +K l 9 +K l N G S +K nauss +K nut +K o j o +K o o s a +K ohen +K orruptt +K ree +K rs +K t r n e +K una +K ushi +K uz +K voth e +K y u m a +K yogre +K-Diddy K-epan K-market K0 +K0 4 K00LBR33ZE K0F K0L0S @@ -22932,6 +24873,7 @@ K0rnuit K0tleciokas K0veras K0zor +K19 K1ERZ K1LLY K1ddl3 @@ -22941,6 +24883,8 @@ K1ngo K1ngshredder K1r1t0123 K2 Jung +K32 +K38 K3KSE K3U S2 K3azkoks @@ -22948,18 +24892,26 @@ K3fka K3kt K3mi K3nn3d +K44K +K4IF20 K8iee +K99 2 +K9Father K9lenny K9rk +KA97 KABBABEAST KAKAGUATE0 KAKERANDELIN KAL-JML KAMlX KAT alyzt +KB1988 KBARAKAT KBX0 KC Chiefz +KC M0 +KC8 KCRB KChiefn KDOG1419 @@ -22986,6 +24938,7 @@ KGP KGee KGoldy KHADER +KIIIIIIIIIIH KILLER COMBO KILO KIMB0 @@ -24934,6 +26887,58 @@ KyuubiKurama Kywt Kyykin Kzyl +L 0 S T Y +L 3 G 4 C Y +L 67 +L A R A M S +L Ben +L CBO +L D A +L E G E N D +L E G O +L E L O +L E P I +L F C +L FC +L Hus +L I N U X +L I V M +L OAFS +L S Q +L U I G +L U U K E +L X R D S +L achie +L aika +L aka +L ama +L ang +L apras +L atias +L aw Rune +L aze +L e an +L eafErikson +L egs +L ek +L emaster +L ev +L i m a a +L iamm +L iar +L ilo +L inox +L ions +L o w g +L ockdown +L ofty +L osi +L paradoxum +L u m i +L u mi +L u x +L ucas +L unatic L00000 L00M L00OL0OO00OL @@ -25021,6 +27026,8 @@ LIMEWORLD LIQUICITY LITEIT LITHITS +LJ 8 +LJAP LJPalmer LKIT LL Trigger @@ -25049,7 +27056,10 @@ LOSTinGAMES LOUlSlANA LOWIQXD LP Smokie +LRG +LRGD LRichyy +LS1 LS3D LSD-25 LSDDS @@ -27066,6 +29076,81 @@ Lyyli PL Lyzu Lzin Lzs +M A G 3 +M 1 KE +M 3 3 P +M 4 T R I X +M 8 A 1 +M A D O X +M A D Storm +M A T E J +M A X O U T +M A X PAYNE +M B Z +M E H I S +M E L D O +M E T R O +M E X I +M I K B A R +M I T H O X +M I U +M I Z Z O U +M INDGAME +M Itty +M K J +M O B I L 3 +M O C 0 +M O C H +M O ID O K +M R NaCl +M Super Buu +M T C +M U D K l P +M X G P +M a V 3 Rick +M a d Shrumn +M a k a i +M age +M aikel +M ak0 +M ammoth +M ana +M ankDemes +M anu +M aples +M arcel +M arquim +M artin +M ask +M athis +M axou +M azzz +M c +M elz +M enzy +M ga +M gh +M i t c h y +M i y a +M ikasa +M ike +M imik +M int +M itchel +M ittens +M l Q Q +M merz poL9 +M o C e +M o r t e n +M oist +M onkfish +M orytania +M the Maxed +M ugger +M ulas +M urphy 2 +M usashi +M-theory M00CHIE M00SE M00SE M01 @@ -27186,38 +29271,55 @@ MCHammered MCKenny91 MCSIZZLE MCmattt +MD7 +MD96 MDE Presents MDPS +MDaher MDucks MEAT G0D MEAT HEAD36 MEGATRON +MEK4KK4KK4KK MELAN00MA MELT METM0NKEY METR0lD METS0 MEV4NS +MF DC MF MORTEN MF SofaKing MF TEE +MFE MFKU MFLI MFSTEVE +MG5 MGFS MGKRevs MGM WAY MGreengrass MH Therapist +MHA C +MHBC +MHS MIDAs MILFmauler MILSHAKE +MINH MISOGl MISSYGAMlNG MIST MITCHY MIX0R +MJ23 +MJKaboose2 +MJT MK-HARDSTYLE +MK6R +MKAM +MLB MLTEEZY MLaidman MMMahogany @@ -27230,6 +29332,10 @@ MOMHUNTER666 MON5TER MOODSWlNGS MOOSEM3AT +MOTM +MP17 +MP9 +MPB MR JOHN WlCK MR LETHAL2u MR REET @@ -27241,6 +29347,7 @@ MRC Tugboat MRGAMEZ MRHD MRLARGE +MRM MRPlZZAPRIZE MRWHlTE MR_MAITO @@ -27248,12 +29355,18 @@ MSPaint64 MSceneFF MSpacePotato MStarkz +MTBMB +MTPETE +MTV CRlBS +MTXP MUISSS911 MULHERndaEXP MUMM0 MURMELl MUSK MUSK0KA +MUSUMUMM +MUZAMMIL MV Flow MV Welshy MVIII @@ -27262,6 +29375,7 @@ MVP HERO MVP Mahomes MVRDA MVTIASD +MWwarzone MY L U N A MYRSKYVIITTA MYTHICROYXLE @@ -27269,6 +29383,7 @@ M_Sariol Ma Band Ma Dood Ma Titi +Ma t t h e w Ma5onx Ma7e MaCoMb @@ -29555,6 +31670,26 @@ MoetIkLopen Mofaer45 MoffelRS Mofleminator +Mofo Lt +Mofo Shadow +MofoMo92 +Mofoe +Mog Time xD +Mogcow +Moggok +Mogtime +Moh +Mohahm +Mohamedss +Mohanad +Mohannah +Moheed +Mohh +Mohib +Mohlo +Mohnday +Mohphy +Moiqol Moist Moist Dreamz Moist Holy @@ -29567,6 +31702,8 @@ MoistWreck Moistium Mojimot0 Mojito +Mojo Fiki +Mojojojo171 Moju Moju GG Mojurico @@ -30351,6 +32488,7 @@ MrsSocorelis Mrslipkn0t Mrwaffleses Ms Goblin +Ms K Ms Lizziard Ms Trap Ms Zik @@ -30391,6 +32529,47 @@ Muckball Muco Mud Cricket Mud Temple +Mud9 +MudCatBigDog +Mudda Focha +Muddas Main +Muddy patch +Mudguard +Mudkins +Mudkip +Mudmur +Mueezy +MuerteBella +Mues +Mufasa +Mufasa IXI +MufffinKing +Mufficer +MuffinActual +Muffinkyutie +Muffins +Muffinyatta +Mufz +Mugarooni +Mugen +Mugge +Muggerman3 +Muggled +Muggles +Muggtjuven +Mugrub +Mugy +Mugzy +Muhaji +Muhamed +Muhfn +Muhkea +Mui Gokuu +Muilpeer +Muki +Mukkaram7861 +Mukkey +Muktheduck MulasRevenge Mulberry Mtn Muleleaveox @@ -30541,6 +32720,8 @@ Muziek Smurf Muzket Muzz Muzzle +Mv P +MvP ov RnG Mvk Mvko Mvp Scrub @@ -30670,16 +32851,51 @@ Mythrin III Myto Myuf Myuk +Mywa +Myz Myzi Mzaa Mziy +Mzr Mztar +N 10 +N 55 +N A l N E R +N E L L +N E N E N Gallagher +N I GH T96 +N I N O X +N I S H +N ICK Y +N O B S Y +N U B U +N W M +N a t t z +N ang +N anko +N arb +N dejay p +N e a k i le +N e i l +N e0 +N iall +N ibbler +N ightgleam +N l C K O +N l E V E +N o m a d +N occo +N oggin +N u d +N uggies +N-J-R N0 H34RT N0 Invictus N0 pid N00biistyl N00bslayer27 +N04me N0B4Marri4g3 N0Ballz N0ID @@ -30696,12 +32912,26 @@ N0t Maxed N0t special N0tliketh1s N0ul +N1 CK N17 Jake +N1C3 N1NJASK1LLZZ N1ckai N1cwho N1nja N1njaCat +N3XX +N3p +N3se +N3x +N4L +N4ruto +N4styNat3 +N7N +N8vy +N9NE420 +N9T7 +N9U NABEEL RJ NAGAKAMAL NANORA @@ -30710,6 +32940,14 @@ NASDBOY NASSERN NASTY NAVl +NB8K 2K13 +NBA +NBA NewMain +NBA Youngb0i +NC90 +NCG +NCG 2 +NCPS NEBR0SKY NECR0DANCER NEEDAMETHYST @@ -30726,9 +32964,14 @@ NEXFARMER NEYOVIC NFed NHL Blues +NHrn NIIXIIK NINJABLEV1NS NINJATMNT +NITR00 +NJC20 +NJWW +NKJ NL Chronos NL Gilbert NLDeluXe @@ -30752,15 +32995,32 @@ NOTaPancake NOmki NPC Healer NPC Icedrake +NPYJ +NRA +NSFL +NSHN NST Praise NT FiSHvv +NT Y NTBeerBandit NTMR RADIO NUEL NULLI NULLlN KUPPl NUTSHOT +NVQ +NWHL +NWI 219 RAT +NY +NY C +NY G +NY x LEGiiT +NZ Dave +NZL +N_MB N_other_day +Na Mn Or I +NaCl NaCl Sprite NaCl is salt NaQ @@ -30785,6 +33045,15 @@ Nacho Alt Nacho2030 NachoByte NachoDragon +NachoPapi +Nacht +Nachtkastje +NachuiTuda +Nadaa +Nadeo +Nader +Nadsage +Nadund Naethera Naftininkas Naga @@ -30841,12 +33110,26 @@ Namine Silke Namir Nammer Namuko +Nana +Nana Steel +Nanado +Nanciscor Nancyy Nander Nandos Nandos Man NangMan Nangdalorian +Nanimavi +Naniva +Nannertee +Nanno +Nannu Baba +NannyCam69 +Nanoh +Nanoman360 +Nanonymouse +Nanook IV Nanoray Nanotech Nans @@ -30896,6 +33179,38 @@ Naru808 Naruto Narval Narvalow +Narwallus +Narwhal1731 +Narx4 +Nas is like +Nasa +Nasaman +Nascar +Naseeph +Nashh +Nashluffy +Nashonic +Nashy +Naskarsdad +Nasko 07 +Nasper +Nasrullah +Nasseee +Nassim +Nast +Nastacov +Nastie +Nastik +Nasty +Nasty107red7 +NastyAss +NastyCasual +NastyDonger +NastyGarbage +NastyGeUsers +NastyV6 +Nasuuu +Nat Scheetje Natalie Natby Nate @@ -31164,6 +33479,8 @@ Nerf Bowfa Nerf Coffee Nerf Th1s NerfMePlz +NerfTG +Nergegante Nergg Nerio x Nerithma @@ -33368,15 +35685,24 @@ Ozzy Hobbit Ozzykye Ozzys Ozzzyy +P 0 W N E D +P 0 E F +P 0 R G I E +P A M K A +P A P Z +P A R N Y P DIRTY SODA P EDRAO P Eng +P I T P K P O L I S H P O T A T O P O V I P Purts P R O X +P R S +P V M Lew P W A Y P Y R O P a n x o @@ -33438,6 +35764,7 @@ P4sk P5ythix P6D P7DRO +P9 PA N I C PACK WATCH PACKETLOSS @@ -34017,7 +36344,11 @@ Pb and Jd Pbby Pbkillua PbyOne +PdaddyReborn PdfPKerNoGF +PdiddyReborn +Pe en +Pe t er Pe1ipp3r Peabody PeacandLove @@ -35854,6 +38185,12 @@ Pyzdalupi PzK Pzju PzzaPredator +Q 1 +Q K M Nophis +Q Proserpina +Q S L +Q cs +Q l ii Ma X Q of Spade Q uincy Q-Dance Jr @@ -47247,6 +49584,7 @@ USirHaveLost USirHaveWon UTT UWCB +UWF UWUSTELIJA UZY VS JAD Ualt @@ -47259,6 +49597,7 @@ Uber Yeats Uberamazing Ubersmind Ubicorn +Ubu Uccino Uchiwa Uchr @@ -47280,6 +49619,7 @@ Uh-0h Uhbove UhhhBoneless Uhhhh Wut +Uhm Uhscended Uidi One Uim Beyonce @@ -47339,6 +49679,7 @@ Umiland Ummfufu Ummz Un Dutchable +Un M-U-T-3-D Un puma Un-Expected UnDutchable @@ -52165,6 +54506,7 @@ apou appelkneuz applee aqp frog +aqqqqqqqqqqq aquafx araenel13 aratsanus @@ -52173,7 +54515,20 @@ archyiop arcvnaxiii arcwriter ard lad 06 +ardazz ardy guardy +arengs +arevles +arexmeister +arfih +argilah +ari abdul +ari shaffir +ariman22 +arkoudaphile +armadyyyyldo +armyofkids +arnr arocardo arookie arouze @@ -52204,6 +54559,7 @@ asian asianbunnyx asibioass asidb +asm asmoooo ason jones aspiraring1 @@ -52215,6 +54571,9 @@ assbergerler assdrag asseaterbtw assoffire +astgferallah +asuhcuh +at0 atob7 atoma619 attaaM @@ -52223,6 +54582,7 @@ auditore28 audrey audrey horne auma +aus j osh aussieyobbo aut AT5 aut1st1c @@ -52263,6 +54623,22 @@ azilim aziz8mohd azj azura +b a g +b a l r a j +b b o x x +b eeg +b enjy +b ezos +b i g s t +b kuz +b l u rr +b oe +b on ass +b oo n +b ooth +b u l +b ulba +b-ray29 b00ty b00tyw1zard b0btehcool @@ -52574,6 +54950,10 @@ bisse bitten by bitter bitter fruit +bj0rne +bjassen +bjpc +bjuti bkguytd6 bl00d twinz bl00dShaman @@ -52646,10 +55026,23 @@ blutorch blvckstvrr blynaas bman5 +bmeow +bnff bnndt bnqy +bo bby +bo nk bo2Lawrence bo3rke +bo4r +bob bob bob +bobby ross +bobby45153 +bobbyb727 +bobbyitsme +bobbyjoe +bobbytronx +bober vvittu bobfish66 bobness bobondowski @@ -52731,8 +55124,10 @@ boycie420 boydi boydt boyuniverse +boz pwr boze bozo +bp9 br0wnardRS braap poster bradrian @@ -52868,6 +55263,18 @@ byEmilsson byll byrny bzerk +c a b l a y +c bro +c greyson +c h u c kles +c hainz +c j t +c m l +c o 1 a +c onorr +c rompt +c ubic +c xx zz c c-ross93 c00lbeer c0vid @@ -57495,7 +59902,14 @@ mlong06 mmaxie mmigo mmmkay02 +mmmmmmmmhmm +mmmmmmnmmnm +mmmuurrddaaa +mndo mniml +mno +mnt +mo an mobile moer mogwire @@ -57600,6 +60014,13 @@ mstr nay nay mtash96 mthic muchderanged +mucserup +mudbitedlite +mufassa +muffing +muggfac +mugii +muh muh sheen muhName muhnamezjeff @@ -57654,6 +60075,12 @@ myrtlecat mys_try mystic myturngranny +mzsc +n a g a +n k h +n o m i s +n oge +n os n00b tax n00btube n00dIe @@ -57664,7 +60091,14 @@ n0rthmemphis n1ch0las n1ghtmares n3cromans3r +n4ts +n8m +n8n nSubordinate +nVox +nYer +n_koo +na cba naamarihomo naapurintati nabritches @@ -57949,10 +60383,17 @@ nymue nysyGG nzskater o Buffy o +o Galaxy +o Jay o +o NEK o o Pug o o SiLeNce o o Steven o o c c u l t +o chem +o n e i n v +o tp +o tu o0 Rang0r 0o o00dan00o o0Ganktank0o @@ -58215,6 +60656,9 @@ oxyy oysni tu ozos ozztrevor +p hd +p n g +p x v x m p000r p0ge p0tat0_baked @@ -58286,6 +60730,7 @@ pazmar pb tiramisu pbagel pbj eater +pbjt pcce pd3 pdi @@ -58612,6 +61057,9 @@ pzqlpwbma q Aleks q Nossie p q b0nkerz q +q f z +q l l u +q sl q-Mini-p q0k q9q9q @@ -58669,6 +61117,15 @@ qwruqwpourqr qy qz qzxz +r a i n i n +r a i q +r d x +r eflex +r ehab +r i ley +r n g o d +r o c h i +r pt r u a pussy r0adh0g r0jasss @@ -59936,6 +62393,12 @@ syytu szer szeth17 sztuk +t iel +t imbo +t r a m +t rio +t u k e +t ux t-Wrench t-painn t0_valhalla @@ -60194,7 +62657,11 @@ tjd1233 tjomka tksnevrlucky tmahones +tmeer +tmeer 18 +tmjdx tmued +to dd to0Oldf0r1t to_o toad @@ -60262,6 +62729,7 @@ toxiclun toxicsaitama toy Owner tozmic +tq tr0nberg tr0nd tra1nwr3ck13 @@ -60525,6 +62993,12 @@ uz x uzei uzis akimbo uzui +v Simba v +v olksu +v oltage +v tsng +v uka +v yp v-yordan0702 v0i kehveli v0mbat @@ -60698,6 +63172,10 @@ vw vzi vzkg w Danko +w e b r l +w en +w ert +w vy w00_88 w00d pecker w00tgh0st @@ -60852,6 +63330,7 @@ whyamisofat whynotp2p whyuboolyme whyzerkbro +wi f wibeton widefang wiegehtsmir @@ -60896,10 +63375,12 @@ wiw wizard129 wizardyoda7 wizkid499 +wjsn wkurtin wlkerTXrangr wndow wndy +wngo woah wocket wodg @@ -60950,10 +63431,17 @@ wutzgood wutzit wwTakun wweadge2 +www +wwwMusic-Map +wyat wyattearp99 wyked wytch wyverns4days +wzav423 +wzrdddddyo +wzrds +wzs x 0lev x x ABBlE x Argonath x @@ -60994,7 +63482,10 @@ x iyad x x lollage x x mk ultra x preska x +x r x warri0r121 +x zi +x zn x073x x0Mag x0Tub @@ -61103,6 +63594,15 @@ xHugsi xHussla xI3reeze xIron Senpai +xJeb +xJiren +xJlN +xJolt +xJord +xJordd +xJulia +xJuve +xKAJJEx xKadi xKdpunx xKing @@ -61322,6 +63822,7 @@ xtyrantix xvn xvrph xvza +xwl xwuwesxdrf xx darkminer xxDerp @@ -61342,6 +63843,8 @@ xzb xzizzil xzn 2 xzwu +y om +y w y0y0keepitup y37ir y8s1 @@ -61366,6 +63869,10 @@ yapgragim yasuo god69 yayasquirrel ydoc +ye idc +ye ki M +ye p to +yea im jebus yeahboi9992 yeahsmitty yeahyoink @@ -61390,7 +63897,9 @@ ykO Ops ykeL yleisradio ylliB +ym y ymca4life +yna yo eight yo itz ep yobacha @@ -61405,6 +63914,32 @@ yooyeet yorkietootz yorue you died123 +you r a qt +youb1n +youneedcope +young meows +young vibby +youngbriks +youngmachine +youngtrop21 +youngwings +youpougou +your +your thrall +youralterego +youssef +yowasupppbra +yoyoma361 +yp +ypoodle +ypool4 +ypools +yragbackward +yrhs +yribbles +ytsud mi +ytuiop +yugiiii yuh huh yum yummybolete @@ -61425,6 +63960,13 @@ yyknaH J yyttam yyzanadu94 yzyzyzy +z 5 x +z Animal z +z Rhodes +z Shane +z a p s +z iQ +z man827 z0nk z0rrda z0up @@ -61457,6 +63999,10 @@ zSlay zSpaceRaptor zSwanny zTitan +zWxLF +za2 +za33erklan +zaaza zacharial zachhy zachte @@ -61483,6 +64029,7 @@ zazyga zbra zclx zcollins +zdi zdin zdya ze4l @@ -61544,6 +64091,10 @@ zionari zippp zirreael ziurbtw +ziuys +ziyi_wangler +zjh +zjind zlayaa zlink10 zlliM @@ -61573,6 +64124,7 @@ zruG zrzwns ztaM ztkfps +zu b zubor1 zuenzima zujal @@ -61587,6 +64139,8 @@ zummorak zurcc zurlond zuuryy +zw +zwah zwint zwolle zwqpDEOXl23 @@ -61598,6 +64152,9 @@ zykez zymaa zymz zysuna +zzad +zzai zzben zzero -zzigma \ No newline at end of file +zzigma +zzzJonno From e343baeea11887f66654e5f9125e705fd57a0a55 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 9 Jun 2026 19:10:25 +0200 Subject: [PATCH 06/94] Fix Treus Dayth unkillable, thanks shire --- Server/src/main/core/game/node/entity/Entity.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Server/src/main/core/game/node/entity/Entity.java b/Server/src/main/core/game/node/entity/Entity.java index d4d1a8f2b..f9746adbd 100644 --- a/Server/src/main/core/game/node/entity/Entity.java +++ b/Server/src/main/core/game/node/entity/Entity.java @@ -236,6 +236,12 @@ public abstract class Entity extends Node { */ public void clear() { active = false; + if (this instanceof Player) { + location.getChunk().removePlayer(asPlayer()); + } + if (this instanceof NPC) { + location.getChunk().remove(asNpc()); + } pulseManager.clear(); } From d8697b762d1e7d10450a1542d6c482c5a0bc9bed Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 10 Jun 2026 08:58:36 +0200 Subject: [PATCH 07/94] Fix star null ptr --- .../global/activity/shootingstar/ShootingStar.kt | 9 +++++++-- Server/src/main/core/game/node/entity/Entity.java | 14 +++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt b/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt index 6a7b8802a..52cbfd52a 100644 --- a/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt +++ b/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt @@ -63,11 +63,16 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando "Lava Maze mining site" to Location.create(3062, 3885, 0), // Wilderness rune mine "Mage Arena bank" to Location.create(3093, 3962, 0) // Mage Arena bank ) - val starSprite = NPC(8091) var location = "Canifis Bank" + val loc = crash_locations[location] + val starSprite = let { + val npc = NPC(8091) + npc.location = loc + npc + } var maxDust = level.totalStardust var dustLeft = level.totalStardust - var starObject = Scenery(level.objectId, crash_locations.get(location)) + var starObject = Scenery(level.objectId, loc) var isDiscovered = false var ticks = 0 var isSpawned = false diff --git a/Server/src/main/core/game/node/entity/Entity.java b/Server/src/main/core/game/node/entity/Entity.java index f9746adbd..96c74d215 100644 --- a/Server/src/main/core/game/node/entity/Entity.java +++ b/Server/src/main/core/game/node/entity/Entity.java @@ -236,11 +236,15 @@ public abstract class Entity extends Node { */ public void clear() { active = false; - if (this instanceof Player) { - location.getChunk().removePlayer(asPlayer()); - } - if (this instanceof NPC) { - location.getChunk().remove(asNpc()); + if (location == null) { + log(getClass(), Log.ERR, "Null location when clearing Entity " + getId()); + } else { + if (this instanceof Player) { + location.getChunk().removePlayer(asPlayer()); + } + if (this instanceof NPC) { + location.getChunk().remove(asNpc()); + } } pulseManager.clear(); } From dbcc67bd94870a332f62808dc408c195ca7ac118 Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 10 Jun 2026 15:12:57 +0200 Subject: [PATCH 08/94] imports --- Server/src/main/core/game/node/entity/Entity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Server/src/main/core/game/node/entity/Entity.java b/Server/src/main/core/game/node/entity/Entity.java index 96c74d215..80134781a 100644 --- a/Server/src/main/core/game/node/entity/Entity.java +++ b/Server/src/main/core/game/node/entity/Entity.java @@ -17,6 +17,7 @@ import core.game.node.entity.player.link.TeleportManager; import core.game.node.entity.skill.Skills; import core.game.system.task.Pulse; import core.game.world.map.zone.ZoneRestriction; +import core.tools.Log; import org.jetbrains.annotations.NotNull; import core.game.world.GameWorld; import core.game.world.map.Location; @@ -33,6 +34,8 @@ import core.game.system.timer.TimerRegistry; import java.util.*; +import static core.api.ContentAPIKt.log; + /** * An entity is a movable node, such as players and NPCs. * @author Emperor From 1485ee9275b94388767e7b269e228ba413d9f54d Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 10 Jun 2026 15:56:09 +0200 Subject: [PATCH 09/94] No need for logging, thanks ceik --- Server/src/main/core/game/node/entity/Entity.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Server/src/main/core/game/node/entity/Entity.java b/Server/src/main/core/game/node/entity/Entity.java index 80134781a..0203fd3e3 100644 --- a/Server/src/main/core/game/node/entity/Entity.java +++ b/Server/src/main/core/game/node/entity/Entity.java @@ -17,7 +17,6 @@ import core.game.node.entity.player.link.TeleportManager; import core.game.node.entity.skill.Skills; import core.game.system.task.Pulse; import core.game.world.map.zone.ZoneRestriction; -import core.tools.Log; import org.jetbrains.annotations.NotNull; import core.game.world.GameWorld; import core.game.world.map.Location; @@ -34,8 +33,6 @@ import core.game.system.timer.TimerRegistry; import java.util.*; -import static core.api.ContentAPIKt.log; - /** * An entity is a movable node, such as players and NPCs. * @author Emperor @@ -239,9 +236,9 @@ public abstract class Entity extends Node { */ public void clear() { active = false; - if (location == null) { - log(getClass(), Log.ERR, "Null location when clearing Entity " + getId()); - } else { + if (location != null) { + // Location can be null if the Entity never got init()ed, for example if NPC(...) was called only to show a face during dialogues. + // In that situation, the NPC never actually got created so it doesn't need to be removed from any chunk. If it had been, however, we do so now. if (this instanceof Player) { location.getChunk().removePlayer(asPlayer()); } From 0b454ab84a2077ad4f39924932e66b846a58f35a Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 16:59:08 +0200 Subject: [PATCH 10/94] PC barricades wip --- .../minigame/pestcontrol/PCObjectHandler.java | 9 ++++---- .../minigame/pestcontrol/PCPortalNPC.java | 3 ++- .../pestcontrol/PestControlSession.java | 21 +++++++++++-------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java b/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java index 650842a1f..741bbc4df 100644 --- a/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java +++ b/Server/src/main/content/minigame/pestcontrol/PCObjectHandler.java @@ -140,7 +140,7 @@ public final class PCObjectHandler extends OptionHandler { handleTurretTower(player, session, object); return true; } - if (!object.isActive() || (getObjectType(object.getId()) == 9 && !session.getBarricades().contains(object))) { + if (!object.isActive() || !session.getBarricades().contains(object)) { return true; } if (option.equals("repair")) { // Handle barricades @@ -229,15 +229,16 @@ public final class PCObjectHandler extends OptionHandler { int dir = open ? object.getRotation() : rotation; Direction direction = Direction.get(!open ? dir : ((3 + dir) % 4)); if (session.getBarricades().contains(object) && session.getBarricades().contains(second)) { + session.getBarricades().remove(object); + session.getBarricades().remove(second); + Location l = object.getLocation().transform(direction.getStepX(), direction.getStepY(), 0); Scenery replacement = new Scenery(object.getId() + (open ? 1 : -1), l, 0, open ? rotation : ((direction.toInteger() + 3) % 4)); - session.getBarricades().remove(object); SceneryBuilder.replace(object, replacement); session.getBarricades().add(replacement); l = second.getLocation().transform(direction.getStepX(), direction.getStepY(), 0); replacement = new Scenery(second.getId() + (open ? 1 : -1), l, 0, open ? getRotation(second) : ((direction.toInteger() + 3) % 4)); - session.getBarricades().remove(second); SceneryBuilder.replace(second, replacement); session.getBarricades().add(replacement); } @@ -294,7 +295,7 @@ public final class PCObjectHandler extends OptionHandler { * @param objectId The object id. * @return The object type. */ - static int getObjectType(int objectId) { + private static int getObjectType(int objectId) { if (objectId == 14225 || objectId == 14226 || objectId == 14228 || objectId == 14229) { return 9; } diff --git a/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java b/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java index b28fa05c2..bf41dc764 100644 --- a/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java +++ b/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java @@ -184,7 +184,8 @@ public final class PCPortalNPC extends AbstractNPC { int index = getDifficultyIndex(); Random r = RandomFunction.RANDOM; int amount = index + 1; - amount += RegionManager.getLocalPlayers(location).size() / 10; + Region region = RegionManager.forId(location.getRegionId()); + amount += region.assemblePlayerList(0).size() / 10; if (getDifficultyIndex() == 0) { amount += ((getDifficultyIndex() + 1) * 3) / 2; } diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java index f24197b85..3d8591916 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java @@ -8,6 +8,7 @@ import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.node.scenery.Scenery; import core.game.world.map.Location; +import core.game.world.map.Point; import core.game.world.map.build.DynamicRegion; import core.tools.RandomFunction; @@ -19,6 +20,12 @@ import static core.api.ContentAPIKt.*; * @author Emperor */ public final class PestControlSession { + + /** + * The barricade object offsets. + */ + private static final Point[] OBJECT_OFFSETS = { new Point(46, 33), new Point(46, 32), new Point(32, 25), new Point(33, 25), new Point(19, 32), new Point(19, 33), new Point(49, 33), new Point(49, 32), new Point(49, 31), new Point(49, 30), new Point(52, 27), new Point(52, 26), new Point(52, 25), new Point(52, 24), new Point(52, 14), new Point(52, 13), new Point(52, 12), new Point(52, 11), new Point(42, 18), new Point(43, 18), new Point(44, 18), new Point(45, 18), new Point(32, 15), new Point(33, 15), new Point(34, 15), new Point(35, 15), new Point(23, 18), new Point(24, 18), new Point(25, 18), new Point(26, 18), new Point(13, 11), new Point(13, 12), new Point(13, 13), new Point(13, 14), new Point(12, 28), new Point(12, 29), new Point(12, 30), new Point(12, 31), }; + /** * The object ids of non-attackable barricades/gates. */ @@ -263,15 +270,11 @@ public final class PestControlSession { * Initializes the barricades list. */ private void initBarricadesList() { - for (int chunkX = 0; chunkX < 8; chunkX++) { - for (int chunkY = 0; chunkY < 8; chunkY++) { - List objects = region.getChunks()[chunkX][chunkY][0].assembleObjectList(); - for (Scenery object : objects) { - boolean isActualBarricade = PCObjectHandler.getObjectType(object.getId()) == 9; - boolean isGate = object.getId() > 14232; - if (isActualBarricade || isGate) { - barricades.add(object); - } + List objectList = region.assembleObjectList(0); + for (Scenery object : objectList) { + for (Point point : OBJECT_OFFSETS) { + if (object.getLocation().getLocalX() == point.getX() && object.getLocation().getLocalY() == point.getY()) { + barricades.add(object); } } } From 08b5e4cb8eaede9c33adba79cf31be9146ddecc7 Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 18:15:12 +0200 Subject: [PATCH 11/94] Fix broken multicombat in pest control --- Server/src/main/core/game/node/entity/npc/NPC.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index fe04c19e1..59629bdde 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -1,5 +1,6 @@ package core.game.node.entity.npc; +import core.ServerConstants; import core.game.event.NPCKillEvent; import core.cache.def.impl.NPCDefinition; import core.game.dialogue.DialoguePlugin; @@ -213,6 +214,7 @@ public class NPC extends Entity { getProperties().setSpawnLocation(getLocation()); initConfig(); Repository.getNpcs().add(this); + RegionManager.move(this, ServerConstants.START_LOCATION, this.location); getLocation().getChunk().add(this); if (getLocation().getRegion().isActive()) { Repository.addRenderableNPC(this); From b0445b87503a656a00095e642121150eb7cc213c Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 19:50:05 +0200 Subject: [PATCH 12/94] Restore incorrect spaces to tabs to facilitate review --- .../item/withitem/SoftclayPlugin.java | 218 +- .../agility/brimhaven/BrimhavenArena.java | 552 +-- .../crafting/spinning/SpinningPulse.java | 160 +- .../woodcutting/WoodcuttingSkillPulse.java | 418 +-- .../quest/witchshouse/NoraTHaggNPC.java | 208 +- .../witchshouse/WitchsExperimentNPC.java | 268 +- .../thetouristrap/TouristTrapPlugin.java | 3298 ++++++++--------- .../seers/handlers/RangingGuildPlugin.java | 2326 ++++++------ Server/src/main/core/game/bots/PvMBots.java | 216 +- .../core/game/interaction/MovementPulse.java | 340 +- .../player/info/login/LoginConfiguration.java | 494 +-- 11 files changed, 4249 insertions(+), 4249 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java index fc63daa34..bf445c470 100644 --- a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java +++ b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java @@ -21,127 +21,127 @@ import java.util.Objects; @Initializable public final class SoftclayPlugin extends UseWithHandler { - /** - * Represents the clay item. - */ - private static final Item CLAY = new Item(Items.CLAY_434); + /** + * Represents the clay item. + */ + private static final Item CLAY = new Item(Items.CLAY_434); - /** - * Represents the soft clay item. - */ - private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); + /** + * Represents the soft clay item. + */ + private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); - /** - * Represents the bowl of water item. - */ - private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); + /** + * Represents the bowl of water item. + */ + private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); - /** - * Represents the empty bowl item. - */ - private static final Item BOWL = new Item(Items.BOWL_1923); + /** + * Represents the empty bowl item. + */ + private static final Item BOWL = new Item(Items.BOWL_1923); - /** - * Represents the empty bucket item. - */ - private static final Item BUCKET = new Item(Items.BUCKET_1925); + /** + * Represents the empty bucket item. + */ + private static final Item BUCKET = new Item(Items.BUCKET_1925); - /** - * Represents the bucket of water item. - */ - private static final Item BUCKET_OF_WATER = new Item(Items.BUCKET_OF_WATER_1929); + /** + * Represents the bucket of water item. + */ + private static final Item BUCKET_OF_WATER = new Item(Items.BUCKET_OF_WATER_1929); - /** - * Represents the jug item. - */ - private static final Item JUG = new Item(Items.JUG_1935); + /** + * Represents the jug item. + */ + private static final Item JUG = new Item(Items.JUG_1935); - /** - * Represents the jug of water item. - */ - private static final Item JUG_OF_WATER = new Item(Items.JUG_OF_WATER_1937); + /** + * Represents the jug of water item. + */ + private static final Item JUG_OF_WATER = new Item(Items.JUG_OF_WATER_1937); - /** - * Constructs a new {@code SoftclayPlugin} {@code Object}. - */ - public SoftclayPlugin() { - super(434); - } + /** + * Constructs a new {@code SoftclayPlugin} {@code Object}. + */ + public SoftclayPlugin() { + super(434); + } - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(1921, ITEM_TYPE, this); - addHandler(1929, ITEM_TYPE, this); - addHandler(1937, ITEM_TYPE, this); - return this; - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + addHandler(1921, ITEM_TYPE, this); + addHandler(1929, ITEM_TYPE, this); + addHandler(1937, ITEM_TYPE, this); + return this; + } - @Override - public boolean handle(final NodeUsageEvent event) { - final Player player = event.getPlayer(); - SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, SOFT_CLAY) { - @Override - public void create(final int amount, int index) { - player.getPulseManager().run(new Pulse(2, player) { - int count; + @Override + public boolean handle(final NodeUsageEvent event) { + final Player player = event.getPlayer(); + SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, SOFT_CLAY) { + @Override + public void create(final int amount, int index) { + player.getPulseManager().run(new Pulse(2, player) { + int count; - @Override - public boolean pulse() { - if (!SoftclayPlugin.this.create(player, event)) { - return true; - } - return ++count >= amount; - } - }); - } + @Override + public boolean pulse() { + if (!SoftclayPlugin.this.create(player, event)) { + return true; + } + return ++count >= amount; + } + }); + } - @Override - public int getAll(int index) { - return player.getInventory().getAmount(CLAY); - } - }; - if (player.getInventory().getAmount(CLAY) == 1) { - create(player, event); - } else { - handler.open(); - } - return true; - } + @Override + public int getAll(int index) { + return player.getInventory().getAmount(CLAY); + } + }; + if (player.getInventory().getAmount(CLAY) == 1) { + create(player, event); + } else { + handler.open(); + } + return true; + } - /** - * Creates a soft clay. - * @param player the player. - * @param event the event. - * @return {@code True} if so. - */ - private boolean create(final Player player, NodeUsageEvent event) { - Item removeItem = null; - Item returnItem = null; - if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { - removeItem = BUCKET_OF_WATER; - returnItem = BUCKET; - } - if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { - removeItem = BOWL_OF_WATER; - returnItem = BOWL; - } - if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { - removeItem = JUG_OF_WATER; - returnItem = JUG; - } + /** + * Creates a soft clay. + * @param player the player. + * @param event the event. + * @return {@code True} if so. + */ + private boolean create(final Player player, NodeUsageEvent event) { + Item removeItem = null; + Item returnItem = null; + if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { + removeItem = BUCKET_OF_WATER; + returnItem = BUCKET; + } + if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { + removeItem = BOWL_OF_WATER; + returnItem = BOWL; + } + if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { + removeItem = JUG_OF_WATER; + returnItem = JUG; + } - if (player.getInventory().containsItem(CLAY) && player.getInventory().containsItem(Objects.requireNonNull(removeItem))) { - player.getInventory().remove(removeItem); - player.getInventory().remove(CLAY); - player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); - player.getInventory().add(SOFT_CLAY); - player.getInventory().add(returnItem); - if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { - player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); - } - return true; - } else { - return false; - } - } + if (player.getInventory().containsItem(CLAY) && player.getInventory().containsItem(Objects.requireNonNull(removeItem))) { + player.getInventory().remove(removeItem); + player.getInventory().remove(CLAY); + player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); + player.getInventory().add(SOFT_CLAY); + player.getInventory().add(returnItem); + if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { + player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); + } + return true; + } else { + return false; + } + } } diff --git a/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java b/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java index c046d73f7..e70f39fa8 100644 --- a/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java +++ b/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java @@ -38,302 +38,302 @@ import static core.api.ContentAPIKt.*; @Initializable public final class BrimhavenArena extends MapZone implements Plugin { - /** - * The location based traps. - */ - private static final Map LOCATION_TRAPS = new HashMap<>(); + /** + * The location based traps. + */ + private static final Map LOCATION_TRAPS = new HashMap<>(); - /** - * The overlay component. - */ - private static final Component OVERLAY = new Component(5); + /** + * The overlay component. + */ + private static final Component OVERLAY = new Component(5); - /** - * The ticket dispenser locations. - */ - private static final Location[] DISPENSERS = new Location[24]; + /** + * The ticket dispenser locations. + */ + private static final Location[] DISPENSERS = new Location[24]; - /** - * The agility ticket reward item. - */ - private static final Item TICKET = new Item(2996); + /** + * The agility ticket reward item. + */ + private static final Item TICKET = new Item(2996); - /** - * If the saw blade is currently active. - */ - public static boolean sawBladeActive; + /** + * If the saw blade is currently active. + */ + public static boolean sawBladeActive; - /** - * Constructs a new {@code BrimhavenArena} {@code Object}. - */ - public BrimhavenArena() { - super("Brimhaven agility arena", true); - } + /** + * Constructs a new {@code BrimhavenArena} {@code Object}. + */ + public BrimhavenArena() { + super("Brimhaven agility arena", true); + } - /** - * Sets the current ticket dispenser target. - * - * @param player The player. - */ - private void setDispenser(Player player) { - if (!player.getAttribute("brim-tagged", false)) { - player.setAttribute("brim-tagcount", 0); - } - player.setAttribute("brim-tagged", false); - setVarp(player, 309, 0); - int index = RandomFunction.randomize(DISPENSERS.length); - if (index == player.getAttribute("brim-tag", -1)) { - index = (index + 1) % DISPENSERS.length; - } - int iconSlot = player.getAttribute("brim-icon", -1); - if (iconSlot > -1) { - HintIconManager.removeHintIcon(player, iconSlot); - } - player.setAttribute("brim-tag", index); - player.setAttribute("brim-icon", HintIconManager.registerHeightHintIcon(player, DISPENSERS[index], 50)); - } + /** + * Sets the current ticket dispenser target. + * + * @param player The player. + */ + private void setDispenser(Player player) { + if (!player.getAttribute("brim-tagged", false)) { + player.setAttribute("brim-tagcount", 0); + } + player.setAttribute("brim-tagged", false); + setVarp(player, 309, 0); + int index = RandomFunction.randomize(DISPENSERS.length); + if (index == player.getAttribute("brim-tag", -1)) { + index = (index + 1) % DISPENSERS.length; + } + int iconSlot = player.getAttribute("brim-icon", -1); + if (iconSlot > -1) { + HintIconManager.removeHintIcon(player, iconSlot); + } + player.setAttribute("brim-tag", index); + player.setAttribute("brim-icon", HintIconManager.registerHeightHintIcon(player, DISPENSERS[index], 50)); + } - @Override - public boolean enter(Entity entity) { - if (entity instanceof Player) { - Player player = (Player) entity; - player.getInterfaceManager().openOverlay(OVERLAY); - setDispenser(player); - } - return super.enter(entity); - } + @Override + public boolean enter(Entity entity) { + if (entity instanceof Player) { + Player player = (Player) entity; + player.getInterfaceManager().openOverlay(OVERLAY); + setDispenser(player); + } + return super.enter(entity); + } - @Override - public boolean leave(Entity entity, boolean logout) { - if (entity instanceof Player && !logout) { - Player player = (Player) entity; - player.getInterfaceManager().closeOverlay(); - player.removeAttribute("brim-tag"); - player.removeAttribute("brim-tagcount"); - int iconSlot = player.getAttribute("brim-icon", -1); - if (iconSlot > -1) { - HintIconManager.removeHintIcon(player, iconSlot); - player.removeAttribute("brim-icon"); - } - } - return super.enter(entity); - } + @Override + public boolean leave(Entity entity, boolean logout) { + if (entity instanceof Player && !logout) { + Player player = (Player) entity; + player.getInterfaceManager().closeOverlay(); + player.removeAttribute("brim-tag"); + player.removeAttribute("brim-tagcount"); + int iconSlot = player.getAttribute("brim-icon", -1); + if (iconSlot > -1) { + HintIconManager.removeHintIcon(player, iconSlot); + player.removeAttribute("brim-icon"); + } + } + return super.enter(entity); + } - @Override - public boolean interact(Entity entity, Node node, Option option) { - if (node instanceof Scenery) { - Scenery object = (Scenery) node; - if (object.getId() == 3610) { - ClimbActionHandler.climb((Player) entity, Animation.create(828), object.getLocation().transform(0, 0, 3)); - return true; - } - if (object.getId() == 3608 || object.getId() == 3581) { - Player player = (Player) entity; - if (!object.getLocation().equals(DISPENSERS[player.getAttribute("brim-tag", 0)])) { - player.getPacketDispatch().sendMessage("Tag the pillar indicated by the yellow arrow to get an Agility ticket."); - return true; - } - if (player.getAttribute("brim-tagged", false)) { - player.getPacketDispatch().sendMessage("You have already tagged this pillar."); - return true; - } - player.setAttribute("brim-tagged", true); - int tags = player.getAttribute("brim-tagcount", 0) + 1; - player.setAttribute("brim-tagcount", tags); - setVarp(player, 309, 4); - if (tags > 1) { - int amount = 1; - if (!player.getInventory().add(new Item(TICKET.getId(), amount))) { - GroundItemManager.create(new GroundItem(new Item(TICKET.getId(), amount), player.getLocation(), player)); - } - player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 0); - player.getDialogueInterpreter().sendItemMessage(TICKET.getId(), "You have received an Agility Arena Ticket!"); - player.getPacketDispatch().sendMessage("You have received an Agility Arena Ticket!"); - return true; - } - player.getPacketDispatch().sendMessage("You get tickets by tagging more than one pillar in a row, tag the next pillar!"); - player.getDialogueInterpreter().sendDialogue("You get tickets by tagging more than one pillar in a row. Tag the", "next pillar for a ticket!"); - return true; - } - } - return false; - } + @Override + public boolean interact(Entity entity, Node node, Option option) { + if (node instanceof Scenery) { + Scenery object = (Scenery) node; + if (object.getId() == 3610) { + ClimbActionHandler.climb((Player) entity, Animation.create(828), object.getLocation().transform(0, 0, 3)); + return true; + } + if (object.getId() == 3608 || object.getId() == 3581) { + Player player = (Player) entity; + if (!object.getLocation().equals(DISPENSERS[player.getAttribute("brim-tag", 0)])) { + player.getPacketDispatch().sendMessage("Tag the pillar indicated by the yellow arrow to get an Agility ticket."); + return true; + } + if (player.getAttribute("brim-tagged", false)) { + player.getPacketDispatch().sendMessage("You have already tagged this pillar."); + return true; + } + player.setAttribute("brim-tagged", true); + int tags = player.getAttribute("brim-tagcount", 0) + 1; + player.setAttribute("brim-tagcount", tags); + setVarp(player, 309, 4); + if (tags > 1) { + int amount = 1; + if (!player.getInventory().add(new Item(TICKET.getId(), amount))) { + GroundItemManager.create(new GroundItem(new Item(TICKET.getId(), amount), player.getLocation(), player)); + } + player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 0); + player.getDialogueInterpreter().sendItemMessage(TICKET.getId(), "You have received an Agility Arena Ticket!"); + player.getPacketDispatch().sendMessage("You have received an Agility Arena Ticket!"); + return true; + } + player.getPacketDispatch().sendMessage("You get tickets by tagging more than one pillar in a row, tag the next pillar!"); + player.getDialogueInterpreter().sendDialogue("You get tickets by tagging more than one pillar in a row. Tag the", "next pillar for a ticket!"); + return true; + } + } + return false; + } - @Override - public boolean move(Entity e, Location loc, Location dest) { - if (!e.getLocks().isMovementLocked() && e instanceof Player) { - MovementHook hook = LOCATION_TRAPS.get(loc); - if (hook != null) { - e.setDirection(Direction.getLogicalDirection(loc, dest)); - return hook.handle(e, loc); - } - } - return super.move(e, loc, dest); - } + @Override + public boolean move(Entity e, Location loc, Location dest) { + if (!e.getLocks().isMovementLocked() && e instanceof Player) { + MovementHook hook = LOCATION_TRAPS.get(loc); + if (hook != null) { + e.setDirection(Direction.getLogicalDirection(loc, dest)); + return hook.handle(e, loc); + } + } + return super.move(e, loc, dest); + } - @Override - public void locationUpdate(Entity e, Location last) { - if (!e.getLocks().isMovementLocked() && e instanceof Player) { - MovementHook hook = LOCATION_TRAPS.get(e.getLocation()); - if (hook != null) { - if (!hook.handle(e, e.getLocation())) { - if (e.getPulseManager().isMovingPulse()) { - e.getPulseManager().clear(); - } - e.getWalkingQueue().reset(); - } - } - } - } + @Override + public void locationUpdate(Entity e, Location last) { + if (!e.getLocks().isMovementLocked() && e instanceof Player) { + MovementHook hook = LOCATION_TRAPS.get(e.getLocation()); + if (hook != null) { + if (!hook.handle(e, e.getLocation())) { + if (e.getPulseManager().isMovingPulse()) { + e.getPulseManager().clear(); + } + e.getWalkingQueue().reset(); + } + } + } + } - @Override - public void configure() { - registerRegion(11157); - PressurePad pad = new PressurePad(); - LOCATION_TRAPS.put(Location.create(2800, 9579, 3), pad); - LOCATION_TRAPS.put(Location.create(2799, 9579, 3), pad); - LOCATION_TRAPS.put(Location.create(2800, 9557, 3), pad); - LOCATION_TRAPS.put(Location.create(2799, 9557, 3), pad); - LOCATION_TRAPS.put(Location.create(2772, 9585, 3), pad); - LOCATION_TRAPS.put(Location.create(2772, 9584, 3), pad); - FloorSpikes spikes = new FloorSpikes(); - LOCATION_TRAPS.put(Location.create(2800, 9568, 3), spikes); - LOCATION_TRAPS.put(Location.create(2799, 9568, 3), spikes); - LOCATION_TRAPS.put(Location.create(2772, 9552, 3), spikes); - LOCATION_TRAPS.put(Location.create(2772, 9551, 3), spikes); - LOCATION_TRAPS.put(Location.create(2761, 9573, 3), spikes); - LOCATION_TRAPS.put(Location.create(2761, 9574, 3), spikes); - DartTrap dart = new DartTrap(); - LOCATION_TRAPS.put(Location.create(2788, 9557, 3), dart); - LOCATION_TRAPS.put(Location.create(2789, 9557, 3), dart); - LOCATION_TRAPS.put(Location.create(2794, 9573, 3), dart); - LOCATION_TRAPS.put(Location.create(2794, 9574, 3), dart); - LOCATION_TRAPS.put(Location.create(2777, 9568, 3), dart); - LOCATION_TRAPS.put(Location.create(2778, 9568, 3), dart); - SpinningBlades blade = new SpinningBlades(); - LOCATION_TRAPS.put(Location.create(2778, 9579, 3), blade); - LOCATION_TRAPS.put(Location.create(2783, 9574, 3), blade); - LOCATION_TRAPS.put(Location.create(2778, 9557, 3), blade); - BladeTrap trap = new BladeTrap(); - LOCATION_TRAPS.put(Location.create(2788, 9579, 3), trap); - LOCATION_TRAPS.put(Location.create(2789, 9579, 3), trap); - LOCATION_TRAPS.put(Location.create(2783, 9551, 3), trap); - LOCATION_TRAPS.put(Location.create(2783, 9552, 3), trap); - LOCATION_TRAPS.put(Location.create(2761, 9584, 3), trap); - LOCATION_TRAPS.put(Location.create(2761, 9585, 3), trap); - int index = 0; - for (int x = 2761; x < 2815; x += 11) { - for (int y = 9546; y < 9600; y += 11) { - if (x == 2805 && y == 9590) { - continue; - } - DISPENSERS[index++] = Location.create(x, y, 3); - } - } - GameWorld.getPulser().submit(new Pulse(1) { - @Override - public boolean pulse() { - Region r = RegionManager.forId(11157); - if (!r.isActive()) { - return false; - } - if (GameWorld.getTicks() % 100 == 0) { - for (int z = 0; z < 4; z++) { - for (Player player : r.assemblePlayerList(z)) { - if (player != null) { - setDispenser(player); - } - } - } - handlePlankSwitching(); - } - int ticks = 3; - if (GameWorld.getTicks() % ticks == 0) { - sawBladeActive = !sawBladeActive; - if (sawBladeActive) { - Scenery object = RegionManager.getObject(3, 2788, 9579); - SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2789, 9579); - SceneryBuilder.replace(object, object.transform(0), ticks); + @Override + public void configure() { + registerRegion(11157); + PressurePad pad = new PressurePad(); + LOCATION_TRAPS.put(Location.create(2800, 9579, 3), pad); + LOCATION_TRAPS.put(Location.create(2799, 9579, 3), pad); + LOCATION_TRAPS.put(Location.create(2800, 9557, 3), pad); + LOCATION_TRAPS.put(Location.create(2799, 9557, 3), pad); + LOCATION_TRAPS.put(Location.create(2772, 9585, 3), pad); + LOCATION_TRAPS.put(Location.create(2772, 9584, 3), pad); + FloorSpikes spikes = new FloorSpikes(); + LOCATION_TRAPS.put(Location.create(2800, 9568, 3), spikes); + LOCATION_TRAPS.put(Location.create(2799, 9568, 3), spikes); + LOCATION_TRAPS.put(Location.create(2772, 9552, 3), spikes); + LOCATION_TRAPS.put(Location.create(2772, 9551, 3), spikes); + LOCATION_TRAPS.put(Location.create(2761, 9573, 3), spikes); + LOCATION_TRAPS.put(Location.create(2761, 9574, 3), spikes); + DartTrap dart = new DartTrap(); + LOCATION_TRAPS.put(Location.create(2788, 9557, 3), dart); + LOCATION_TRAPS.put(Location.create(2789, 9557, 3), dart); + LOCATION_TRAPS.put(Location.create(2794, 9573, 3), dart); + LOCATION_TRAPS.put(Location.create(2794, 9574, 3), dart); + LOCATION_TRAPS.put(Location.create(2777, 9568, 3), dart); + LOCATION_TRAPS.put(Location.create(2778, 9568, 3), dart); + SpinningBlades blade = new SpinningBlades(); + LOCATION_TRAPS.put(Location.create(2778, 9579, 3), blade); + LOCATION_TRAPS.put(Location.create(2783, 9574, 3), blade); + LOCATION_TRAPS.put(Location.create(2778, 9557, 3), blade); + BladeTrap trap = new BladeTrap(); + LOCATION_TRAPS.put(Location.create(2788, 9579, 3), trap); + LOCATION_TRAPS.put(Location.create(2789, 9579, 3), trap); + LOCATION_TRAPS.put(Location.create(2783, 9551, 3), trap); + LOCATION_TRAPS.put(Location.create(2783, 9552, 3), trap); + LOCATION_TRAPS.put(Location.create(2761, 9584, 3), trap); + LOCATION_TRAPS.put(Location.create(2761, 9585, 3), trap); + int index = 0; + for (int x = 2761; x < 2815; x += 11) { + for (int y = 9546; y < 9600; y += 11) { + if (x == 2805 && y == 9590) { + continue; + } + DISPENSERS[index++] = Location.create(x, y, 3); + } + } + GameWorld.getPulser().submit(new Pulse(1) { + @Override + public boolean pulse() { + Region r = RegionManager.forId(11157); + if (!r.isActive()) { + return false; + } + if (GameWorld.getTicks() % 100 == 0) { + for (int z = 0; z < 4; z++) { + for (Player player : r.assemblePlayerList(z)) { + if (player != null) { + setDispenser(player); + } + } + } + handlePlankSwitching(); + } + int ticks = 3; + if (GameWorld.getTicks() % ticks == 0) { + sawBladeActive = !sawBladeActive; + if (sawBladeActive) { + Scenery object = RegionManager.getObject(3, 2788, 9579); + SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); + object = RegionManager.getObject(3, 2789, 9579); + SceneryBuilder.replace(object, object.transform(0), ticks); - object = RegionManager.getObject(3, 2783, 9551); - SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2783, 9552); - SceneryBuilder.replace(object, object.transform(0), ticks); + object = RegionManager.getObject(3, 2783, 9551); + SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); + object = RegionManager.getObject(3, 2783, 9552); + SceneryBuilder.replace(object, object.transform(0), ticks); - object = RegionManager.getObject(3, 2761, 9584); - SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2761, 9585); - SceneryBuilder.replace(object, object.transform(0), ticks); - } - } - return false; - } - }); - } + object = RegionManager.getObject(3, 2761, 9584); + SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); + object = RegionManager.getObject(3, 2761, 9585); + SceneryBuilder.replace(object, object.transform(0), ticks); + } + } + return false; + } + }); + } - /** - * Switches the plank states. - */ - private static void handlePlankSwitching() { - boolean[] available = new boolean[3]; - for (int i = 0; i < 1 + RandomFunction.randomize(2); i++) { - available[RandomFunction.randomize(3)] = true; - } - for (int i = 0; i < 3; i++) { - boolean avail = available[i]; - for (PlankSet set : PlankSet.values()) { - Location l = set.entrance[i]; - for (int x = 1; x < set.exit[i].getX() - l.getX(); x++) { - Scenery object = RegionManager.getObject(l.transform(x, 0, 0)); - if(object != null) - SceneryBuilder.replace(object, object.transform(avail ? 3573 : 3576)); - } - RegionManager.getObject(set.entrance[i]).setCharge(avail ? 1000 : 500); - RegionManager.getObject(set.exit[i]).setCharge(avail ? 1000 : 500); - } - } - } + /** + * Switches the plank states. + */ + private static void handlePlankSwitching() { + boolean[] available = new boolean[3]; + for (int i = 0; i < 1 + RandomFunction.randomize(2); i++) { + available[RandomFunction.randomize(3)] = true; + } + for (int i = 0; i < 3; i++) { + boolean avail = available[i]; + for (PlankSet set : PlankSet.values()) { + Location l = set.entrance[i]; + for (int x = 1; x < set.exit[i].getX() - l.getX(); x++) { + Scenery object = RegionManager.getObject(l.transform(x, 0, 0)); + if(object != null) + SceneryBuilder.replace(object, object.transform(avail ? 3573 : 3576)); + } + RegionManager.getObject(set.entrance[i]).setCharge(avail ? 1000 : 500); + RegionManager.getObject(set.exit[i]).setCharge(avail ? 1000 : 500); + } + } + } - /** - * The plank obstacles. - * - * @author Emperor - */ - private static enum PlankSet { - FIRST(new Location[]{Location.create(2797, 9591, 3), Location.create(2797, 9590, 3), Location.create(2797, 9589, 3)}, new Location[]{Location.create(2802, 9591, 3), Location.create(2802, 9590, 3), Location.create(2802, 9589, 3)}), SECOND(new Location[]{Location.create(2764, 9558, 3), Location.create(2764, 9557, 3), Location.create(2764, 9556, 3)}, new Location[]{Location.create(2769, 9558, 3), Location.create(2769, 9557, 3), Location.create(2769, 9556, 3)}); + /** + * The plank obstacles. + * + * @author Emperor + */ + private static enum PlankSet { + FIRST(new Location[]{Location.create(2797, 9591, 3), Location.create(2797, 9590, 3), Location.create(2797, 9589, 3)}, new Location[]{Location.create(2802, 9591, 3), Location.create(2802, 9590, 3), Location.create(2802, 9589, 3)}), SECOND(new Location[]{Location.create(2764, 9558, 3), Location.create(2764, 9557, 3), Location.create(2764, 9556, 3)}, new Location[]{Location.create(2769, 9558, 3), Location.create(2769, 9557, 3), Location.create(2769, 9556, 3)}); - /** - * Constructs a new {@code PlankSet} {@code Object}. - * - * @param entrance The entrance locations for each plank. - * @param exit The exit locations for each plank. - */ - private PlankSet(Location[] entrance, Location[] exit) { - this.entrance = entrance; - this.exit = exit; - } + /** + * Constructs a new {@code PlankSet} {@code Object}. + * + * @param entrance The entrance locations for each plank. + * @param exit The exit locations for each plank. + */ + private PlankSet(Location[] entrance, Location[] exit) { + this.entrance = entrance; + this.exit = exit; + } - /** - * The entrance location of the plank. - */ - Location[] entrance; + /** + * The entrance location of the plank. + */ + Location[] entrance; - /** - * The exit location of the plank. - */ - Location[] exit; - } + /** + * The exit location of the plank. + */ + Location[] exit; + } - @Override - public Plugin newInstance(Object arg) throws Throwable { - ZoneBuilder.configure(this); - return this; - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + ZoneBuilder.configure(this); + return this; + } - @Override - public Object fireEvent(String identifier, Object... args) { - return null; - } + @Override + public Object fireEvent(String identifier, Object... args) { + return null; + } } diff --git a/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java b/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java index b7efeae3a..87e0ce531 100644 --- a/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java +++ b/Server/src/main/content/global/skill/crafting/spinning/SpinningPulse.java @@ -20,94 +20,94 @@ import static core.api.ContentAPIKt.playAudio; */ public final class SpinningPulse extends SkillPulse { - /** - * Represents the animation to use. - */ - private static final Animation ANIMATION = new Animation(896); + /** + * Represents the animation to use. + */ + private static final Animation ANIMATION = new Animation(896); - /** - * Represents the type of spinning item. - */ - private final SpinningItem type; + /** + * Represents the type of spinning item. + */ + private final SpinningItem type; - /** - * Represents the amount to spin. - */ - private int ammount; + /** + * Represents the amount to spin. + */ + private int ammount; - /** - * Represents the ticks passed. - */ - private int ticks; + /** + * Represents the ticks passed. + */ + private int ticks; - /** - * Constructs a new {@code SpinningPulse.java} {@Code Object} - * - * @param player - * @param node - */ - public SpinningPulse(Player player, Item node, int ammount, SpinningItem def) { - super(player, node); - this.type = def; - this.ammount = ammount; - } + /** + * Constructs a new {@code SpinningPulse.java} {@Code Object} + * + * @param player + * @param node + */ + public SpinningPulse(Player player, Item node, int ammount, SpinningItem def) { + super(player, node); + this.type = def; + this.ammount = ammount; + } - @Override - public boolean checkRequirements() { - player.getInterfaceManager().close(); - if (player.getSkills().getLevel(Skills.CRAFTING) < type.getLevel()) { - player.getPacketDispatch().sendMessage("You need a crafting level of " + type.getLevel() + " to make this."); - return false; - } - if (!player.getInventory().contains(type.getNeed(), 1)) { - player.getPacketDispatch().sendMessage("You need " + ItemDefinition.forId(type.getNeed()).getName() + " to do this."); - return false; - } - return true; - } + @Override + public boolean checkRequirements() { + player.getInterfaceManager().close(); + if (player.getSkills().getLevel(Skills.CRAFTING) < type.getLevel()) { + player.getPacketDispatch().sendMessage("You need a crafting level of " + type.getLevel() + " to make this."); + return false; + } + if (!player.getInventory().contains(type.getNeed(), 1)) { + player.getPacketDispatch().sendMessage("You need " + ItemDefinition.forId(type.getNeed()).getName() + " to do this."); + return false; + } + return true; + } - @Override - public void animate() { - if (ticks % 5 == 0) { - player.animate(ANIMATION); - playAudio(player, Sounds.SPINNING_2590); - } - } + @Override + public void animate() { + if (ticks % 5 == 0) { + player.animate(ANIMATION); + playAudio(player, Sounds.SPINNING_2590); + } + } - @Override - public boolean reward() { - int tickThreshhold = 4; - if (player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(2) - && player.getLocation().withinDistance(Location.create(2711,3471,1)) - && player.getEquipment().get(EquipmentContainer.SLOT_HAT) != null - && player.getEquipment().get(EquipmentContainer.SLOT_HAT).getId() == 14631) { - tickThreshhold = 2; - } - if (++ticks % tickThreshhold != 0) { - return false; - } - if (player.getInventory().remove(new Item(type.getNeed(), 1))) { - final Item item = new Item(type.getProduct(), 1); - player.getInventory().add(item); - player.getSkills().addExperience(Skills.CRAFTING, type.getExp(), true); + @Override + public boolean reward() { + int tickThreshhold = 4; + if (player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(2) + && player.getLocation().withinDistance(Location.create(2711,3471,1)) + && player.getEquipment().get(EquipmentContainer.SLOT_HAT) != null + && player.getEquipment().get(EquipmentContainer.SLOT_HAT).getId() == 14631) { + tickThreshhold = 2; + } + if (++ticks % tickThreshhold != 0) { + return false; + } + if (player.getInventory().remove(new Item(type.getNeed(), 1))) { + final Item item = new Item(type.getProduct(), 1); + player.getInventory().add(item); + player.getSkills().addExperience(Skills.CRAFTING, type.getExp(), true); - // Seers achievement diary - if (player.getLocation().getRegionId() == 10806 - && !player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(0, 4)) { - if (player.getAttribute("diary:seers:bowstrings-spun", 0) >= 4) { - player.setAttribute("/save:diary:seers:bowstrings-spun", 5); - player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 0, 4); - } else { - player.setAttribute("/save:diary:seers:bowstrings-spun", player.getAttribute("diary:seers:bowstrings-spun", 0) + 1); - } - } - } - ammount--; - return ammount < 1; - } + // Seers achievement diary + if (player.getLocation().getRegionId() == 10806 + && !player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(0, 4)) { + if (player.getAttribute("diary:seers:bowstrings-spun", 0) >= 4) { + player.setAttribute("/save:diary:seers:bowstrings-spun", 5); + player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 0, 4); + } else { + player.setAttribute("/save:diary:seers:bowstrings-spun", player.getAttribute("diary:seers:bowstrings-spun", 0) + 1); + } + } + } + ammount--; + return ammount < 1; + } - @Override - public void message(int type) { - } + @Override + public void message(int type) { + } } diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java index cf0a4557a..465912ee5 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java @@ -39,244 +39,244 @@ import static core.game.system.command.sets.StatAttributeKeysKt.STATS_LOGS; * @author ceik */ public class WoodcuttingSkillPulse extends Pulse { - private int[] woodcuttingSounds = { - Sounds.WOODCUTTING_HIT_3038, - Sounds.WOODCUTTING_HIT_3039, - Sounds.WOODCUTTING_HIT_3040, - Sounds.WOODCUTTING_HIT_3041, - Sounds.WOODCUTTING_HIT_3042 - }; + private int[] woodcuttingSounds = { + Sounds.WOODCUTTING_HIT_3038, + Sounds.WOODCUTTING_HIT_3039, + Sounds.WOODCUTTING_HIT_3040, + Sounds.WOODCUTTING_HIT_3041, + Sounds.WOODCUTTING_HIT_3042 + }; - private WoodcuttingNode resource; - private int ticks; - private Player player; - private Scenery node; - protected boolean resetAnimation = true; + private WoodcuttingNode resource; + private int ticks; + private Player player; + private Scenery node; + protected boolean resetAnimation = true; - public WoodcuttingSkillPulse(Player player, Scenery node) { - super(1, player, node); - this.player = player; - this.node = node; - super.stop(); - } + public WoodcuttingSkillPulse(Player player, Scenery node) { + super(1, player, node); + this.player = player; + this.node = node; + super.stop(); + } - public void message(int type) { - if (type == 0) { - player.getPacketDispatch().sendMessage("You swing your axe at the tree..."); - } - } + public void message(int type) { + if (type == 0) { + player.getPacketDispatch().sendMessage("You swing your axe at the tree..."); + } + } - @Override - public boolean pulse() { - if (!checkRequirements()) { - return true; - } - animate(); - return reward(); - } + @Override + public boolean pulse() { + if (!checkRequirements()) { + return true; + } + animate(); + return reward(); + } - @Override - public void stop() { - if (resetAnimation) { - player.animate(new Animation(-1, Animator.Priority.HIGH)); - } - super.stop(); - message(1); - } + @Override + public void stop() { + if (resetAnimation) { + player.animate(new Animation(-1, Animator.Priority.HIGH)); + } + super.stop(); + message(1); + } - @Override - public void start() { - resource = WoodcuttingNode.forId(node.getId()); - if (resource == null) { - return; - } - if (checkRequirements()) { - super.start(); - message(0); - } - } + @Override + public void start() { + resource = WoodcuttingNode.forId(node.getId()); + if (resource == null) { + return; + } + if (checkRequirements()) { + super.start(); + message(0); + } + } - public boolean checkRequirements() { - if (player.getSkills().getLevel(Skills.WOODCUTTING) < resource.getLevel()) { - player.getPacketDispatch().sendMessage("You need a woodcutting level of " + resource.getLevel() + " to chop this tree."); - return false; - } - if (SkillingTool.getHatchet(player) == null) { - player.getPacketDispatch().sendMessage("You do not have an axe to use."); - return false; - } - if (player.getInventory().freeSlots() < 1) { - player.getDialogueInterpreter().sendDialogue("Your inventory is too full to hold any more " + ItemDefinition.forId(resource.getReward()).getName().toLowerCase() + "."); - return false; - } - return true; - } + public boolean checkRequirements() { + if (player.getSkills().getLevel(Skills.WOODCUTTING) < resource.getLevel()) { + player.getPacketDispatch().sendMessage("You need a woodcutting level of " + resource.getLevel() + " to chop this tree."); + return false; + } + if (SkillingTool.getHatchet(player) == null) { + player.getPacketDispatch().sendMessage("You do not have an axe to use."); + return false; + } + if (player.getInventory().freeSlots() < 1) { + player.getDialogueInterpreter().sendDialogue("Your inventory is too full to hold any more " + ItemDefinition.forId(resource.getReward()).getName().toLowerCase() + "."); + return false; + } + return true; + } - public void animate() { - if (!player.getAnimator().isAnimating()) { - player.animate(SkillingTool.getHatchet(player).getAnimation()); - for (Player p : RegionManager.getLocalPlayers(player.getLocation(), 2)) { - if (p.getName() == player.getName()) { - continue; - } - int soundIndex = RandomFunction.random(0, woodcuttingSounds.length); - playAudio(p, woodcuttingSounds[soundIndex]); - } - } - } + public void animate() { + if (!player.getAnimator().isAnimating()) { + player.animate(SkillingTool.getHatchet(player).getAnimation()); + for (Player p : RegionManager.getLocalPlayers(player.getLocation(), 2)) { + if (p.getName() == player.getName()) { + continue; + } + int soundIndex = RandomFunction.random(0, woodcuttingSounds.length); + playAudio(p, woodcuttingSounds[soundIndex]); + } + } + } - public boolean reward() { - if (++ticks % 4 != 0) { - return false; - } - if (node.getId() == 10041) { - player.getDialogueInterpreter().sendDialogues(2574, FacialExpression.FURIOUS, RandomFunction.random(2) == 1 ? "You'll blow my cover! I'm meant to be hidden!" : "Will you stop that?"); - return true; - } - if (!checkReward(SkillingTool.getHatchet(player))) { - return false; - } + public boolean reward() { + if (++ticks % 4 != 0) { + return false; + } + if (node.getId() == 10041) { + player.getDialogueInterpreter().sendDialogues(2574, FacialExpression.FURIOUS, RandomFunction.random(2) == 1 ? "You'll blow my cover! I'm meant to be hidden!" : "Will you stop that?"); + return true; + } + if (!checkReward(SkillingTool.getHatchet(player))) { + return false; + } - // 20% chance to auto burn logs when using "inferno adze" item - if (SkillingTool.getHatchet(player).getId() == 13661 && RandomFunction.random(100) < 25) { - player.sendMessage("You chop some logs. The heat of the inferno adze incinerates them."); - Projectile.create(player, null, 1776, 35, 30, 20, 25).transform(player, new Location(player.getLocation().getX() + 2, player.getLocation().getY()), true, 25, 25).send(); - player.getSkills().addExperience(Skills.WOODCUTTING, resource.getExperience()); - player.getSkills().addExperience(Skills.FIREMAKING, resource.getExperience()); - return rollDepletion(); - } + // 20% chance to auto burn logs when using "inferno adze" item + if (SkillingTool.getHatchet(player).getId() == 13661 && RandomFunction.random(100) < 25) { + player.sendMessage("You chop some logs. The heat of the inferno adze incinerates them."); + Projectile.create(player, null, 1776, 35, 30, 20, 25).transform(player, new Location(player.getLocation().getX() + 2, player.getLocation().getY()), true, 25, 25).send(); + player.getSkills().addExperience(Skills.WOODCUTTING, resource.getExperience()); + player.getSkills().addExperience(Skills.FIREMAKING, resource.getExperience()); + return rollDepletion(); + } - //actual reward calculations - int reward = resource.getReward(); - int rewardAmount = 0; - if (reward > 0) { - reward = calculateReward(reward); // calculate rewards - rewardAmount = calculateRewardAmount(reward); // calculate amount + //actual reward calculations + int reward = resource.getReward(); + int rewardAmount = 0; + if (reward > 0) { + reward = calculateReward(reward); // calculate rewards + rewardAmount = calculateRewardAmount(reward); // calculate amount - //add experience - double experience = calculateExperience(resource.reward, rewardAmount); + //add experience + double experience = calculateExperience(resource.reward, rewardAmount); - player.getSkills().addExperience(Skills.WOODCUTTING, experience, true); + player.getSkills().addExperience(Skills.WOODCUTTING, experience, true); - //send the message for the resource reward - player.getPacketDispatch().sendMessage("You get some " + ItemDefinition.forId(reward).getName().toLowerCase() + "."); - //give the reward - player.getInventory().add(new Item(reward, rewardAmount)); - player.dispatch(new ResourceProducedEvent(reward, rewardAmount, node, -1)); - int cutLogs = player.getAttribute(STATS_BASE + ":" + STATS_LOGS,0); - player.setAttribute("/save:" + STATS_BASE + ":" + STATS_LOGS,++cutLogs); + //send the message for the resource reward + player.getPacketDispatch().sendMessage("You get some " + ItemDefinition.forId(reward).getName().toLowerCase() + "."); + //give the reward + player.getInventory().add(new Item(reward, rewardAmount)); + player.dispatch(new ResourceProducedEvent(reward, rewardAmount, node, -1)); + int cutLogs = player.getAttribute(STATS_BASE + ":" + STATS_LOGS,0); + player.setAttribute("/save:" + STATS_BASE + ":" + STATS_LOGS,++cutLogs); - //calculate bonus bird nest for mining - int chance = 282; - if (RandomFunction.random(chance) == chance / 2) { - if(SkillcapePerks.isActive(SkillcapePerks.NEST_HUNTER,player)){ - if(!player.getInventory().add(BirdNest.getRandomNest(false).getNest())){ - BirdNest.drop(player); - } - } else { - BirdNest.drop(player); - } - } + //calculate bonus bird nest for mining + int chance = 282; + if (RandomFunction.random(chance) == chance / 2) { + if(SkillcapePerks.isActive(SkillcapePerks.NEST_HUNTER,player)){ + if(!player.getInventory().add(BirdNest.getRandomNest(false).getNest())){ + BirdNest.drop(player); + } + } else { + BirdNest.drop(player); + } + } - } + } - return rollDepletion(); - } + return rollDepletion(); + } - private boolean rollDepletion() { - //transform to depleted version - //OSRS and RS3 Wikis both agree: All trees present in 2009 are a 1/8 fell chance, aside from normal trees/dead trees which are 100% - //OSRS: https://oldschool.runescape.wiki/w/Woodcutting scroll down to the mechanics section - //RS3 : https://runescape.wiki/w/Woodcutting scroll down to the mechanics section, and expand the tree felling chances table - if (resource.getRespawnRate() > 0) { - if (RandomFunction.roll(8) || resource.identifier == 1 || resource.identifier == 2 || resource.identifier == 3 || resource.identifier == 6) { - if (resource.isFarming()) { - FarmingPatch fPatch = FarmingPatch.forObject(node.asScenery()); - if(fPatch != null) { - Patch patch = fPatch.getPatchFor(player, true); - patch.setCurrentState(patch.getCurrentState() + 1); - } - return true; - } - if (resource.getEmptyId() > -1) { - SceneryBuilder.replace(node, node.transform(resource.getEmptyId()), resource.getRespawnDuration()); - } else { - SceneryBuilder.replace(node, node.transform(0), resource.getRespawnDuration()); - } - node.setActive(false); + private boolean rollDepletion() { + //transform to depleted version + //OSRS and RS3 Wikis both agree: All trees present in 2009 are a 1/8 fell chance, aside from normal trees/dead trees which are 100% + //OSRS: https://oldschool.runescape.wiki/w/Woodcutting scroll down to the mechanics section + //RS3 : https://runescape.wiki/w/Woodcutting scroll down to the mechanics section, and expand the tree felling chances table + if (resource.getRespawnRate() > 0) { + if (RandomFunction.roll(8) || resource.identifier == 1 || resource.identifier == 2 || resource.identifier == 3 || resource.identifier == 6) { + if (resource.isFarming()) { + FarmingPatch fPatch = FarmingPatch.forObject(node.asScenery()); + if(fPatch != null) { + Patch patch = fPatch.getPatchFor(player, true); + patch.setCurrentState(patch.getCurrentState() + 1); + } + return true; + } + if (resource.getEmptyId() > -1) { + SceneryBuilder.replace(node, node.transform(resource.getEmptyId()), resource.getRespawnDuration()); + } else { + SceneryBuilder.replace(node, node.transform(0), resource.getRespawnDuration()); + } + node.setActive(false); - playAudio(player, Sounds.TREE_FALLING_2734); - return true; - } - } - return false; - } + playAudio(player, Sounds.TREE_FALLING_2734); + return true; + } + } + return false; + } - private int calculateRewardAmount(int reward) { - int amount = 1; + private int calculateRewardAmount(int reward) { + int amount = 1; - // 3239: Hollow tree (bark) 10% chance of obtaining - if (reward == 3239 && RandomFunction.random(100) >= 10) { - amount = 0; - } + // 3239: Hollow tree (bark) 10% chance of obtaining + if (reward == 3239 && RandomFunction.random(100) >= 10) { + amount = 0; + } - // Seers village medium reward - extra normal log while in seer's village - if (reward == 1511 - && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) - && player.getLocation().getRegionId() == 10806) { - amount = 2; - } + // Seers village medium reward - extra normal log while in seer's village + if (reward == 1511 + && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) + && player.getLocation().getRegionId() == 10806) { + amount = 2; + } - return amount; - } + return amount; + } - private double calculateExperience(int reward, int amount) { - double experience = resource.getExperience(); + private double calculateExperience(int reward, int amount) { + double experience = resource.getExperience(); - if(player.getLocation().getRegionId() == 10300){ - return 1.0; - } + if(player.getLocation().getRegionId() == 10300){ + return 1.0; + } - // Bark - if (reward == 3239) { - // If we receive the item, give the full experience points otherwise give the base amount - if (amount >= 1) { - experience = 275.2; - } else { - amount = 1; - } - } + // Bark + if (reward == 3239) { + // If we receive the item, give the full experience points otherwise give the base amount + if (amount >= 1) { + experience = 275.2; + } else { + amount = 1; + } + } - // Seers village medium reward - extra 10% xp from maples while wearing headband - if (reward == 1517 - && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) - && player.getEquipment().get(EquipmentContainer.SLOT_HAT) != null - && player.getEquipment().get(EquipmentContainer.SLOT_HAT).getId() == 14631) { - experience *= 1.10; - } + // Seers village medium reward - extra 10% xp from maples while wearing headband + if (reward == 1517 + && player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1) + && player.getEquipment().get(EquipmentContainer.SLOT_HAT) != null + && player.getEquipment().get(EquipmentContainer.SLOT_HAT).getId() == 14631) { + experience *= 1.10; + } - return experience * amount; - } + return experience * amount; + } - private int calculateReward(int reward) { - return reward; - } + private int calculateReward(int reward) { + return reward; + } - /** - * Checks if the player gets rewarded. - * - * @return {@code True} if so. - */ - private boolean checkReward(SkillingTool tool) { - int skill = Skills.WOODCUTTING; - int level = player.getSkills().getLevel(skill) + player.getFamiliarManager().getBoost(skill); - double hostRatio = RandomFunction.randomDouble(100.0); - double lowMod = tool == SkillingTool.BLACK_AXE ? resource.tierModLow / 2 : resource.tierModLow; - double low = resource.baseLow + (tool.ordinal() * lowMod); - double highMod = tool == SkillingTool.BLACK_AXE ? resource.tierModHigh / 2 : resource.tierModHigh; - double high = resource.baseHigh + (tool.ordinal() * highMod); - double clientRatio = RandomFunction.getSkillSuccessChance(low,high,level); - return hostRatio < clientRatio; - } + /** + * Checks if the player gets rewarded. + * + * @return {@code True} if so. + */ + private boolean checkReward(SkillingTool tool) { + int skill = Skills.WOODCUTTING; + int level = player.getSkills().getLevel(skill) + player.getFamiliarManager().getBoost(skill); + double hostRatio = RandomFunction.randomDouble(100.0); + double lowMod = tool == SkillingTool.BLACK_AXE ? resource.tierModLow / 2 : resource.tierModLow; + double low = resource.baseLow + (tool.ordinal() * lowMod); + double highMod = tool == SkillingTool.BLACK_AXE ? resource.tierModHigh / 2 : resource.tierModHigh; + double high = resource.baseHigh + (tool.ordinal() * highMod); + double clientRatio = RandomFunction.getSkillSuccessChance(low,high,level); + return hostRatio < clientRatio; + } } diff --git a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java index 30d12d34a..7cb1070e7 100644 --- a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java +++ b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java @@ -30,122 +30,122 @@ import java.util.List; @Initializable public class NoraTHaggNPC extends AbstractNPC { - boolean walkdir; + boolean walkdir; - public NoraTHaggNPC() { - super(896, Location.create(2904, 3463, 0)); - } - private Location getRespawnLocation() { - return Location.create(2900, 3473, 0); - } + public NoraTHaggNPC() { + super(896, Location.create(2904, 3463, 0)); + } + private Location getRespawnLocation() { + return Location.create(2900, 3473, 0); + } - private NoraTHaggNPC(int id, Location location) { - super(id, location); - } + private NoraTHaggNPC(int id, Location location) { + super(id, location); + } - @Override - public Plugin newInstance(Object arg) throws Throwable { - this.configure(); - init(); - return super.newInstance(arg); - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + this.configure(); + init(); + return super.newInstance(arg); + } - private boolean canTeleport(Entity t) { - int playerX = t.getLocation().getX(); - int npcX = getLocation().getX(); - int[] sectors = { 2904, 2907, 2910, 2914, 2918, 2922, 2926, 2928 }; - for (int i = 0; i < sectors.length -1; i++) { - if (npcX >= sectors[i] && npcX <= sectors[i+1] && playerX >= sectors[i] && playerX <= sectors[i+1]) { - if (playerX < npcX && getDirection() == Direction.WEST || playerX > npcX && getDirection() == Direction.EAST) { - return true; - } - if (playerX == npcX) { - return true; - } - } - } - return false; - } + private boolean canTeleport(Entity t) { + int playerX = t.getLocation().getX(); + int npcX = getLocation().getX(); + int[] sectors = { 2904, 2907, 2910, 2914, 2918, 2922, 2926, 2928 }; + for (int i = 0; i < sectors.length -1; i++) { + if (npcX >= sectors[i] && npcX <= sectors[i+1] && playerX >= sectors[i] && playerX <= sectors[i+1]) { + if (playerX < npcX && getDirection() == Direction.WEST || playerX > npcX && getDirection() == Direction.EAST) { + return true; + } + if (playerX == npcX) { + return true; + } + } + } + return false; + } - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new NoraTHaggNPC(id, location); - } + @Override + public AbstractNPC construct(int id, Location location, Object... objects) { + return new NoraTHaggNPC(id, location); + } - @Override - public int[] getIds() { - return new int[] { 896 }; - } + @Override + public int[] getIds() { + return new int[] { 896 }; + } - @Override - public int getWalkRadius() { - return 50; - } + @Override + public int getWalkRadius() { + return 50; + } - public void configure() { - super.configure(); - setWalks(false); - setPathBoundMovement(true); - } + public void configure() { + super.configure(); + setWalks(false); + setPathBoundMovement(true); + } - private void sendTeleport(final Player player) { - player.lock(); - GameWorld.getPulser().submit(new Pulse(1) { - int delay = 0; + private void sendTeleport(final Player player) { + player.lock(); + GameWorld.getPulser().submit(new Pulse(1) { + int delay = 0; - @Override - public boolean pulse() { - if (delay == 0) { - face(player); - player.getInventory().remove(WitchsHousePlugin.BALL); - player.getInventory().remove(WitchsHousePlugin.KEY); - player.getInventory().remove(WitchsHousePlugin.DOOR_KEY); - sendChat("Stop! Thief!"); - player.getPacketDispatch().sendMessage("You've been spotted by the witch."); - player.graphics(new Graphics(110, 100)); - PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2)); - } else if (delay == 2) { - sendChat("Klarata... Seppteno... Valkan!"); - face(null); - } else if (delay == 4) { - player.getProperties().setTeleportLocation(Location.create(getRespawnLocation())); - PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0)); - face(null); - player.unlock(); - return true; - } - delay++; - return false; - } - }); - } + @Override + public boolean pulse() { + if (delay == 0) { + face(player); + player.getInventory().remove(WitchsHousePlugin.BALL); + player.getInventory().remove(WitchsHousePlugin.KEY); + player.getInventory().remove(WitchsHousePlugin.DOOR_KEY); + sendChat("Stop! Thief!"); + player.getPacketDispatch().sendMessage("You've been spotted by the witch."); + player.graphics(new Graphics(110, 100)); + PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2)); + } else if (delay == 2) { + sendChat("Klarata... Seppteno... Valkan!"); + face(null); + } else if (delay == 4) { + player.getProperties().setTeleportLocation(Location.create(getRespawnLocation())); + PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0)); + face(null); + player.unlock(); + return true; + } + delay++; + return false; + } + }); + } - @Override - public void tick() { - super.tick(); - List players = RegionManager.getLocalPlayers(location); - if(getLocation().getX() == 2930){ - walkdir = false; - } else if(getLocation().getX() == 2904){ - walkdir = true; - } - for (Player player : players) { - if (player == null || !player.isActive() || player.getLocks().isInteractionLocked() || DeathTask.isDead(player) || !canTeleport(player) || !CombatSwingHandler.isProjectileClipped(this, player, false)) { - continue; - } - animate(new Animation(5803)); - sendTeleport(player); - player.getPacketDispatch().sendMessage("" + getLocation() + " matches? " + (getLocation().getX() == 2904)); - } - if (location.getX() != 2930 && walkdir) { - this.getWalkingQueue().reset(); - this.getWalkingQueue().addPath(location.getX() + 1,3463,true); - } else if (location.getX() != 2904 && !walkdir) { - this.getWalkingQueue().reset(); - this.getWalkingQueue().addPath(location.getX() - 1,3463,true); - } - } + @Override + public void tick() { + super.tick(); + List players = RegionManager.getLocalPlayers(location); + if(getLocation().getX() == 2930){ + walkdir = false; + } else if(getLocation().getX() == 2904){ + walkdir = true; + } + for (Player player : players) { + if (player == null || !player.isActive() || player.getLocks().isInteractionLocked() || DeathTask.isDead(player) || !canTeleport(player) || !CombatSwingHandler.isProjectileClipped(this, player, false)) { + continue; + } + animate(new Animation(5803)); + sendTeleport(player); + player.getPacketDispatch().sendMessage("" + getLocation() + " matches? " + (getLocation().getX() == 2904)); + } + if (location.getX() != 2930 && walkdir) { + this.getWalkingQueue().reset(); + this.getWalkingQueue().addPath(location.getX() + 1,3463,true); + } else if (location.getX() != 2904 && !walkdir) { + this.getWalkingQueue().reset(); + this.getWalkingQueue().addPath(location.getX() - 1,3463,true); + } + } } diff --git a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java index 8a99ad831..08eb59dee 100644 --- a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java +++ b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/WitchsExperimentNPC.java @@ -19,165 +19,165 @@ import core.plugin.Initializable; @Initializable public class WitchsExperimentNPC extends AbstractNPC { - private ExperimentType type; - private boolean commenced; - Player p; + private ExperimentType type; + private boolean commenced; + Player p; - public WitchsExperimentNPC() { - super(0, null); - } + public WitchsExperimentNPC() { + super(0, null); + } - WitchsExperimentNPC(int id, Location location, Player player) { - super(id, location); - this.setWalks(true); - this.setRespawn(false); - this.type = WitchsExperimentNPC.ExperimentType.forId(id); - p = player; - } + WitchsExperimentNPC(int id, Location location, Player player) { + super(id, location); + this.setWalks(true); + this.setRespawn(false); + this.type = WitchsExperimentNPC.ExperimentType.forId(id); + p = player; + } - @Override - public void handleTickActions() { - super.handleTickActions(); - if (!p.isActive() || !RegionManager.getLocalPlayers(location).contains(p)) { - p.removeAttribute("witchs-experiment:npc_spawned"); - clear(); - } - if (!getProperties().getCombatPulse().isAttacking()) { - getProperties().getCombatPulse().attack(p); - } - } + @Override + public void handleTickActions() { + super.handleTickActions(); + if (!p.isActive() || !RegionManager.getLocalPlayers(location).contains(p)) { + p.removeAttribute("witchs-experiment:npc_spawned"); + clear(); + } + if (!getProperties().getCombatPulse().isAttacking()) { + getProperties().getCombatPulse().attack(p); + } + } - @Override - public void startDeath(Entity killer) { - if (killer == p) { - type.transform(this, p); - return; - } - super.startDeath(killer); - } + @Override + public void startDeath(Entity killer) { + if (killer == p) { + type.transform(this, p); + return; + } + super.startDeath(killer); + } - @Override - public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { - return p == entity; - } + @Override + public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { + return p == entity; + } - @Override - public boolean canSelectTarget(Entity target) { - if (target instanceof Player) { - Player p = (Player) target; - return p == this.p; - } - return true; - } + @Override + public boolean canSelectTarget(Entity target) { + if (target instanceof Player) { + Player p = (Player) target; + return p == this.p; + } + return true; + } - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new WitchsExperimentNPC(id, location, null); - } + @Override + public AbstractNPC construct(int id, Location location, Object... objects) { + return new WitchsExperimentNPC(id, location, null); + } - @Override - public int[] getIds() { - return new int[] { 897, 898, 899, 900 }; - } + @Override + public int[] getIds() { + return new int[] { 897, 898, 899, 900 }; + } - public void setType(ExperimentType type) { - this.type = type; - } + public void setType(ExperimentType type) { + this.type = type; + } - public ExperimentType getType() { - return type; - } + public ExperimentType getType() { + return type; + } - public void setCommenced(boolean commenced) { - this.commenced = commenced; - } + public void setCommenced(boolean commenced) { + this.commenced = commenced; + } - public enum ExperimentType { - FIRST(897, ""), - SECOND(898, "The shapeshifter's body begins to deform!", "The shapeshifter turns into a spider!"), - THIRD(899, "The shapeshifter's body begins to twist!", "The shapeshifter turns into a bear!"), - FOURTH(900, "The shapeshifter's body pulses!", "The shapeshifter turns into a wolf!"), - END(-1, ""), + public enum ExperimentType { + FIRST(897, ""), + SECOND(898, "The shapeshifter's body begins to deform!", "The shapeshifter turns into a spider!"), + THIRD(899, "The shapeshifter's body begins to twist!", "The shapeshifter turns into a bear!"), + FOURTH(900, "The shapeshifter's body pulses!", "The shapeshifter turns into a wolf!"), + END(-1, ""), - ; + ; - private int id; - private String[] message; + private int id; + private String[] message; - ExperimentType(int id, String... message) { - this.id = id; - this.message = message; - } + ExperimentType(int id, String... message) { + this.id = id; + this.message = message; + } - /** - * Transforms the new npc. - */ - public void transform(final WitchsExperimentNPC npc, final Player player) { - final ExperimentType newType = next(); - npc.lock(); - npc.getPulseManager().clear(); - npc.getWalkingQueue().reset(); - player.setAttribute("/save:witchs_house:experiment_id",this.id); - GameWorld.getPulser().submit(new Pulse(1, npc, player) { - int counter; + /** + * Transforms the new npc. + */ + public void transform(final WitchsExperimentNPC npc, final Player player) { + final ExperimentType newType = next(); + npc.lock(); + npc.getPulseManager().clear(); + npc.getWalkingQueue().reset(); + player.setAttribute("/save:witchs_house:experiment_id",this.id); + GameWorld.getPulser().submit(new Pulse(1, npc, player) { + int counter; - @Override - public boolean pulse() { - switch (++counter) { + @Override + public boolean pulse() { + switch (++counter) { - case 1: - npc.unlock(); - npc.getAnimator().reset(); - npc.fullRestore(); - npc.setType(newType); - npc.transform(newType.getId()); - npc.getImpactHandler().setDisabledTicks(1); - if (newType != END) { - npc.getProperties().getCombatPulse().attack(player); - } - if (newType.getMessage() != null && newType != END) { - player.sendMessage(newType.getMessage()[0]); - player.sendMessage(newType.getMessage()[1]); - } - if (newType == END) { - player.setAttribute("witchs_house:experiment_killed",true); - npc.clear(); - return false; - } - player.unlock(); - return true; - } - return false; - } + case 1: + npc.unlock(); + npc.getAnimator().reset(); + npc.fullRestore(); + npc.setType(newType); + npc.transform(newType.getId()); + npc.getImpactHandler().setDisabledTicks(1); + if (newType != END) { + npc.getProperties().getCombatPulse().attack(player); + } + if (newType.getMessage() != null && newType != END) { + player.sendMessage(newType.getMessage()[0]); + player.sendMessage(newType.getMessage()[1]); + } + if (newType == END) { + player.setAttribute("witchs_house:experiment_killed",true); + npc.clear(); + return false; + } + player.unlock(); + return true; + } + return false; + } - }); - } + }); + } - public static ExperimentType forId(int id) { - for (ExperimentType type : values()) { - if (type.getId() == id) { - return type; - } - } - return null; - } + public static ExperimentType forId(int id) { + for (ExperimentType type : values()) { + if (type.getId() == id) { + return type; + } + } + return null; + } - private static ExperimentType[] experimentTypes = values(); + private static ExperimentType[] experimentTypes = values(); - public ExperimentType next() - { - return experimentTypes[this.ordinal() + 1]; - } + public ExperimentType next() + { + return experimentTypes[this.ordinal() + 1]; + } - public int getId() { - return id; - } + public int getId() { + return id; + } - public String[] getMessage() { - return message; - } + public String[] getMessage() { + return message; + } - } + } } diff --git a/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java b/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java index e486577e7..0f0f4a2af 100644 --- a/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java +++ b/Server/src/main/content/region/desert/quest/thetouristrap/TouristTrapPlugin.java @@ -49,1653 +49,1653 @@ import static core.api.ContentAPIKt.*; */ public final class TouristTrapPlugin extends OptionHandler { - @Override - public Plugin newInstance(Object arg) throws Throwable { - SceneryDefinition.forId(2673).getHandlers().put("option:open", this); - SceneryDefinition.forId(2674).getHandlers().put("option:open", this); - SceneryDefinition.forId(2673).getHandlers().put("option:search", this); - SceneryDefinition.forId(2674).getHandlers().put("option:search", this); - SceneryDefinition.forId(2688).getHandlers().put("option:open", this); - SceneryDefinition.forId(2688).getHandlers().put("option:search", this); - SceneryDefinition.forId(2687).getHandlers().put("option:open", this); - SceneryDefinition.forId(2687).getHandlers().put("option:search", this); - SceneryDefinition.forId(2685).getHandlers().put("option:open", this); - SceneryDefinition.forId(2685).getHandlers().put("option:open", this); - SceneryDefinition.forId(2686).getHandlers().put("option:search", this); - SceneryDefinition.forId(2686).getHandlers().put("option:search", this); - SceneryDefinition.forId(18958).getHandlers().put("option:search", this); - SceneryDefinition.forId(18958).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18959).getHandlers().put("option:search", this); - SceneryDefinition.forId(18959).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18888).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18888).getHandlers().put("option:operate", this); - SceneryDefinition.forId(36748).getHandlers().put("option:talk-to", this); - SceneryDefinition.forId(18869).getHandlers().put("option:bend", this); - SceneryDefinition.forId(18870).getHandlers().put("option:escape", this); - SceneryDefinition.forId(2689).getHandlers().put("option:open", this); - SceneryDefinition.forId(1528).getHandlers().put("option:open", this); - SceneryDefinition.forId(1529).getHandlers().put("option:close", this); - SceneryDefinition.forId(18899).getHandlers().put("option:search", this); - SceneryDefinition.forId(18899).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18878).getHandlers().put("option:search", this); - SceneryDefinition.forId(18878).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18879).getHandlers().put("option:search", this); - SceneryDefinition.forId(18879).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18898).getHandlers().put("option:search", this); - SceneryDefinition.forId(18898).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18902).getHandlers().put("option:search", this); - SceneryDefinition.forId(18871).getHandlers().put("option:climb", this); - SceneryDefinition.forId(18923).getHandlers().put("option:climb-up", this); - SceneryDefinition.forId(18924).getHandlers().put("option:climb-down", this); - SceneryDefinition.forId(2676).getHandlers().put("option:open", this); - SceneryDefinition.forId(2675).getHandlers().put("option:open", this); - SceneryDefinition.forId(2676).getHandlers().put("option:watch", this); - SceneryDefinition.forId(2675).getHandlers().put("option:watch", this); - SceneryDefinition.forId(2690).getHandlers().put("option:open", this); - SceneryDefinition.forId(2691).getHandlers().put("option:open", this); - SceneryDefinition.forId(2698).getHandlers().put("option:walk through", this); - SceneryDefinition.forId(2699).getHandlers().put("option:walk through", this); - SceneryDefinition.forId(2677).getHandlers().put("option:open", this); - SceneryDefinition.forId(2678).getHandlers().put("option:search", this); - SceneryDefinition.forId(2684).getHandlers().put("option:search", this); - SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); - SceneryDefinition.forId(2680).getHandlers().put("option:search", this); - SceneryDefinition.forId(2680).getHandlers().put("option:look-in", this); - SceneryDefinition.forId(2681).getHandlers().put("option:search", this); - SceneryDefinition.forId(2681).getHandlers().put("option:look in", this); - SceneryDefinition.forId(18962).getHandlers().put("option:search", this); - SceneryDefinition.forId(18962).getHandlers().put("option:look in", this); - SceneryDefinition.forId(18963).getHandlers().put("option:search", this); - SceneryDefinition.forId(18963).getHandlers().put("option:look in", this); - SceneryDefinition.forId(18951).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18951).getHandlers().put("option:use", this); - SceneryDefinition.forId(2684).getHandlers().put("option:search", this); - SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); - SceneryDefinition.forId(18875).getHandlers().put("option:inspect", this); - NPCDefinition.forId(830).getHandlers().put("option:watch", this); - NPCDefinition.forId(4975).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(4976).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(4977).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(4978).getHandlers().put("option:talk-to", this); - NPCDefinition.forId(5002).getHandlers().put("option:talk-to", this); - TouristTrap.TECHNICAL_PLANS.getDefinition().getHandlers().put("option:read", this); - TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:look", this); - TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:drop", this); - ClassScanner.definePlugin(new BedabinKeyHandler()); - ClassScanner.definePlugin(new BedabinAnvilHandler()); - ClassScanner.definePlugin(new BarrelDialogue()); - ClassScanner.definePlugin(new WinchDialogue()); - ClassScanner.definePlugin(new MineCartDialogue()); - ClassScanner.definePlugin(new AnnaCartHandler()); - ClassScanner.definePlugin(new AnnaCartCutscene()); - ClassScanner.definePlugin(new AnnaWinchHandler()); - ClassScanner.definePlugin(new WinchCutscene()); - ClassScanner.definePlugin(new CartDialogue()); - return this; - } - - @Override - public boolean handle(final Player player, Node node, String option) { - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - final int id = node.getId(); - switch (option) { - case "read": - player.getDialogueInterpreter().sendDialogue("The plans look very technical! But you can see that this item will", "require a bronze bar and at least 10 feathers."); - break; - case "watch": - switch (id) { - case 2676: - case 2675: - player.getDialogueInterpreter().sendDialogue("You watch the doors for some time. You notice that only slaves seem", "to do down there. You might be able to sneak down if you pass as a", "slave."); - break; - default: - player.getDialogueInterpreter().sendDialogue("You watch the Mercenary Captain for some time. He has a large", "metal key attached to his belt. You notice that he usually gets his", "men to do his dirty work."); - break; - } - break; - case "walk through": - switch (id) { - case 2698: - case 2699: - if (quest.getStage(player) < 60) { - player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you! You're not allowed in there."); - break; - } - if (!TouristTrap.hasSlaveClothes(player)) { - player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you're not a slave!"); - break; - } - player.getProperties().setTeleportLocation(player.getLocation().transform(player.getLocation().getX() >= 3284 ? -4 : 4, 0, 0)); - player.getPacketDispatch().sendMessages("You walk into the darkness of the cavern...", "... and emerge in a different part of this huge underground complex."); - break; - } - break; - case "look": - player.getDialogueInterpreter().sendDialogues(823, null, "Let me out of here, I feel sick!"); - break; - case "drop": - player.getDialogueInterpreter().sendDialogues(823, null, "Don't let me out!"); - break; - case "open": - switch (id) { - case 2688: - case 2687: - if (!player.getInventory().containsItem(TouristTrap.WROUGHT_IRON_KEY)) { - player.getPacketDispatch().sendMessage("This gate looks like it needs a key to open it."); - break; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - break; - case 2686: - case 2685: - player.getDialogueInterpreter().sendDialogues(4999, null, "Hey, move away from the gate. There's nothing", "interesting for you here."); - break; - case 2677: - if (!player.getInventory().containsItem(TouristTrap.BEDABIN_KEY)) { - player.getPacketDispatch().sendMessage("This chest needs a key to unlock it."); - break; - } - if (quest.getStage(player) <= 54 && quest.getStage(player) != 53) { - player.getPacketDispatch().sendMessage("The captain spots you before you manage to open the chest..."); - player.lock(3); - GameWorld.getPulser().submit(new Pulse(2, player) { - @Override - public boolean pulse() { - player.getDialogueInterpreter().open(831, RegionManager.getNpc(player.getLocation(), 831, 16)); - return true; - } - }); - } else if (quest.getStage(player) == 53) { - if (!player.hasItem(TouristTrap.TECHNICAL_PLANS)) { - player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "While the Captain's distracted, you quickly unlock the", "chest with the Bedabins' copy of the key. You take out", "the plans."); - player.getInventory().add(TouristTrap.TECHNICAL_PLANS, player); - } - } - break; - case 2690: - case 2691: - player.setAttribute("ana-delay", GameWorld.getTicks() + 2); - player.getProperties().setTeleportLocation(Location.create(3301, 3035, 0)); - break; - case 2676: - case 2675: - if (!TouristTrap.hasSlaveClothes(player)) { - player.getDialogueInterpreter().sendDialogues(4997, null, "Watch it! Only slaves can travel into the mine."); - break; - } - player.setAttribute("ana-delay", GameWorld.getTicks() + 2); - player.getProperties().setTeleportLocation(Location.create(3278, 9427, 0)); - player.getDialogueInterpreter().sendDialogue("The huge doors open into a dark, dank and smelly tunnel. The", "associated smells of a hundred sweaty miners greets your nostrils.", "And your ears ring with the 'CLANG CLANG CLANG' as metal hits", "rock."); - break; - case 2674: - case 2673: - if (quest.getStage(player) > 60 && quest.getStage(player) < 98 && player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { - player.lock(); - player.getDialogueInterpreter().sendDialogues(4999, null, true, "Would you like me to take that heavy barrel", "for you?"); - GameWorld.getPulser().submit(new Pulse(4, player) { - int counter; - - @Override - public boolean pulse() { - switch (++counter) { - case 1: - player.getDialogueInterpreter().sendDialogues(player, null, "No, please don't."); - break; - case 2: - player.getDialogueInterpreter().close(); - player.getPacketDispatch().sendMessage("The guards search you!"); - break; - case 3: - player.getPacketDispatch().sendMessage("You are roughed up by the guards and manhandled into a cell."); - break; - case 4: - player.unlock(); - player.getInventory().remove(TouristTrap.ANNA_BARREL); - TouristTrap.addConfig(player, (1 << 4)); - quest.setStage(player, 61); - player.getProperties().setTeleportLocation(Location.create(3285, 3034, 0)); - return true; - } - return false; - } - }); - return true; - } - if (node.getLocation().withinDistance(new Location(3273, 3028, 0)) && !((player.getLocation().getX() >= 3274))) { - if (!player.getInventory().containsItem(TouristTrap.METAL_KEY)) { - player.getPacketDispatch().sendMessage("The gate needs a key in order to be opened."); - return true; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - player.getPacketDispatch().sendMessage("The guards search you thoroughly as you go through the gates."); - return true; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - break; - case 2689: - if (!player.getInventory().containsItem(TouristTrap.CELL_DOOR_KEY)) { - player.getPacketDispatch().sendMessage("The door seems to be pretty locked."); - break; - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); - break; - case 1528: - SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1529)); - break; - } - break; - case "close": - if (id == 1529) { - SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1528)); - } - break; - case "look-in": - case "look in": - switch (id) { - case 2681: - case 18962: - case 18963: - player.getDialogueInterpreter().sendDialogue("This looks like an empty mining barrel. Slaves use this to load up the", "rocks and stones that they're mining."); - break; - case 2680: - player.getDialogueInterpreter().sendDialogue("You search the full barrel... It's full of rocks."); - break; - } - break; - case "use": - if (id == 18951) { - player.getDialogueInterpreter().open("winch dialogue"); - } - break; - case "search": - switch (id) { - case 2688: - case 2687: - player.getDialogueInterpreter().sendDialogue("These wrought iron gates look like they're designed to keep people out.", "it looks like you'll need a key to get past these."); - break; - case 2686: - case 2685: - player.getDialogueInterpreter().sendDialogue("It looks as if this is where very difficult prisoners are sent as a", "punishment."); - break; - case 2681: - case 18962: - case 18963: - player.getDialogueInterpreter().open("barrel dialogue", node); - break; - case 2680:// barrel of rocks. - player.getDialogueInterpreter().sendDialogue("This looks like a full mining barrel. Slaves use this to load up the", "rocks and stones that they're mining. This barrel is full of rocks."); - break; - case 2684:// cart - player.getDialogueInterpreter().open("cart dialogue", node); - break; - case 2678: - if (quest.getStage(player) == 51) { - quest.setStage(player, 52); - } - player.getDialogueInterpreter().sendItemMessage(9904, "You notice several books on the subject of sailing."); - break; - case 2673: - case 2674: - player.getDialogueInterpreter().sendDialogue("You see what looks like a mining compound. There seems to be people", "mining rocks. They look as if they're chained to the rocks and they're", "being watched over by the guards. It's not a very happy place."); - break; - case 18958: - case 18959: - if (quest.getStage(player) == 90) { - player.getDialogueInterpreter().open("ana cart dialogue"); - break; - } - player.getPacketDispatch().sendMessage("This looks like a mine cart which takes barrels out of the encampment to Al Kharid."); - break; - case 18899: - case 18898: - case 18878: - case 18879: - player.getDialogueInterpreter().sendDialogue("You search the footsteps more closely. You can see that there are", "five sets of footprints. One set of footprints seem lighter than the", "others. The four other footsteps were made by heavier people", "with boots."); - break; - case 18902: - if (hasItem(player, TouristTrap.CELL_DOOR_KEY)) { - player.getInventory().add(TouristTrap.CELL_DOOR_KEY, player); - player.getDialogueInterpreter().sendItemMessage(TouristTrap.CELL_DOOR_KEY, "You find a cell door key."); - break; - } else if (hasItem(player, TouristTrap.WROUGHT_IRON_KEY) && player.getQuestRepository().isComplete(Quests.THE_TOURIST_TRAP)) { - player.getInventory().add(TouristTrap.WROUGHT_IRON_KEY, player); - player.getDialogueInterpreter().sendItemMessage(TouristTrap.WROUGHT_IRON_KEY, "You find the key to the main gate."); - break; - } - player.getPacketDispatch().sendMessage("You search the captains desk while he's not looking..."); - player.getPacketDispatch().sendMessage("...but you find nothing of interest."); - break; - } - break; - case "operate": - if (quest.getStage(player) != 71) { - player.getDialogueInterpreter().sendDialogue("There doesn't seem anything to lift."); - break; - } - ActivityManager.start(player, "winch cutscene", false); - break; - case "look at": - switch (id) { - case 18888: - player.getDialogueInterpreter().sendDialogue("This looks like a winch, it probably brings rocks up from", "underground."); - break; - case 18951: - player.getDialogueInterpreter().sendDialogue("This looks like a lift of some sort. You see barrels of rocks being", "placed on the lift and they're hauled up to the surface."); - break; - case 2684: - if (node.getLocation().getX() == 3318) { - player.getDialogueInterpreter().sendDialogue("This mine cart is being loaded up with new rocks and stone.", "It gets sent to a different section of the mine for unloading."); - break; - } - player.getDialogueInterpreter().sendDialogue("This cart is being unloaded into this section of the mine. Before being", "sent back to another section for another load."); - break; - case 18958: - case 18959: - player.getDialogueInterpreter().sendDialogue("A sturdy looking cart for carrying barrels of rocks out of ", "the mining camp."); - break; - case 18900: - case 18899: - case 18898: - case 18887: - case 18886: - case 18885: - case 18884: - case 18883: - case 18882: - case 18881: - case 18880: - case 18879: - case 18878: - case 18877: - player.getDialogueInterpreter().sendDialogue("This looks like some disturbed sand. Footsteps seem to be heading off", "towards the South."); - break; - } - break; - case "talk-to": - switch (id) { - case 5002: - ((NPC) node).sendChat("Move along please, don't want any trouble today!"); - break; - case 36748: - player.getDialogueInterpreter().sendDialogues(player, null, "Mmm... looks like that camel would make a nice kebab."); - break; - case 4975: - case 4977: - case 4978: - case 4976: - ((NPC) node).sendChat("Hey leave me alone, can't you see that i'm busy?"); - break; - } - break; - case "bend": - player.animate(Animation.create(5037)); - GameWorld.getPulser().submit(new Pulse(5, player) { - @Override - public boolean pulse() { - player.getPacketDispatch().sendMessage("You bend the bars back."); - setVarp(player, 907, getVarp(player, 907) + 1); - return true; - } - }); - break; - case "escape": - player.getPacketDispatch().sendMessage("You prepare to squeeze through the bars."); - AgilityHandler.forceWalk(player, 0, player.getLocation(), player.getLocation().transform(player.getLocation().getX() <= node.getLocation().getX() ? 1 : -1, 0, 0), Animation.create(5038), 4, 0.0, null); - break; - case "climb": - player.getPacketDispatch().sendMessage("You scrape your hands and knees as you climb up."); - AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3279, 3037, 0), Animation.create(5041), 10, 0, null); - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.getAnimator().reset(); - return true; - } - }); - break; - case "climb-up": - if (id == 18923) { - if (player.getLocation().getX() <= 3278) { - return true; - } - player.animate(Animation.create(5039)); - GameWorld.getPulser().submit(new Pulse(6, player) { - @Override - public boolean pulse() { - player.getAnimator().reset(); - player.getProperties().setTeleportLocation(Location.create(3278, 3037, 0)); - return true; - } - }); - } - break; - case "climb-down": - if (id == 18924) { - if (player.getLocation().getX() <= 3273) { - return true; - } - AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3270, 3039, 0), Animation.create(5040), 20, 0, null); - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.getAnimator().reset(); - return true; - } - }); - } - break; - case "inspect": - if (id == 18875) { - sendDialogue(player, "You remember that Irena mentioned something about Ana wearing a red scarf before she left for the desert."); - } - break; - } - return true; - } - - @Override - public boolean isWalk(final Player player, Node node) { - return !(node instanceof Item); - } - - @Override - public boolean isWalk() { - return false; - } - - @Override - public Location getDestination(Node node, Node n) { - if (n.getId() == 18923) { - return new Location(3279, 3037, 0); - } - return null; - } - - /** - * Checks if the player contains an item. - * - * @param player the player. - * @param item the item. - * @return the item. - */ - private boolean hasItem(final Player player, final Item item) { - return !player.getInventory().containsItem(item) && !player.getBank().containsItem(item); - } - - /** - * The winch dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class WinchDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code WinchDialogue} {@code Object}. - */ - public WinchDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code WinchDialogue} {@code Object}. - * - * @param player the player. - */ - public WinchDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new WinchDialogue(player); - } - - @Override - public boolean open(Object... args) { - if (args.length >= 1) { - interpreter.sendDialogue("The guard notices the barrel (with Ana in it) that you're carrying."); - stage = 500; - return true; - } - interpreter.sendDialogues(4999, null, "Hey there, what do you want?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 500:// winch - interpreter.sendDialogues(5002, null, "Hey, that Barrel looks heavy, do you need a hand?"); - stage++; - break; - case 501: - player("Yes please."); - stage++; - break; - case 502: - interpreter.sendDialogue("The guard comes over and helps you. He takes one end of the", "barrel."); - stage++; - break; - case 503: - interpreter.sendDialogues(5002, null, "Blimey! This is heavy!"); - stage++; - break; - case 504: - interpreter.sendDialogues(823, null, "Why you cheeky....!"); - stage++; - break; - case 505: - interpreter.sendDialogues(5002, null, "- The guard looks around surprised at Ana's outburst. -", "What was that?"); - stage++; - break; - case 506: - player("Oh, it was nothing."); - stage++; - break; - case 507: - interpreter.sendDialogues(5002, null, "I could have sworn I heard something!"); - stage++; - break; - case 508: - interpreter.sendDialogues(823, null, "Yes you did you ignoramus."); - stage++; - break; - case 509: - interpreter.sendDialogues(5002, null, "What was that you said?"); - stage++; - break; - case 510: - player("I said you were very gregarious!"); - stage++; - break; - case 511: - interpreter.sendDialogues(823, null, "You creep!"); - stage++; - break; - case 512: - interpreter.sendDialogues(5002, null, "Oh, right, how very nice of you to say so.", "-- The guard seems flattered. --"); - stage++; - break; - case 513: - interpreter.sendDialogues(5002, null, "Anyway, let's get this barrel up to the surface, plenty", "more work for you to do!"); - stage++; - break; - case 514: - interpreter.sendDialogue("The guard places the barrel carefully on the lift platform."); - stage++; - break; - case 515: - interpreter.sendDialogues(5002, null, "Oh, there's no one operating the lift up top, hope this", "barrel isn't urgent? You'd better get back to work!"); - stage = 516; - break; - case 516: - player.getInventory().remove(TouristTrap.ANNA_BARREL); - player.getBank().remove(TouristTrap.ANNA_BARREL); - player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 71); - end(); - break; - case 0: - options("What is this thing?", "Can I use this?"); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - player("What is this thing?"); - stage = 10; - break; - case 2: - player("Can I use this?"); - stage = 20; - break; - } - break; - case 10: - interpreter.sendDialogues(4999, null, "It is quite clearly a lift. Any fool can see that it's used to", "transport rock to the surface."); - stage++; - break; - case 11: - case 21: - end(); - break; - case 20: - interpreter.sendDialogues(4999, null, "Of course not, you'd be doing me out of a job. Anyway", "you haven't got any barrels that need to go to", "the surface."); - stage++; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("winch dialogue")}; - } - - } - - /** - * The use with handler for anna on the cart. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class AnnaCartHandler extends UseWithHandler { - - /** - * Constructs a new {@code AnnaCartHandler} {@code Object}. - */ - public AnnaCartHandler() { - super(TouristTrap.ANNA_BARREL.getId()); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(2684, OBJECT_TYPE, this); - addHandler(18958, OBJECT_TYPE, this); - return this; - } - - @Override - public boolean handle(final NodeUsageEvent event) { - final Player player = event.getPlayer(); - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if (event.getUsedWith().getId() == 18958) {// cart - if (quest.getStage(player) == 72) { - player.lock(4); - player.animate(Animation.create(5050)); - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.getInventory().remove(event.getUsedItem()); - TouristTrap.addConfig(player, 4096 + (2048 + (1 << 4))); - quest.setStage(player, 80); - player.getDialogueInterpreter().sendDialogue("You place Ana (In the barrel) carefully on the cart. This was the last", "barrel to go on the cart, but the cart driver doesn't seem to be", "any rush to get going. And the desert heat will soon get to Ana."); - return true; - } - }); - } - return true; - } - if (!event.getUsedWith().getLocation().equals(Location.create(3318, 9430, 0))) { - return false; - } - if (quest.getStage(player) != 61) { - return false; - } - player.getDialogueInterpreter().sendDialogue("You carefully place Ana in the barrel into the mine", "cart. Soon the cart moves out of sight and then it", "returns."); - player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); - ActivityManager.start(player, "ana cart", false); - return true; - } - - /** - * The ana cart cutscene plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class AnnaCartCutscene extends CutscenePlugin { - - /** - * The paths. - */ - private static final Location[][] PATHS = new Location[][]{{Location.create(3315, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9428, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3316, 9417, 0), Location.create(3314, 9417, 0), Location.create(3303, 9417, 0)}}; - - /** - * Constructs a new {@code AnnaCartCutscene} {@code Object}. - */ - public AnnaCartCutscene() { - super("ana cart"); - } - - /** - * Constructs a new {@code AnnaCartCutscene} {@code Object}. - * - * @param player the player. - */ - public AnnaCartCutscene(final Player player) { - super("ana cart"); - this.player = player; - } - - @Override - public void open() { - super.open(); - player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); - player.faceLocation(base.transform(54, 22, 0)); - GameWorld.getPulser().submit(new Pulse(1, player) { - int counter; - NPC cart; - - @Override - public boolean pulse() { - switch (++counter) { - case 1: - player.animate(Animation.create(5052)); - break; - case 3: - SceneryBuilder.remove(RegionManager.getObject(base.transform(54, 22, 0))); - cart = NPC.create(4980, base.transform(54, 22, 0)); - cart.init(); - break; - case 4: - cart.getWalkingQueue().reset(); - for (Location l : PATHS[1]) { - Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); - cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); - } - break; - case 18: - cart.clear(); - break; - case 22: - cart = NPC.create(4981, base.transform(51, 9, 0)); - cart.init(); - cart.getWalkingQueue().reset(); - for (Location l : PATHS[0]) { - Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); - cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); - } - break; - case 33: - player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 70); - player.getInventory().remove(TouristTrap.ANNA_BARREL); - player.removeAttribute("ana-delay"); - AnnaCartCutscene.this.stop(true); - return true; - } - return false; - } - }); - } - - @Override - public ActivityPlugin newInstance(Player p) { - return new AnnaCartCutscene(p); - } - - @Override - public Location getSpawnLocation() { - return null; - } - - @Override - public Location getStartLocation() { - return base.transform(54, 23, 0); - } - - @Override - public void configure() { - region = DynamicRegion.create(13203); - setRegionBase(); - registerRegion(region.getId()); - } - } - } - - /** - * The cart dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class CartDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code CartDialogue} {@code Object}. - * - * @param player the player. - */ - public CartDialogue(final Player player) { - super(player); - } - - /** - * Constructs a new {@code CartDialogue} {@code Object}. - */ - public CartDialogue() { - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new CartDialogue(player); - } - - @Override - public boolean open(Object... args) { - interpreter.sendDialogue("There is space on the cart for you get on, would you like to try?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - options("Yes, I'll get on.", "No, I've got other plans."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - interpreter.sendDialogue("You decide to climb onto the cart."); - stage++; - break; - case 2: - end(); - break; - } - break; - case 2: - player.lock(); - player.animate(ClimbActionHandler.CLIMB_UP); - GameWorld.getPulser().submit(new Pulse(1, player) { - int counter; - - @Override - public boolean pulse() { - switch (counter++) { - case 1: - player.getInterfaceManager().openOverlay(new Component(115)); - break; - case 4: - player.getDialogueInterpreter().sendDialogue("As soon as you get on the cart, it starts to move.", "Before too long you are past the gates. You jump off", "the cart taking Ana with you."); - break; - case 6: - player.unlock(); - player.getInterfaceManager().closeOverlay(); - player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 95); - player.getInterfaceManager().close(); - player.getProperties().setTeleportLocation(Location.create(3258, 3029, 0)); - player.getInventory().add(TouristTrap.ANNA_BARREL); - return true; - } - return false; - } - }); - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("ana cart dialogue")}; - } - - } - - /** - * The minecart dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class MineCartDialogue extends DialoguePlugin { - - /** - * The failing animation of getting in the cart. - */ - private static final Animation FAIL_ANIMATION = new Animation(5048); - - /** - * The jumping animation. - */ - private static final Animation JUMP_ANIMATION = new Animation(5049); - - /** - * The cart. - */ - private Scenery cart; - - /** - * Constructs a new {@code MineCartDialogue} {@code Object}. - */ - public MineCartDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code MineCartDialogue} {@code Object}. - * - * @param player the player. - */ - public MineCartDialogue(final Player player) { - super(player); - } - - @Override - public void init() { - super.init(); - ClassScanner.definePlugin(new MiningCartCutscene()); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new MineCartDialogue(player); - } - - @Override - public boolean open(Object... args) { - cart = (Scenery) args[0]; - if (player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { - player("There's not enough room for both of us."); - stage = -1; - return true; - } - interpreter.sendDialogue("You search the mine cart..."); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case -1: - end(); - break; - case 0: - interpreter.sendDialogue("There may be just enough space to squeeze yourself into the cart.", "Would you like to try?"); - stage++; - break; - case 1: - options("Yes, of course.", "No thanks, it looks pretty dangerous."); - stage++; - break; - case 2: - switch (buttonId) { - case 1: - end(); - enterCart(player); - break; - case 2: - end(); - break; - } - break; - } - return true; - } - - /** - * Method used to enter the cart. - * - * @param player the player. - */ - public void enterCart(final Player player) { - if (RandomFunction.random(3) == 1) { - player.lock(FAIL_ANIMATION.getDelay()); - player.animate(FAIL_ANIMATION); - player.getImpactHandler().manualHit(player, 2, HitsplatType.NORMAL); - player.getPacketDispatch().sendMessages("You fail to fit yourself into the cart in time before it starts its journey.", "You bang your head on the cart as you try to jump in."); - } else { - GameWorld.getPulser().submit(new Pulse(3, player) { - @Override - public boolean pulse() { - player.animate(JUMP_ANIMATION); - return true; - } - }); - ActivityManager.start(player, "mining cart", false, cart.getLocation().getX() == 3303 ? 0 : 1); - } - } - - /** - * The mining cart cutscene plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class MiningCartCutscene extends CutscenePlugin { - - /** - * The paths. - */ - private static final Location[][] PATHS = new Location[][]{{Location.create(3303, 9417, 0), Location.create(3316, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9430, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3303, 9417, 0)}}; - - /** - * The path index. - */ - private int index; - - /** - * Constructs a new {@code MiningCartCutscene} {@code Object}. - */ - public MiningCartCutscene() { - super("mining cart"); - } - - /** - * Constructs a new {@code MiningCartCutscene} {@code Object}. - * - * @param player the player. - */ - public MiningCartCutscene(final Player player) { - super("mining cart"); - this.player = player; - } - - @Override - public boolean start(final Player player, boolean login, Object... args) { - index = (int) args[0]; - return super.start(player, login, args); - } - - @Override - public void open() { - SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0))); - SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[getPath().length - 1].getLocalX(), getPath()[getPath().length - 1].getLocalY(), 0))); - player.getAppearance().setAnimations(Animation.create(211)); - player.getAppearance().setRidingMinecart(true); - player.getAppearance().sync(); - player.getWalkingQueue().reset(); - for (Location l : getPath()) { - Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); - player.getWalkingQueue().addPath(loc.getX(), loc.getY(), true); - } - GameWorld.getPulser().submit(new Pulse(22, player) { - @Override - public boolean pulse() { - player.setAttribute("real-end", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); - player.setAttribute("cutscene:original-loc", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); - MiningCartCutscene.this.stop(true); - return true; - } - }); - } - - @Override - public void end() { - super.end(); - player.getAppearance().setDefaultAnimations(); - player.getAppearance().setRidingMinecart(false); - player.getAppearance().sync(); - } - - @Override - public void fade() { - if (index == 0) { - player.getDialogueInterpreter().sendDialogue("You appear in a large open room with what looks like lots of miners", "working away. This is a very rough looking area, the miners look like", "they're on their last legs."); - } else { - player.getDialogueInterpreter().sendDialogue("You appear back in the barrel loading room. A nearby slave looks", "surprised to see you popping out of the cart."); - } - } - - @Override - public ActivityPlugin newInstance(Player p) { - return new MiningCartCutscene(p); - } - - @Override - public Location getSpawnLocation() { - return null; - } - - @Override - public Location getStartLocation() { - return base.transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0); - } - - @Override - public void configure() { - region = DynamicRegion.create(13203); - setRegionBase(); - registerRegion(region.getId()); - } - - /** - * Gets the path index. - * - * @return the location. - */ - public Location[] getPath() { - return PATHS[index]; - } - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("cart dialogue")}; - } - - } - - /** - * The winch cutscene plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class WinchCutscene extends CutscenePlugin { - - /** - * Constructs a new {@code WinchCutscene} {@code Object}. - */ - public WinchCutscene() { - super("winch cutscene"); - } - - /** - * Constructs a new {@code WinchCutscene} {@code Object}. - * - * @param player the player. - */ - public WinchCutscene(final Player player) { - super("winch cutscene"); - this.player = player; - } - - @Override - public ActivityPlugin newInstance(Player p) { - return new WinchCutscene(p); - } - - @Override - public void open() { - super.open(); - player.getPacketDispatch().sendMessage("You try to operate the winch."); - player.faceLocation(base.transform(15, 9, 0)); - player.animate(Animation.create(5054)); - GameWorld.getPulser().submit(new Pulse(AnimationDefinition.forId(5054).getDurationTicks(), player) { - @Override - public boolean pulse() { - TouristTrap.addConfig(player, 2048 + (1 << 4)); - WinchCutscene.this.stop(true); - player.getDialogueInterpreter().open(822, true, true); - return true; - } - }); - } - - @Override - public Location getSpawnLocation() { - return null; - } - - @Override - public Location getStartLocation() { - return base.transform(16, 10, 0); - } - - @Override - public void configure() { - region = DynamicRegion.create(13103); - setRegionBase(); - registerRegion(region.getId()); - } - - } - - /** - * The use with handler on the chest. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BedabinKeyHandler extends UseWithHandler { - - /** - * Constructs a new {@code BedabinKeyHandler} {@code Object}. - */ - public BedabinKeyHandler() { - super(TouristTrap.BEDABIN_KEY.getId()); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(2677, OBJECT_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - player.getDialogueInterpreter().open(831, RegionManager.getNpc(player.getLocation(), 831, 16)); - return true; - } - - } - - /** - * The barrel dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BarrelDialogue extends DialoguePlugin { - - /** - * The scenery barrel. - */ - private Scenery barrel; - - /** - * The quest. - */ - private Quest quest; - - /** - * Constructs a new {@code BarrelDialogue} {@code Object}. - */ - public BarrelDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code BarrelDialogue} {@code Object}. - * - * @param player the player. - */ - public BarrelDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new BarrelDialogue(player); - } - - @Override - public boolean open(Object... args) { - barrel = (Scenery) args[0]; - quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if ((quest.getStage(player) == 70 || quest.getStage(player) == 72) && !player.hasItem(TouristTrap.ANNA_BARREL)) { - interpreter.sendDialogue("You search the barrels and find Ana."); - stage = 400; - return true; - } - if (player.getInventory().containsItem(TouristTrap.BARREL)) { - player.getPacketDispatch().sendMessage("You can only manage to have one of these at a time."); - end(); - return true; - } - interpreter.sendItemMessage(TouristTrap.BARREL, "This barrel is quite big. but you may be able to carry one. Would you like to take one?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 400:// finding anna. - interpreter.sendDialogues(823, null, "Let me out!"); - stage++; - break; - case 401: - if (!player.getInventory().hasSpaceFor(TouristTrap.ANNA_BARREL)) { - end(); - return true; - } - player.getPacketDispatch().sendMessage("You pick up Ana in a Barrel."); - player.getInventory().add(TouristTrap.ANNA_BARREL); - end(); - break; - case 402: - end(); - break; - case 0: - options("Yeah, cool!", "No thanks."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - interpreter.sendItemMessage(TouristTrap.BARREL, "You take the barrel, it's not heavy, just awkward."); - stage = 3; - break; - case 2: - end(); - break; - } - break; - case 3: - end(); - player.getInventory().add(TouristTrap.BARREL, player); - SceneryBuilder.remove(barrel); - GameWorld.getPulser().submit(new Pulse(40) { - @Override - public boolean pulse() { - SceneryBuilder.add(barrel); - return true; - } - }); - break; - - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("barrel dialogue")}; - } - - } - - /** - * The use with handler for the bedabin anvil. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BedabinAnvilHandler extends UseWithHandler { - - /** - * Constructs a new {@code BedabinAnvilHandler} {@code Object}. - */ - public BedabinAnvilHandler() { - super(2349); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(2672, OBJECT_TYPE, this); - ClassScanner.definePlugin(new PrototypeDartHandler()); - ClassScanner.definePlugin(new BedabinAnvilDialogue()); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if (quest.getStage(player) == 54 && player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { - player.getDialogueInterpreter().open("bedabin-anvil"); - return true; - } else { - player.getPacketDispatch().sendMessage("You need technical plans in order to do this."); - } - return true; - } - - /** - * The handler used to handle the anna barrel on the winch. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class AnnaWinchHandler extends UseWithHandler { - - /** - * Constructs a new {@code AnnaWinchHandler} {@code Object}. - */ - public AnnaWinchHandler() { - super(TouristTrap.ANNA_BARREL.getId()); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(18951, OBJECT_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); - if (!event.getUsedWith().getLocation().equals(Location.create(3292, 9423, 0))) { - return false; - } - if (quest.getStage(player) == 70) { - player.getDialogueInterpreter().open("winch dialogue", true); - return true; - } - return false; - } - - } - - /** - * The prototype dart creation handler. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class PrototypeDartHandler extends UseWithHandler { - - /** - * Constructs a new {@code PrototypeDartHandler} {@code Object}. - */ - public PrototypeDartHandler() { - super(314); - } - - @Override - public Plugin newInstance(Object arg) { - addHandler(TouristTrap.PROTOTYPE_DART_TIP.getId(), ITEM_TYPE, this); - ClassScanner.definePlugin(new ProtoTypeDialogue()); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - player.getDialogueInterpreter().open("prototype dart"); - return true; - } - - /** - * The prototype dialogue plugin. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class ProtoTypeDialogue extends DialoguePlugin { - - /** - * The feathers item. - */ - private static final Item FEATHERS = new Item(314, 10); - - /** - * Constructs a new {@code ProtoTypeDialogue} {@code Object}. - * - * @param player the player. - */ - public ProtoTypeDialogue(final Player player) { - super(player); - } - - /** - * Constructs a new {@code ProtoTypeDialogue} {@code Object}. - */ - public ProtoTypeDialogue() { - /** - * empty. - */ - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new ProtoTypeDialogue(player); - } - - @Override - public boolean open(Object... args) { - if (!player.getInventory().containsItem(FEATHERS)) { - interpreter.sendDialogue("You need 10 feathers in order to do this."); - stage = 10; - return false; - } - interpreter.sendItemMessage(314, "You try to attach feathers to the bronze dart tip."); - stage = 1; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 1: - interpreter.sendDialogue("Following the plans is tricky, but you persevere."); - stage++; - break; - case 2: - interpreter.sendItemMessage(TouristTrap.PROTOTYPE_DART, "You successfully attach the feathers to the dart tip."); - stage++; - break; - case 3: - player.getInventory().remove(FEATHERS, TouristTrap.PROTOTYPE_DART_TIP); - player.getInventory().add(TouristTrap.PROTOTYPE_DART); - end(); - break; - case 4: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("prototype dart")}; - } - - } - } - - /** - * The bedabin dialogue plugin handler. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class BedabinAnvilDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. - */ - public BedabinAnvilDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. - * - * @param player the player. - */ - public BedabinAnvilDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new BedabinAnvilDialogue(player); - } - - @Override - public boolean open(Object... args) { - if (!player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { - player.getPacketDispatch().sendMessage("You need the plans to do this."); - return false; - } - player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "Do you want to follow the technical plans ?"); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - options("Yes. I'd like to try.", "No, not just yet."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - end(); - player.getPulseManager().run(new ProtoTypePulse(player)); - break; - case 2: - end(); - break; - } - break; - } - return true; - } - - /** - * The skill pulse used to make a prototype dart. - * - * @author 'Vexia - * @version 1.0 - */ - public static final class ProtoTypePulse extends SkillPulse { - - /** - * The hammer item. - */ - private static final Item HAMMER = new Item(2347); - - /** - * The ticks passed. - */ - private int ticks; - - /** - * Constructs a new {@code ProtoTypePulse} {@code Object}. - * - * @param player the player. - */ - public ProtoTypePulse(Player player) { - super(player, null); - } - - @Override - public boolean checkRequirements() { - if (!player.getInventory().hasSpaceFor(TouristTrap.PROTOTYPE_DART_TIP)) { - player.getPacketDispatch().sendMessage("Not enough inventory space."); - return false; - } - if (!player.getInventory().containsItem(HAMMER)) { - player.getPacketDispatch().sendMessage("You need a hammer in order to work metal with."); - return false; - } - return player.getInventory().containsItem(Bar.BRONZE.getProduct()); - } - - @Override - public void animate() { - if (ticks % 4 == 0) { - player.animate(Animation.create(898)); - } - } - - @Override - public boolean reward() { - if (++ticks % 4 != 0) { - return false; - } - if (ticks == 4) { - player.getDialogueInterpreter().sendPlainMessage(true, "You begin experimenting in forging the weapon..."); - } else if (ticks == 8) { - player.getInventory().remove(Bar.BRONZE.getProduct()); - player.getInventory().add(TouristTrap.PROTOTYPE_DART_TIP); - player.getDialogueInterpreter().sendItemMessage(TouristTrap.PROTOTYPE_DART_TIP, "You follow the plans carefully, and after some careful", "work, you finally manage to forge a sharp, pointed...", "dart tip."); - return true; - } - return false; - } - - @Override - public void stop() { - super.stop(); - } - - } - - @Override - public int[] getIds() { - return new int[]{DialogueInterpreter.getDialogueKey("bedabin-anvil")}; - } - - } - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + SceneryDefinition.forId(2673).getHandlers().put("option:open", this); + SceneryDefinition.forId(2674).getHandlers().put("option:open", this); + SceneryDefinition.forId(2673).getHandlers().put("option:search", this); + SceneryDefinition.forId(2674).getHandlers().put("option:search", this); + SceneryDefinition.forId(2688).getHandlers().put("option:open", this); + SceneryDefinition.forId(2688).getHandlers().put("option:search", this); + SceneryDefinition.forId(2687).getHandlers().put("option:open", this); + SceneryDefinition.forId(2687).getHandlers().put("option:search", this); + SceneryDefinition.forId(2685).getHandlers().put("option:open", this); + SceneryDefinition.forId(2685).getHandlers().put("option:open", this); + SceneryDefinition.forId(2686).getHandlers().put("option:search", this); + SceneryDefinition.forId(2686).getHandlers().put("option:search", this); + SceneryDefinition.forId(18958).getHandlers().put("option:search", this); + SceneryDefinition.forId(18958).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18959).getHandlers().put("option:search", this); + SceneryDefinition.forId(18959).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18888).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18888).getHandlers().put("option:operate", this); + SceneryDefinition.forId(36748).getHandlers().put("option:talk-to", this); + SceneryDefinition.forId(18869).getHandlers().put("option:bend", this); + SceneryDefinition.forId(18870).getHandlers().put("option:escape", this); + SceneryDefinition.forId(2689).getHandlers().put("option:open", this); + SceneryDefinition.forId(1528).getHandlers().put("option:open", this); + SceneryDefinition.forId(1529).getHandlers().put("option:close", this); + SceneryDefinition.forId(18899).getHandlers().put("option:search", this); + SceneryDefinition.forId(18899).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18878).getHandlers().put("option:search", this); + SceneryDefinition.forId(18878).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18879).getHandlers().put("option:search", this); + SceneryDefinition.forId(18879).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18898).getHandlers().put("option:search", this); + SceneryDefinition.forId(18898).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18902).getHandlers().put("option:search", this); + SceneryDefinition.forId(18871).getHandlers().put("option:climb", this); + SceneryDefinition.forId(18923).getHandlers().put("option:climb-up", this); + SceneryDefinition.forId(18924).getHandlers().put("option:climb-down", this); + SceneryDefinition.forId(2676).getHandlers().put("option:open", this); + SceneryDefinition.forId(2675).getHandlers().put("option:open", this); + SceneryDefinition.forId(2676).getHandlers().put("option:watch", this); + SceneryDefinition.forId(2675).getHandlers().put("option:watch", this); + SceneryDefinition.forId(2690).getHandlers().put("option:open", this); + SceneryDefinition.forId(2691).getHandlers().put("option:open", this); + SceneryDefinition.forId(2698).getHandlers().put("option:walk through", this); + SceneryDefinition.forId(2699).getHandlers().put("option:walk through", this); + SceneryDefinition.forId(2677).getHandlers().put("option:open", this); + SceneryDefinition.forId(2678).getHandlers().put("option:search", this); + SceneryDefinition.forId(2684).getHandlers().put("option:search", this); + SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); + SceneryDefinition.forId(2680).getHandlers().put("option:search", this); + SceneryDefinition.forId(2680).getHandlers().put("option:look-in", this); + SceneryDefinition.forId(2681).getHandlers().put("option:search", this); + SceneryDefinition.forId(2681).getHandlers().put("option:look in", this); + SceneryDefinition.forId(18962).getHandlers().put("option:search", this); + SceneryDefinition.forId(18962).getHandlers().put("option:look in", this); + SceneryDefinition.forId(18963).getHandlers().put("option:search", this); + SceneryDefinition.forId(18963).getHandlers().put("option:look in", this); + SceneryDefinition.forId(18951).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18951).getHandlers().put("option:use", this); + SceneryDefinition.forId(2684).getHandlers().put("option:search", this); + SceneryDefinition.forId(2684).getHandlers().put("option:look at", this); + SceneryDefinition.forId(18875).getHandlers().put("option:inspect", this); + NPCDefinition.forId(830).getHandlers().put("option:watch", this); + NPCDefinition.forId(4975).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(4976).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(4977).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(4978).getHandlers().put("option:talk-to", this); + NPCDefinition.forId(5002).getHandlers().put("option:talk-to", this); + TouristTrap.TECHNICAL_PLANS.getDefinition().getHandlers().put("option:read", this); + TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:look", this); + TouristTrap.ANNA_BARREL.getDefinition().getHandlers().put("option:drop", this); + ClassScanner.definePlugin(new BedabinKeyHandler()); + ClassScanner.definePlugin(new BedabinAnvilHandler()); + ClassScanner.definePlugin(new BarrelDialogue()); + ClassScanner.definePlugin(new WinchDialogue()); + ClassScanner.definePlugin(new MineCartDialogue()); + ClassScanner.definePlugin(new AnnaCartHandler()); + ClassScanner.definePlugin(new AnnaCartCutscene()); + ClassScanner.definePlugin(new AnnaWinchHandler()); + ClassScanner.definePlugin(new WinchCutscene()); + ClassScanner.definePlugin(new CartDialogue()); + return this; + } + + @Override + public boolean handle(final Player player, Node node, String option) { + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + final int id = node.getId(); + switch (option) { + case "read": + player.getDialogueInterpreter().sendDialogue("The plans look very technical! But you can see that this item will", "require a bronze bar and at least 10 feathers."); + break; + case "watch": + switch (id) { + case 2676: + case 2675: + player.getDialogueInterpreter().sendDialogue("You watch the doors for some time. You notice that only slaves seem", "to do down there. You might be able to sneak down if you pass as a", "slave."); + break; + default: + player.getDialogueInterpreter().sendDialogue("You watch the Mercenary Captain for some time. He has a large", "metal key attached to his belt. You notice that he usually gets his", "men to do his dirty work."); + break; + } + break; + case "walk through": + switch (id) { + case 2698: + case 2699: + if (quest.getStage(player) < 60) { + player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you! You're not allowed in there."); + break; + } + if (!TouristTrap.hasSlaveClothes(player)) { + player.getDialogueInterpreter().sendDialogues(5001, null, "Hey you're not a slave!"); + break; + } + player.getProperties().setTeleportLocation(player.getLocation().transform(player.getLocation().getX() >= 3284 ? -4 : 4, 0, 0)); + player.getPacketDispatch().sendMessages("You walk into the darkness of the cavern...", "... and emerge in a different part of this huge underground complex."); + break; + } + break; + case "look": + player.getDialogueInterpreter().sendDialogues(823, null, "Let me out of here, I feel sick!"); + break; + case "drop": + player.getDialogueInterpreter().sendDialogues(823, null, "Don't let me out!"); + break; + case "open": + switch (id) { + case 2688: + case 2687: + if (!player.getInventory().containsItem(TouristTrap.WROUGHT_IRON_KEY)) { + player.getPacketDispatch().sendMessage("This gate looks like it needs a key to open it."); + break; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + break; + case 2686: + case 2685: + player.getDialogueInterpreter().sendDialogues(4999, null, "Hey, move away from the gate. There's nothing", "interesting for you here."); + break; + case 2677: + if (!player.getInventory().containsItem(TouristTrap.BEDABIN_KEY)) { + player.getPacketDispatch().sendMessage("This chest needs a key to unlock it."); + break; + } + if (quest.getStage(player) <= 54 && quest.getStage(player) != 53) { + player.getPacketDispatch().sendMessage("The captain spots you before you manage to open the chest..."); + player.lock(3); + GameWorld.getPulser().submit(new Pulse(2, player) { + @Override + public boolean pulse() { + player.getDialogueInterpreter().open(831, RegionManager.getNpc(player.getLocation(), 831, 16)); + return true; + } + }); + } else if (quest.getStage(player) == 53) { + if (!player.hasItem(TouristTrap.TECHNICAL_PLANS)) { + player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "While the Captain's distracted, you quickly unlock the", "chest with the Bedabins' copy of the key. You take out", "the plans."); + player.getInventory().add(TouristTrap.TECHNICAL_PLANS, player); + } + } + break; + case 2690: + case 2691: + player.setAttribute("ana-delay", GameWorld.getTicks() + 2); + player.getProperties().setTeleportLocation(Location.create(3301, 3035, 0)); + break; + case 2676: + case 2675: + if (!TouristTrap.hasSlaveClothes(player)) { + player.getDialogueInterpreter().sendDialogues(4997, null, "Watch it! Only slaves can travel into the mine."); + break; + } + player.setAttribute("ana-delay", GameWorld.getTicks() + 2); + player.getProperties().setTeleportLocation(Location.create(3278, 9427, 0)); + player.getDialogueInterpreter().sendDialogue("The huge doors open into a dark, dank and smelly tunnel. The", "associated smells of a hundred sweaty miners greets your nostrils.", "And your ears ring with the 'CLANG CLANG CLANG' as metal hits", "rock."); + break; + case 2674: + case 2673: + if (quest.getStage(player) > 60 && quest.getStage(player) < 98 && player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { + player.lock(); + player.getDialogueInterpreter().sendDialogues(4999, null, true, "Would you like me to take that heavy barrel", "for you?"); + GameWorld.getPulser().submit(new Pulse(4, player) { + int counter; + + @Override + public boolean pulse() { + switch (++counter) { + case 1: + player.getDialogueInterpreter().sendDialogues(player, null, "No, please don't."); + break; + case 2: + player.getDialogueInterpreter().close(); + player.getPacketDispatch().sendMessage("The guards search you!"); + break; + case 3: + player.getPacketDispatch().sendMessage("You are roughed up by the guards and manhandled into a cell."); + break; + case 4: + player.unlock(); + player.getInventory().remove(TouristTrap.ANNA_BARREL); + TouristTrap.addConfig(player, (1 << 4)); + quest.setStage(player, 61); + player.getProperties().setTeleportLocation(Location.create(3285, 3034, 0)); + return true; + } + return false; + } + }); + return true; + } + if (node.getLocation().withinDistance(new Location(3273, 3028, 0)) && !((player.getLocation().getX() >= 3274))) { + if (!player.getInventory().containsItem(TouristTrap.METAL_KEY)) { + player.getPacketDispatch().sendMessage("The gate needs a key in order to be opened."); + return true; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + player.getPacketDispatch().sendMessage("The guards search you thoroughly as you go through the gates."); + return true; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + break; + case 2689: + if (!player.getInventory().containsItem(TouristTrap.CELL_DOOR_KEY)) { + player.getPacketDispatch().sendMessage("The door seems to be pretty locked."); + break; + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node); + break; + case 1528: + SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1529)); + break; + } + break; + case "close": + if (id == 1529) { + SceneryBuilder.replace((Scenery) node, ((Scenery) node).transform(1528)); + } + break; + case "look-in": + case "look in": + switch (id) { + case 2681: + case 18962: + case 18963: + player.getDialogueInterpreter().sendDialogue("This looks like an empty mining barrel. Slaves use this to load up the", "rocks and stones that they're mining."); + break; + case 2680: + player.getDialogueInterpreter().sendDialogue("You search the full barrel... It's full of rocks."); + break; + } + break; + case "use": + if (id == 18951) { + player.getDialogueInterpreter().open("winch dialogue"); + } + break; + case "search": + switch (id) { + case 2688: + case 2687: + player.getDialogueInterpreter().sendDialogue("These wrought iron gates look like they're designed to keep people out.", "it looks like you'll need a key to get past these."); + break; + case 2686: + case 2685: + player.getDialogueInterpreter().sendDialogue("It looks as if this is where very difficult prisoners are sent as a", "punishment."); + break; + case 2681: + case 18962: + case 18963: + player.getDialogueInterpreter().open("barrel dialogue", node); + break; + case 2680:// barrel of rocks. + player.getDialogueInterpreter().sendDialogue("This looks like a full mining barrel. Slaves use this to load up the", "rocks and stones that they're mining. This barrel is full of rocks."); + break; + case 2684:// cart + player.getDialogueInterpreter().open("cart dialogue", node); + break; + case 2678: + if (quest.getStage(player) == 51) { + quest.setStage(player, 52); + } + player.getDialogueInterpreter().sendItemMessage(9904, "You notice several books on the subject of sailing."); + break; + case 2673: + case 2674: + player.getDialogueInterpreter().sendDialogue("You see what looks like a mining compound. There seems to be people", "mining rocks. They look as if they're chained to the rocks and they're", "being watched over by the guards. It's not a very happy place."); + break; + case 18958: + case 18959: + if (quest.getStage(player) == 90) { + player.getDialogueInterpreter().open("ana cart dialogue"); + break; + } + player.getPacketDispatch().sendMessage("This looks like a mine cart which takes barrels out of the encampment to Al Kharid."); + break; + case 18899: + case 18898: + case 18878: + case 18879: + player.getDialogueInterpreter().sendDialogue("You search the footsteps more closely. You can see that there are", "five sets of footprints. One set of footprints seem lighter than the", "others. The four other footsteps were made by heavier people", "with boots."); + break; + case 18902: + if (hasItem(player, TouristTrap.CELL_DOOR_KEY)) { + player.getInventory().add(TouristTrap.CELL_DOOR_KEY, player); + player.getDialogueInterpreter().sendItemMessage(TouristTrap.CELL_DOOR_KEY, "You find a cell door key."); + break; + } else if (hasItem(player, TouristTrap.WROUGHT_IRON_KEY) && player.getQuestRepository().isComplete(Quests.THE_TOURIST_TRAP)) { + player.getInventory().add(TouristTrap.WROUGHT_IRON_KEY, player); + player.getDialogueInterpreter().sendItemMessage(TouristTrap.WROUGHT_IRON_KEY, "You find the key to the main gate."); + break; + } + player.getPacketDispatch().sendMessage("You search the captains desk while he's not looking..."); + player.getPacketDispatch().sendMessage("...but you find nothing of interest."); + break; + } + break; + case "operate": + if (quest.getStage(player) != 71) { + player.getDialogueInterpreter().sendDialogue("There doesn't seem anything to lift."); + break; + } + ActivityManager.start(player, "winch cutscene", false); + break; + case "look at": + switch (id) { + case 18888: + player.getDialogueInterpreter().sendDialogue("This looks like a winch, it probably brings rocks up from", "underground."); + break; + case 18951: + player.getDialogueInterpreter().sendDialogue("This looks like a lift of some sort. You see barrels of rocks being", "placed on the lift and they're hauled up to the surface."); + break; + case 2684: + if (node.getLocation().getX() == 3318) { + player.getDialogueInterpreter().sendDialogue("This mine cart is being loaded up with new rocks and stone.", "It gets sent to a different section of the mine for unloading."); + break; + } + player.getDialogueInterpreter().sendDialogue("This cart is being unloaded into this section of the mine. Before being", "sent back to another section for another load."); + break; + case 18958: + case 18959: + player.getDialogueInterpreter().sendDialogue("A sturdy looking cart for carrying barrels of rocks out of ", "the mining camp."); + break; + case 18900: + case 18899: + case 18898: + case 18887: + case 18886: + case 18885: + case 18884: + case 18883: + case 18882: + case 18881: + case 18880: + case 18879: + case 18878: + case 18877: + player.getDialogueInterpreter().sendDialogue("This looks like some disturbed sand. Footsteps seem to be heading off", "towards the South."); + break; + } + break; + case "talk-to": + switch (id) { + case 5002: + ((NPC) node).sendChat("Move along please, don't want any trouble today!"); + break; + case 36748: + player.getDialogueInterpreter().sendDialogues(player, null, "Mmm... looks like that camel would make a nice kebab."); + break; + case 4975: + case 4977: + case 4978: + case 4976: + ((NPC) node).sendChat("Hey leave me alone, can't you see that i'm busy?"); + break; + } + break; + case "bend": + player.animate(Animation.create(5037)); + GameWorld.getPulser().submit(new Pulse(5, player) { + @Override + public boolean pulse() { + player.getPacketDispatch().sendMessage("You bend the bars back."); + setVarp(player, 907, getVarp(player, 907) + 1); + return true; + } + }); + break; + case "escape": + player.getPacketDispatch().sendMessage("You prepare to squeeze through the bars."); + AgilityHandler.forceWalk(player, 0, player.getLocation(), player.getLocation().transform(player.getLocation().getX() <= node.getLocation().getX() ? 1 : -1, 0, 0), Animation.create(5038), 4, 0.0, null); + break; + case "climb": + player.getPacketDispatch().sendMessage("You scrape your hands and knees as you climb up."); + AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3279, 3037, 0), Animation.create(5041), 10, 0, null); + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.getAnimator().reset(); + return true; + } + }); + break; + case "climb-up": + if (id == 18923) { + if (player.getLocation().getX() <= 3278) { + return true; + } + player.animate(Animation.create(5039)); + GameWorld.getPulser().submit(new Pulse(6, player) { + @Override + public boolean pulse() { + player.getAnimator().reset(); + player.getProperties().setTeleportLocation(Location.create(3278, 3037, 0)); + return true; + } + }); + } + break; + case "climb-down": + if (id == 18924) { + if (player.getLocation().getX() <= 3273) { + return true; + } + AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(3270, 3039, 0), Animation.create(5040), 20, 0, null); + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.getAnimator().reset(); + return true; + } + }); + } + break; + case "inspect": + if (id == 18875) { + sendDialogue(player, "You remember that Irena mentioned something about Ana wearing a red scarf before she left for the desert."); + } + break; + } + return true; + } + + @Override + public boolean isWalk(final Player player, Node node) { + return !(node instanceof Item); + } + + @Override + public boolean isWalk() { + return false; + } + + @Override + public Location getDestination(Node node, Node n) { + if (n.getId() == 18923) { + return new Location(3279, 3037, 0); + } + return null; + } + + /** + * Checks if the player contains an item. + * + * @param player the player. + * @param item the item. + * @return the item. + */ + private boolean hasItem(final Player player, final Item item) { + return !player.getInventory().containsItem(item) && !player.getBank().containsItem(item); + } + + /** + * The winch dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class WinchDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code WinchDialogue} {@code Object}. + */ + public WinchDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code WinchDialogue} {@code Object}. + * + * @param player the player. + */ + public WinchDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new WinchDialogue(player); + } + + @Override + public boolean open(Object... args) { + if (args.length >= 1) { + interpreter.sendDialogue("The guard notices the barrel (with Ana in it) that you're carrying."); + stage = 500; + return true; + } + interpreter.sendDialogues(4999, null, "Hey there, what do you want?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 500:// winch + interpreter.sendDialogues(5002, null, "Hey, that Barrel looks heavy, do you need a hand?"); + stage++; + break; + case 501: + player("Yes please."); + stage++; + break; + case 502: + interpreter.sendDialogue("The guard comes over and helps you. He takes one end of the", "barrel."); + stage++; + break; + case 503: + interpreter.sendDialogues(5002, null, "Blimey! This is heavy!"); + stage++; + break; + case 504: + interpreter.sendDialogues(823, null, "Why you cheeky....!"); + stage++; + break; + case 505: + interpreter.sendDialogues(5002, null, "- The guard looks around surprised at Ana's outburst. -", "What was that?"); + stage++; + break; + case 506: + player("Oh, it was nothing."); + stage++; + break; + case 507: + interpreter.sendDialogues(5002, null, "I could have sworn I heard something!"); + stage++; + break; + case 508: + interpreter.sendDialogues(823, null, "Yes you did you ignoramus."); + stage++; + break; + case 509: + interpreter.sendDialogues(5002, null, "What was that you said?"); + stage++; + break; + case 510: + player("I said you were very gregarious!"); + stage++; + break; + case 511: + interpreter.sendDialogues(823, null, "You creep!"); + stage++; + break; + case 512: + interpreter.sendDialogues(5002, null, "Oh, right, how very nice of you to say so.", "-- The guard seems flattered. --"); + stage++; + break; + case 513: + interpreter.sendDialogues(5002, null, "Anyway, let's get this barrel up to the surface, plenty", "more work for you to do!"); + stage++; + break; + case 514: + interpreter.sendDialogue("The guard places the barrel carefully on the lift platform."); + stage++; + break; + case 515: + interpreter.sendDialogues(5002, null, "Oh, there's no one operating the lift up top, hope this", "barrel isn't urgent? You'd better get back to work!"); + stage = 516; + break; + case 516: + player.getInventory().remove(TouristTrap.ANNA_BARREL); + player.getBank().remove(TouristTrap.ANNA_BARREL); + player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 71); + end(); + break; + case 0: + options("What is this thing?", "Can I use this?"); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + player("What is this thing?"); + stage = 10; + break; + case 2: + player("Can I use this?"); + stage = 20; + break; + } + break; + case 10: + interpreter.sendDialogues(4999, null, "It is quite clearly a lift. Any fool can see that it's used to", "transport rock to the surface."); + stage++; + break; + case 11: + case 21: + end(); + break; + case 20: + interpreter.sendDialogues(4999, null, "Of course not, you'd be doing me out of a job. Anyway", "you haven't got any barrels that need to go to", "the surface."); + stage++; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("winch dialogue")}; + } + + } + + /** + * The use with handler for anna on the cart. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class AnnaCartHandler extends UseWithHandler { + + /** + * Constructs a new {@code AnnaCartHandler} {@code Object}. + */ + public AnnaCartHandler() { + super(TouristTrap.ANNA_BARREL.getId()); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(2684, OBJECT_TYPE, this); + addHandler(18958, OBJECT_TYPE, this); + return this; + } + + @Override + public boolean handle(final NodeUsageEvent event) { + final Player player = event.getPlayer(); + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if (event.getUsedWith().getId() == 18958) {// cart + if (quest.getStage(player) == 72) { + player.lock(4); + player.animate(Animation.create(5050)); + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.getInventory().remove(event.getUsedItem()); + TouristTrap.addConfig(player, 4096 + (2048 + (1 << 4))); + quest.setStage(player, 80); + player.getDialogueInterpreter().sendDialogue("You place Ana (In the barrel) carefully on the cart. This was the last", "barrel to go on the cart, but the cart driver doesn't seem to be", "any rush to get going. And the desert heat will soon get to Ana."); + return true; + } + }); + } + return true; + } + if (!event.getUsedWith().getLocation().equals(Location.create(3318, 9430, 0))) { + return false; + } + if (quest.getStage(player) != 61) { + return false; + } + player.getDialogueInterpreter().sendDialogue("You carefully place Ana in the barrel into the mine", "cart. Soon the cart moves out of sight and then it", "returns."); + player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); + ActivityManager.start(player, "ana cart", false); + return true; + } + + /** + * The ana cart cutscene plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class AnnaCartCutscene extends CutscenePlugin { + + /** + * The paths. + */ + private static final Location[][] PATHS = new Location[][]{{Location.create(3315, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9428, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3316, 9417, 0), Location.create(3314, 9417, 0), Location.create(3303, 9417, 0)}}; + + /** + * Constructs a new {@code AnnaCartCutscene} {@code Object}. + */ + public AnnaCartCutscene() { + super("ana cart"); + } + + /** + * Constructs a new {@code AnnaCartCutscene} {@code Object}. + * + * @param player the player. + */ + public AnnaCartCutscene(final Player player) { + super("ana cart"); + this.player = player; + } + + @Override + public void open() { + super.open(); + player.setAttribute("ana-delay", GameWorld.getTicks() + 100000000); + player.faceLocation(base.transform(54, 22, 0)); + GameWorld.getPulser().submit(new Pulse(1, player) { + int counter; + NPC cart; + + @Override + public boolean pulse() { + switch (++counter) { + case 1: + player.animate(Animation.create(5052)); + break; + case 3: + SceneryBuilder.remove(RegionManager.getObject(base.transform(54, 22, 0))); + cart = NPC.create(4980, base.transform(54, 22, 0)); + cart.init(); + break; + case 4: + cart.getWalkingQueue().reset(); + for (Location l : PATHS[1]) { + Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); + cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); + } + break; + case 18: + cart.clear(); + break; + case 22: + cart = NPC.create(4981, base.transform(51, 9, 0)); + cart.init(); + cart.getWalkingQueue().reset(); + for (Location l : PATHS[0]) { + Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); + cart.getWalkingQueue().addPath(loc.getX(), loc.getY()); + } + break; + case 33: + player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 70); + player.getInventory().remove(TouristTrap.ANNA_BARREL); + player.removeAttribute("ana-delay"); + AnnaCartCutscene.this.stop(true); + return true; + } + return false; + } + }); + } + + @Override + public ActivityPlugin newInstance(Player p) { + return new AnnaCartCutscene(p); + } + + @Override + public Location getSpawnLocation() { + return null; + } + + @Override + public Location getStartLocation() { + return base.transform(54, 23, 0); + } + + @Override + public void configure() { + region = DynamicRegion.create(13203); + setRegionBase(); + registerRegion(region.getId()); + } + } + } + + /** + * The cart dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class CartDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code CartDialogue} {@code Object}. + * + * @param player the player. + */ + public CartDialogue(final Player player) { + super(player); + } + + /** + * Constructs a new {@code CartDialogue} {@code Object}. + */ + public CartDialogue() { + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new CartDialogue(player); + } + + @Override + public boolean open(Object... args) { + interpreter.sendDialogue("There is space on the cart for you get on, would you like to try?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + options("Yes, I'll get on.", "No, I've got other plans."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + interpreter.sendDialogue("You decide to climb onto the cart."); + stage++; + break; + case 2: + end(); + break; + } + break; + case 2: + player.lock(); + player.animate(ClimbActionHandler.CLIMB_UP); + GameWorld.getPulser().submit(new Pulse(1, player) { + int counter; + + @Override + public boolean pulse() { + switch (counter++) { + case 1: + player.getInterfaceManager().openOverlay(new Component(115)); + break; + case 4: + player.getDialogueInterpreter().sendDialogue("As soon as you get on the cart, it starts to move.", "Before too long you are past the gates. You jump off", "the cart taking Ana with you."); + break; + case 6: + player.unlock(); + player.getInterfaceManager().closeOverlay(); + player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP).setStage(player, 95); + player.getInterfaceManager().close(); + player.getProperties().setTeleportLocation(Location.create(3258, 3029, 0)); + player.getInventory().add(TouristTrap.ANNA_BARREL); + return true; + } + return false; + } + }); + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("ana cart dialogue")}; + } + + } + + /** + * The minecart dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class MineCartDialogue extends DialoguePlugin { + + /** + * The failing animation of getting in the cart. + */ + private static final Animation FAIL_ANIMATION = new Animation(5048); + + /** + * The jumping animation. + */ + private static final Animation JUMP_ANIMATION = new Animation(5049); + + /** + * The cart. + */ + private Scenery cart; + + /** + * Constructs a new {@code MineCartDialogue} {@code Object}. + */ + public MineCartDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code MineCartDialogue} {@code Object}. + * + * @param player the player. + */ + public MineCartDialogue(final Player player) { + super(player); + } + + @Override + public void init() { + super.init(); + ClassScanner.definePlugin(new MiningCartCutscene()); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new MineCartDialogue(player); + } + + @Override + public boolean open(Object... args) { + cart = (Scenery) args[0]; + if (player.getInventory().containsItem(TouristTrap.ANNA_BARREL)) { + player("There's not enough room for both of us."); + stage = -1; + return true; + } + interpreter.sendDialogue("You search the mine cart..."); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case -1: + end(); + break; + case 0: + interpreter.sendDialogue("There may be just enough space to squeeze yourself into the cart.", "Would you like to try?"); + stage++; + break; + case 1: + options("Yes, of course.", "No thanks, it looks pretty dangerous."); + stage++; + break; + case 2: + switch (buttonId) { + case 1: + end(); + enterCart(player); + break; + case 2: + end(); + break; + } + break; + } + return true; + } + + /** + * Method used to enter the cart. + * + * @param player the player. + */ + public void enterCart(final Player player) { + if (RandomFunction.random(3) == 1) { + player.lock(FAIL_ANIMATION.getDelay()); + player.animate(FAIL_ANIMATION); + player.getImpactHandler().manualHit(player, 2, HitsplatType.NORMAL); + player.getPacketDispatch().sendMessages("You fail to fit yourself into the cart in time before it starts its journey.", "You bang your head on the cart as you try to jump in."); + } else { + GameWorld.getPulser().submit(new Pulse(3, player) { + @Override + public boolean pulse() { + player.animate(JUMP_ANIMATION); + return true; + } + }); + ActivityManager.start(player, "mining cart", false, cart.getLocation().getX() == 3303 ? 0 : 1); + } + } + + /** + * The mining cart cutscene plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class MiningCartCutscene extends CutscenePlugin { + + /** + * The paths. + */ + private static final Location[][] PATHS = new Location[][]{{Location.create(3303, 9417, 0), Location.create(3316, 9417, 0), Location.create(3317, 9417, 0), Location.create(3318, 9418, 0), Location.create(3318, 9430, 0)}, {Location.create(3318, 9430, 0), Location.create(3318, 9418, 0), Location.create(3317, 9417, 0), Location.create(3303, 9417, 0)}}; + + /** + * The path index. + */ + private int index; + + /** + * Constructs a new {@code MiningCartCutscene} {@code Object}. + */ + public MiningCartCutscene() { + super("mining cart"); + } + + /** + * Constructs a new {@code MiningCartCutscene} {@code Object}. + * + * @param player the player. + */ + public MiningCartCutscene(final Player player) { + super("mining cart"); + this.player = player; + } + + @Override + public boolean start(final Player player, boolean login, Object... args) { + index = (int) args[0]; + return super.start(player, login, args); + } + + @Override + public void open() { + SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0))); + SceneryBuilder.remove(RegionManager.getObject(base.getLocation().transform(getPath()[getPath().length - 1].getLocalX(), getPath()[getPath().length - 1].getLocalY(), 0))); + player.getAppearance().setAnimations(Animation.create(211)); + player.getAppearance().setRidingMinecart(true); + player.getAppearance().sync(); + player.getWalkingQueue().reset(); + for (Location l : getPath()) { + Location loc = base.transform(l.getLocalX(), l.getLocalY(), 0); + player.getWalkingQueue().addPath(loc.getX(), loc.getY(), true); + } + GameWorld.getPulser().submit(new Pulse(22, player) { + @Override + public boolean pulse() { + player.setAttribute("real-end", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); + player.setAttribute("cutscene:original-loc", index == 0 ? Location.create(3319, 9431, 0) : Location.create(3303, 9416, 0)); + MiningCartCutscene.this.stop(true); + return true; + } + }); + } + + @Override + public void end() { + super.end(); + player.getAppearance().setDefaultAnimations(); + player.getAppearance().setRidingMinecart(false); + player.getAppearance().sync(); + } + + @Override + public void fade() { + if (index == 0) { + player.getDialogueInterpreter().sendDialogue("You appear in a large open room with what looks like lots of miners", "working away. This is a very rough looking area, the miners look like", "they're on their last legs."); + } else { + player.getDialogueInterpreter().sendDialogue("You appear back in the barrel loading room. A nearby slave looks", "surprised to see you popping out of the cart."); + } + } + + @Override + public ActivityPlugin newInstance(Player p) { + return new MiningCartCutscene(p); + } + + @Override + public Location getSpawnLocation() { + return null; + } + + @Override + public Location getStartLocation() { + return base.transform(getPath()[0].getLocalX(), getPath()[0].getLocalY(), 0); + } + + @Override + public void configure() { + region = DynamicRegion.create(13203); + setRegionBase(); + registerRegion(region.getId()); + } + + /** + * Gets the path index. + * + * @return the location. + */ + public Location[] getPath() { + return PATHS[index]; + } + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("cart dialogue")}; + } + + } + + /** + * The winch cutscene plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class WinchCutscene extends CutscenePlugin { + + /** + * Constructs a new {@code WinchCutscene} {@code Object}. + */ + public WinchCutscene() { + super("winch cutscene"); + } + + /** + * Constructs a new {@code WinchCutscene} {@code Object}. + * + * @param player the player. + */ + public WinchCutscene(final Player player) { + super("winch cutscene"); + this.player = player; + } + + @Override + public ActivityPlugin newInstance(Player p) { + return new WinchCutscene(p); + } + + @Override + public void open() { + super.open(); + player.getPacketDispatch().sendMessage("You try to operate the winch."); + player.faceLocation(base.transform(15, 9, 0)); + player.animate(Animation.create(5054)); + GameWorld.getPulser().submit(new Pulse(AnimationDefinition.forId(5054).getDurationTicks(), player) { + @Override + public boolean pulse() { + TouristTrap.addConfig(player, 2048 + (1 << 4)); + WinchCutscene.this.stop(true); + player.getDialogueInterpreter().open(822, true, true); + return true; + } + }); + } + + @Override + public Location getSpawnLocation() { + return null; + } + + @Override + public Location getStartLocation() { + return base.transform(16, 10, 0); + } + + @Override + public void configure() { + region = DynamicRegion.create(13103); + setRegionBase(); + registerRegion(region.getId()); + } + + } + + /** + * The use with handler on the chest. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BedabinKeyHandler extends UseWithHandler { + + /** + * Constructs a new {@code BedabinKeyHandler} {@code Object}. + */ + public BedabinKeyHandler() { + super(TouristTrap.BEDABIN_KEY.getId()); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(2677, OBJECT_TYPE, this); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + player.getDialogueInterpreter().open(831, RegionManager.getNpc(player.getLocation(), 831, 16)); + return true; + } + + } + + /** + * The barrel dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BarrelDialogue extends DialoguePlugin { + + /** + * The scenery barrel. + */ + private Scenery barrel; + + /** + * The quest. + */ + private Quest quest; + + /** + * Constructs a new {@code BarrelDialogue} {@code Object}. + */ + public BarrelDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code BarrelDialogue} {@code Object}. + * + * @param player the player. + */ + public BarrelDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new BarrelDialogue(player); + } + + @Override + public boolean open(Object... args) { + barrel = (Scenery) args[0]; + quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if ((quest.getStage(player) == 70 || quest.getStage(player) == 72) && !player.hasItem(TouristTrap.ANNA_BARREL)) { + interpreter.sendDialogue("You search the barrels and find Ana."); + stage = 400; + return true; + } + if (player.getInventory().containsItem(TouristTrap.BARREL)) { + player.getPacketDispatch().sendMessage("You can only manage to have one of these at a time."); + end(); + return true; + } + interpreter.sendItemMessage(TouristTrap.BARREL, "This barrel is quite big. but you may be able to carry one. Would you like to take one?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 400:// finding anna. + interpreter.sendDialogues(823, null, "Let me out!"); + stage++; + break; + case 401: + if (!player.getInventory().hasSpaceFor(TouristTrap.ANNA_BARREL)) { + end(); + return true; + } + player.getPacketDispatch().sendMessage("You pick up Ana in a Barrel."); + player.getInventory().add(TouristTrap.ANNA_BARREL); + end(); + break; + case 402: + end(); + break; + case 0: + options("Yeah, cool!", "No thanks."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + interpreter.sendItemMessage(TouristTrap.BARREL, "You take the barrel, it's not heavy, just awkward."); + stage = 3; + break; + case 2: + end(); + break; + } + break; + case 3: + end(); + player.getInventory().add(TouristTrap.BARREL, player); + SceneryBuilder.remove(barrel); + GameWorld.getPulser().submit(new Pulse(40) { + @Override + public boolean pulse() { + SceneryBuilder.add(barrel); + return true; + } + }); + break; + + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("barrel dialogue")}; + } + + } + + /** + * The use with handler for the bedabin anvil. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BedabinAnvilHandler extends UseWithHandler { + + /** + * Constructs a new {@code BedabinAnvilHandler} {@code Object}. + */ + public BedabinAnvilHandler() { + super(2349); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(2672, OBJECT_TYPE, this); + ClassScanner.definePlugin(new PrototypeDartHandler()); + ClassScanner.definePlugin(new BedabinAnvilDialogue()); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if (quest.getStage(player) == 54 && player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { + player.getDialogueInterpreter().open("bedabin-anvil"); + return true; + } else { + player.getPacketDispatch().sendMessage("You need technical plans in order to do this."); + } + return true; + } + + /** + * The handler used to handle the anna barrel on the winch. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class AnnaWinchHandler extends UseWithHandler { + + /** + * Constructs a new {@code AnnaWinchHandler} {@code Object}. + */ + public AnnaWinchHandler() { + super(TouristTrap.ANNA_BARREL.getId()); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(18951, OBJECT_TYPE, this); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + final Quest quest = player.getQuestRepository().getQuest(Quests.THE_TOURIST_TRAP); + if (!event.getUsedWith().getLocation().equals(Location.create(3292, 9423, 0))) { + return false; + } + if (quest.getStage(player) == 70) { + player.getDialogueInterpreter().open("winch dialogue", true); + return true; + } + return false; + } + + } + + /** + * The prototype dart creation handler. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class PrototypeDartHandler extends UseWithHandler { + + /** + * Constructs a new {@code PrototypeDartHandler} {@code Object}. + */ + public PrototypeDartHandler() { + super(314); + } + + @Override + public Plugin newInstance(Object arg) { + addHandler(TouristTrap.PROTOTYPE_DART_TIP.getId(), ITEM_TYPE, this); + ClassScanner.definePlugin(new ProtoTypeDialogue()); + return this; + } + + @Override + public boolean handle(NodeUsageEvent event) { + final Player player = event.getPlayer(); + player.getDialogueInterpreter().open("prototype dart"); + return true; + } + + /** + * The prototype dialogue plugin. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class ProtoTypeDialogue extends DialoguePlugin { + + /** + * The feathers item. + */ + private static final Item FEATHERS = new Item(314, 10); + + /** + * Constructs a new {@code ProtoTypeDialogue} {@code Object}. + * + * @param player the player. + */ + public ProtoTypeDialogue(final Player player) { + super(player); + } + + /** + * Constructs a new {@code ProtoTypeDialogue} {@code Object}. + */ + public ProtoTypeDialogue() { + /** + * empty. + */ + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new ProtoTypeDialogue(player); + } + + @Override + public boolean open(Object... args) { + if (!player.getInventory().containsItem(FEATHERS)) { + interpreter.sendDialogue("You need 10 feathers in order to do this."); + stage = 10; + return false; + } + interpreter.sendItemMessage(314, "You try to attach feathers to the bronze dart tip."); + stage = 1; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 1: + interpreter.sendDialogue("Following the plans is tricky, but you persevere."); + stage++; + break; + case 2: + interpreter.sendItemMessage(TouristTrap.PROTOTYPE_DART, "You successfully attach the feathers to the dart tip."); + stage++; + break; + case 3: + player.getInventory().remove(FEATHERS, TouristTrap.PROTOTYPE_DART_TIP); + player.getInventory().add(TouristTrap.PROTOTYPE_DART); + end(); + break; + case 4: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("prototype dart")}; + } + + } + } + + /** + * The bedabin dialogue plugin handler. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class BedabinAnvilDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. + */ + public BedabinAnvilDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code BedabinAnvilDialogue} {@code Object}. + * + * @param player the player. + */ + public BedabinAnvilDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new BedabinAnvilDialogue(player); + } + + @Override + public boolean open(Object... args) { + if (!player.getInventory().containsItem(TouristTrap.TECHNICAL_PLANS)) { + player.getPacketDispatch().sendMessage("You need the plans to do this."); + return false; + } + player.getDialogueInterpreter().sendItemMessage(TouristTrap.TECHNICAL_PLANS, "Do you want to follow the technical plans ?"); + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + options("Yes. I'd like to try.", "No, not just yet."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + end(); + player.getPulseManager().run(new ProtoTypePulse(player)); + break; + case 2: + end(); + break; + } + break; + } + return true; + } + + /** + * The skill pulse used to make a prototype dart. + * + * @author 'Vexia + * @version 1.0 + */ + public static final class ProtoTypePulse extends SkillPulse { + + /** + * The hammer item. + */ + private static final Item HAMMER = new Item(2347); + + /** + * The ticks passed. + */ + private int ticks; + + /** + * Constructs a new {@code ProtoTypePulse} {@code Object}. + * + * @param player the player. + */ + public ProtoTypePulse(Player player) { + super(player, null); + } + + @Override + public boolean checkRequirements() { + if (!player.getInventory().hasSpaceFor(TouristTrap.PROTOTYPE_DART_TIP)) { + player.getPacketDispatch().sendMessage("Not enough inventory space."); + return false; + } + if (!player.getInventory().containsItem(HAMMER)) { + player.getPacketDispatch().sendMessage("You need a hammer in order to work metal with."); + return false; + } + return player.getInventory().containsItem(Bar.BRONZE.getProduct()); + } + + @Override + public void animate() { + if (ticks % 4 == 0) { + player.animate(Animation.create(898)); + } + } + + @Override + public boolean reward() { + if (++ticks % 4 != 0) { + return false; + } + if (ticks == 4) { + player.getDialogueInterpreter().sendPlainMessage(true, "You begin experimenting in forging the weapon..."); + } else if (ticks == 8) { + player.getInventory().remove(Bar.BRONZE.getProduct()); + player.getInventory().add(TouristTrap.PROTOTYPE_DART_TIP); + player.getDialogueInterpreter().sendItemMessage(TouristTrap.PROTOTYPE_DART_TIP, "You follow the plans carefully, and after some careful", "work, you finally manage to forge a sharp, pointed...", "dart tip."); + return true; + } + return false; + } + + @Override + public void stop() { + super.stop(); + } + + } + + @Override + public int[] getIds() { + return new int[]{DialogueInterpreter.getDialogueKey("bedabin-anvil")}; + } + + } + } } diff --git a/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java b/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java index b8e504953..b11c6e164 100644 --- a/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java +++ b/Server/src/main/content/region/kandarin/seers/handlers/RangingGuildPlugin.java @@ -45,1168 +45,1168 @@ import static core.api.ContentAPIKt.*; @Initializable public final class RangingGuildPlugin extends OptionHandler { - @Override - public Plugin newInstance(Object arg) throws Throwable { - SceneryDefinition.forId(2514).getHandlers().put("option:open", this); - SceneryDefinition.forId(2511).getHandlers().put("option:climb-up", this); - SceneryDefinition.forId(2512).getHandlers().put("option:climb-down", this); - SceneryDefinition.forId(2513).getHandlers().put("option:fire-at", this); - new RangingGuildDoorman().init(); - new GuardDialogue().init(); - new LeatherWorkerDialogue().init(); - new ArmourSalesman().init(); - new TribalWeaponSalesman().init(); - new BowArrowSalesman().init(); - new WarningInterface().newInstance(arg); - new CompetitionJudge().init(); - ClassScanner.definePlugin(new TowerArcher()); - return this; - } - - @Override - public boolean handle(Player player, Node node, String option) { - final int id = node instanceof Scenery ? ((Scenery) node).getId() : 0; - switch (option) { - case "fire-at": - if (player.getArcheryTargets() <= 0) { - player.getDialogueInterpreter().sendDialogues(693, null, "Sorry, you may only use the targets for the", "competition, not for practicing."); - return true; - } - if (!player.getEquipment().containsItem(new Item(882)) - || player.getEquipment().get(EquipmentContainer.SLOT_WEAPON) == null - || (!player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("shortbow") - && !player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("longbow"))) { - player.sendMessage("You must have bronze arrows and a bow equipped."); - return true; - } - player.getPulseManager().run(new ArcheryCompetitionPulse(player, (Scenery) node)); - break; - case "open": - switch (id) { - case 2514: - if (player.getLocation().getY() >= 3438) { - if (player.getSkills().getStaticLevel(Skills.RANGE) < 40) { - player.getDialogueInterpreter().sendDialogue("You need a Ranging level of 40 to enter here."); - return true; - } - } - DoorActionHandler.handleAutowalkDoor(player, (Scenery) node, player.getLocation().getY() >= 3438 ? Location.create(2659, 3437, 0) : Location.create(2657, 3439, 0)); - break; - } - break; - case "climb-up": - switch (id) { - case 2511: - player.setAttribute("ladder", node); - player.getInterfaceManager().open(new Component(564)); - break; - } - break; - case "climb-down": - switch (id) { - case 2512: - ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 0)); - break; - } - break; - } - return true; - } - - @Override - public Location getDestination(Node node, Node n) { - if (n instanceof Scenery) { - if (((Scenery) n).getDefinition().hasAction("open")) { - if (((Scenery) n).getId() == 2514) { - if (node.getLocation().getY() >= 3438) { - return Location.create(2657, 3439, 0); - } else { - return Location.create(2659, 3437, 0); - } - } - return DoorActionHandler.getDestination((Player) node, (Scenery) n); - } - if (((Scenery) n).getId() == 2513) - return Location.create(2673, 3420, 0); - } - return null; - } - - /** - * Represents the dialogue used for the ranging guild door man. - * - * @author 'Vexia - * @version 1.0 - */ - public class RangingGuildDoorman extends DialoguePlugin { - - /** - * Constructs a new {@code RangingGuildDoorman} {@code Object}. - */ - public RangingGuildDoorman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code RangingGuildDoorman} {@code Object}. - * - * @param player the player. - */ - public RangingGuildDoorman(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new RangingGuildDoorman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello there."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Greetings. If you are an experienced archer, you may", "want to visit the guild here..."); - stage = 1; - break; - case 1: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{679}; - } - } - - /** - * Represents the tribal weapon salseman dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class TribalWeaponSalesman extends DialoguePlugin { - - /** - * Constructs a new {@code TribalWeaponSalesman} {@code Object}. - */ - public TribalWeaponSalesman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code TribalWeaponSalesman} {@code Object}. - * - * @param player the player. - */ - public TribalWeaponSalesman(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new TribalWeaponSalesman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - player("Hello there."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("Greetings, traveller. Are you interested in any throwing", "weapons?"); - stage = 1; - break; - case 1: - options("Yes I am.", "Not really."); - stage = 2; - break; - case 2: - switch (buttonId) { - case 1: - player("Yes I am."); - stage = 10; - break; - case 2: - player("Not really."); - stage = 20; - break; - } - break; - case 10: - npc("That is a good thing."); - stage = 11; - break; - case 11: - end(); - npc.openShop(player); - break; - case 20: - npc("No bother to me."); - stage = 21; - break; - case 21: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{692}; - } - - } - - /** - * Represents the guard dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class GuardDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code GuardDialogue} {@code Object}. - */ - public GuardDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code GuardDialogue} {@code Object}. - * - * @param player the player. - */ - public GuardDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new GuardDialogue(player); - } - - @Override - public boolean open(Object... args) { - player("Hello there."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("Greetings, traveller. Enjoy the time at the Ranging", "Guild."); - stage = 1; - break; - case 1: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{678}; - } - - } - - /** - * Represents the leather workers dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class LeatherWorkerDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. - */ - public LeatherWorkerDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. - * - * @param player the player. - */ - public LeatherWorkerDialogue(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new LeatherWorkerDialogue(player); - } - - @Override - public boolean open(Object... args) { - player("Hello."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("Can I help you?"); - stage = 1; - break; - case 1: - options("What do you do here?", "No thanks."); - stage = 2; - break; - case 2: - switch (buttonId) { - case 1: - player("What do you do here?"); - stage = 10; - break; - case 2: - player("No thanks."); - stage = 20; - break; - } - break; - case 10: - npc("Well, I can cure plain cowhides into pieces of leather", "ready for crafting."); - stage = 11; - break; - case 11: - npc("I work with ordinary, hard or dragonhide leather and", "also snakeskin."); - stage = 12; - break; - case 12: - end(); - TanningProduct.open(player, 680); - break; - case 20: - npc("Suit yourself."); - stage = 21; - break; - case 21: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{680}; - } - - } - - /** - * Represents the armour salesman dialogue. - * - * @author 'Vexia - * @version 1.0 - */ - public final class ArmourSalesman extends DialoguePlugin { - - /** - * Constructs a new {@code ArmourSalesman} {@code Object}. - */ - public ArmourSalesman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code ArmourSalesman} {@code Object}. - * - * @param player the player. - */ - public ArmourSalesman(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new ArmourSalesman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - player("Good day to you."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("And to you. Can I help you?"); - stage = 1; - break; - case 1: - if (Skillcape.isMaster(player, Skills.RANGE)) { - options("What do you do here?", "I'd like to see what you sell.", "Can I buy a Skillcape of Range?", "I've seen enough, thanks."); - stage = 100; - } else { - options("What do you do here?", "I'd like to see what you sell.", "I've seen enough, thanks."); - stage = 2; - } - break; - case 2: - switch (buttonId) { - case 1: - player("What do you do here?"); - stage = 10; - break; - case 2: - player("I'd like to see what you sell."); - stage = 20; - break; - case 3: - player("I've seen enough, thanks."); - stage = 30; - break; - } - break; - case 10: - npc("I am a supplier of leather armours and accessories. Ask", "and I will tell you what I know."); - stage = 11; - break; - case 11: - options("Tell me about your armours.", "Tell me about your accessories.", "I've seen enough, thanks."); - stage = 12; - break; - case 12: - switch (buttonId) { - case 1: - player("Tell me about your armours."); - stage = 13; - break; - case 2: - player("Tell me about your accessories."); - stage = 15; - break; - case 3: - player("I've seen enough, thanks."); - stage = 30; - break; - } - break; - case 13: - npc("I have normal, studded and hard types."); - stage = 14; - break; - case 14: - case 31: - case 105: - end(); - break; - case 15: - npc("Ah yes we have a new range of accessories in stock.", "Essential items for an archer like you."); - stage = 14; - break; - case 20: - npc("Indeed, cast your eyes on my wares, adventurer."); - stage = 21; - break; - case 21: - end(); - npc.openShop(player); - break; - case 30: - npc("Very good, adventurer."); - stage = 31; - break; - case 100: - switch (buttonId) { - case 1: - player("What do you do here?"); - stage = 10; - break; - case 2: - player("I'd like to see what you sell."); - stage = 20; - break; - case 3: - player("Can I buy a Skillcape of Range?"); - stage = 101; - break; - case 4: - player("I've seen enough, thanks."); - stage = 30; - break; - } - break; - case 101: - npc("Certainly! Right when you give me 99000 coins."); - stage = 102; - break; - case 102: - options("Okay, here you go.", "No, thanks."); - stage = 103; - break; - case 103: - switch (buttonId) { - case 1: - player("Okay, here you go."); - stage = 104; - break; - case 2: - end(); - break; - } - break; - case 104: - if (Skillcape.purchase(player, Skills.RANGE)) { - npc("There you go! Enjoy."); - } - stage = 105; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{682}; - } - - } - - /** - * Represents the dialogue plugin used for the bow and arrow salesman. - * - * @author 'Vexia - * @version 1.0 - */ - public final class BowArrowSalesman extends DialoguePlugin { - - /** - * Constructs a new {@code BowArrowSalesman} {@code Object}. - */ - public BowArrowSalesman() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code BowArrowSalesman} {@code Object}. - * - * @param player the player. - */ - public BowArrowSalesman(final Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new BowArrowSalesman(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - player("Hello."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - npc("A fair day, traveller. Would you like to see my wares?"); - stage = 1; - break; - case 1: - options("Yes please.", "No thanks."); - stage = 2; - break; - case 2: - switch (buttonId) { - case 1: - end(); - npc.openShop(player); - - break; - case 2: - end(); - break; - } - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{683}; - } - - } - - /** - * Represents the waring interface used in the guild. - * - * @author 'Vexia - * @version 1.0 - */ - public final class WarningInterface extends ComponentPlugin { - - @Override - public Plugin newInstance(Object arg) throws Throwable { - ComponentDefinition.forId(564).setPlugin(this); - return this; - } - - @Override - public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) { - switch (button) { - case 17: - ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 2)); - player.getInterfaceManager().close(); - List npcs = RegionManager.getLocalNPCs(Location.create(2668, 3427, 2)); - String dir = ""; - for (NPC n : npcs) { - if (n.getId() >= 684 && n.getId() <= 687) { - switch (n.getId()) { - case 684: - dir = "north"; - break; - case 685: - dir = "east"; - break; - case 686: - dir = "south"; - break; - case 687: - dir = "west"; - break; - } - n.sendChat("The " + dir + " tower is occupied, get them!"); - } - } - break; - case 18: - player.getInterfaceManager().close(); - break; - } - return true; - } - - } - - /** - * Represents the competition judge. - * - * @author afaroutdude - */ - public final class CompetitionJudge extends DialoguePlugin { - - /** - * Constructs a new {@code CompetitionJudge} {@code Object}. - * - * @param player the player. - */ - public CompetitionJudge(final Player player) { - super(player); - } - - /** - * Constructs a new {@code CompetitionJudge} {@code Object}. - */ - public CompetitionJudge() { - /** - * empty. - */ - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new CompetitionJudge(player); - } - - @Override - public boolean open(Object... args) { - if (player.getInventory().getAmount(1464) >= 1000 - && !player.getAchievementDiaryManager().hasCompletedTask(DiaryType.SEERS_VILLAGE, 1, 7)) { - npc("Wow! I see that you've got yourself a whole load of ", "archery tickets. Well done!"); - player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 7); - stage = -1; - } else if (player.getArcheryTargets() > 0) { - npc("Hello again, do you need reminding of the rules?"); - stage = 20; - } else if (player.getArcheryTotal() == 0) { - npc("Hello there, would you like to take part in the", - "archery competition? It only costs 200 coins to", - "enter."); - stage = 0; - } else { - int reward = player.getArcheryTotal() / 10; - npc("Well done. Your score is: " + player.getArcheryTotal() + ".", - "For that score you will receive " + reward + " Archery tickets."); - player.setArcheryTargets(-1); - player.setArcheryTotal(0); - if (!player.getInventory().add(new Item(1464, reward))) { - player.getBank().add(new Item(1464, reward)); - player.sendMessage("Your reward was sent to your bank."); - } - stage = 999; - } - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 999: - end(); - break; - case -1: - if (player.getArcheryTargets() > 0) { - npc("Hello again, do you need reminding of the rules?"); - stage = 20; - } else if (player.getArcheryTotal() == 0) { - npc("Hello there, would you like to take part in the", - "archery competition? It only costs 200 coins to", - "enter."); - stage = 0; - } else { - int reward = player.getArcheryTotal() / 10; - npc("Well done. Your score is: " + player.getArcheryTotal() + ".", - "For that score you will receive " + reward + " Archery tickets."); - if (!player.getInventory().add(new Item(1464, reward))) { - player.getBank().add(new Item(1464, reward)); - player.sendMessage("Your reward was sent to your bank."); - } - stage = 999; - } - break; - case 0: - options("Sure, I'll give it a go.", "What are the rules?", "No thanks."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - player("Sure, I'll give it a go."); - stage = 2; - break; - case 2: - player("What are the rules?"); - stage = 5; - break; - case 3: - player("No thanks."); - stage = 999; - break; - } - break; - case 2: - npc("Great! That will be 200 coins then please."); - stage++; - break; - case 3: - if (player.getInventory().getAmount(995) < 200) { - player("Oops, I don't have enough coins on me..."); - stage++; - } else { - end(); - player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); - player.getInventory().remove(new Item(995, 200)); - player.getInventory().add(new Item(882, 10)); - player.setArcheryTargets(10); - player.setArcheryTotal(0); - } - break; - case 4: - npc("Never mind, come back when you've got enough."); - stage = 999; - break; - case 5: - case 22: - npc("The rules are very simple:"); - stage++; - break; - case 6: - case 23: - npc("You're given 10 shots at the targets, for each hit", "you will receive points. At the end you'll be", "rewarded 1 ticket for every 10 points."); - stage++; - break; - case 7: - npc("The tickets can be exchanged for goods from our stores.", "Do you want to give it a go? Only 200 coins."); - stage++; - break; - case 8: - options("Sure, I'll give it a go.", "No thanks."); - stage++; - break; - case 9: - switch (buttonId) { - case 1: - player("Sure, I'll give it a go."); - stage = 2; - break; - case 3: - player("No thanks."); - stage = 999; - break; - } - break; - case 20: - int arrows = player.getInventory().getAmount(Items.BRONZE_ARROW_882) - + player.getEquipment().getAmount(Items.BRONZE_ARROW_882); - if (arrows < 1) { - player("Well, I actually don't have any more arrows. Could I", "get some more?"); - stage = 25; - } else { - options("Yes please.", "No thanks, I've got it.", "How am I doing so far?"); - stage++; - } - break; - case 21: - switch (buttonId) { - case 1: - player("Yes please."); - stage++; - break; - case 2: - player("No thanks, I've got it."); - stage = 30; - break; - case 3: - player("How am I doing so far?"); - stage = 40; - break; - } - break; - case 24: - npc("The tickets can be exchanged for goods from our stores.", "Good Luck!"); - stage = 999; - break; - case 25: - npc("Ok, but it'll cost you 100 coins."); - stage++; - break; - case 26: - options("Sure, I'll take some.", "No thanks."); - stage++; - break; - case 27: - switch (buttonId) { - case 1: - player("Sure, I'll take some."); - stage++; - break; - case 2: - player("No thanks."); - stage = 999; - break; - } - break; - case 28: - if (player.getInventory().getAmount(995) < 100) { - player("Oops, I don't have enough coins on me..."); - stage++; - } else { - end(); - player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); - player.getInventory().remove(new Item(995, 100)); - player.getInventory().add(new Item(882, 10)); - } - break; - case 30: - npc("Glad to hear it, good luck!"); - stage = 999; - break; - case 40: - String msg; - if (player.getArcheryTotal() <= 0) { - msg = "You haven't started yet."; - } else if (player.getArcheryTotal() <= 80) { - msg = "Not bad, keep going."; - } else { - msg = "You're pretty good, keep it up."; - } - npc("So far your score is: " + player.getArcheryTotal(), msg); - stage = 999; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{693}; - } - - } - - /** - * Represents the tower advisors. - * - * @author afaroutdude - */ - public final class TowerAdvisor extends DialoguePlugin { - - /** - * Constructs a new {@code TowerAdvisor} {@code Object}. - * - * @param player the player. - */ - public TowerAdvisor(final Player player) { - super(player); - } - - /** - * Constructs a new {@code TowerAdvisor} {@code Object}. - */ - public TowerAdvisor() { - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new TowerAdvisor(player); - } - - @Override - public boolean open(Object... args) { - player("Hello there, what do you do here?"); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 999: - end(); - case 0: - npc("Hi. We are in charge of this practice area."); - stage++; - break; - case 1: - player("This is a practice area?"); - break; - case 2: - npc("Surrounding us are four towers. Each tower contains", - "trained archers of a different level. You'll notice", - "it's quite a distance, so you'll need a longbow."); - stage++; - break; - case 3: - int rangeLevel = player.getSkills().getLevel(Skills.RANGE); - if (rangeLevel < 50) { // north - npc("As you're not very skilled, I advise you to practice", - "on the north tower. That'll provide the best", - "challenge for you."); - } else if (rangeLevel < 60) { // east - npc("You appear to be somewhat skilled with a bow, so I", - "advise you to practice on the south tower. That'll", - "provide the best challenge for you."); - } else if (rangeLevel < 70) { // south - npc("You appear to be fairly skilled with a bow, so I", - "advise you to practice on the south tower. That'll", - "provide the best challenge for you."); - } else { // west - npc("Looks like you're very skilled, so I advise you to", - "practice on the west tower. That'll provide the best", - "challenge for you."); - } - stage = 999; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[]{684, 685, 686, 687}; - } - - } - - - /** - * Represents all the tower archers - * - * @author afaroutdude - */ - public final class TowerArcher extends AbstractNPC { - - public TowerArcher() { - super(-1, null); - } - public TowerArcher(int id, Location location) { - super(id, location); - } - - - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new TowerArcher(id, location); - } - - @Override - public int[] getIds() { - return new int[]{688, 689, 690, 691}; - } - } - - /** - * Represents the archery target pulse. - * - * @author Jamix77 - */ - public static final class ArcheryCompetitionPulse extends Pulse { - - /** - * Represents the player instance. - */ - private final Player player; - - /** - * Represents the scenery. - */ - private final Scenery object; - - /** - * Constructs a new {@code ArcheryCompetitionPulse} {@code Object}. - * - * @param player the player. - * @param object the object. - */ - public ArcheryCompetitionPulse(final Player player, final Scenery object) { - super(1, player, object); - this.player = player; - this.object = object; - } - - private void showInterface(int points, int arrowsLeft, int target, String msg) { - player.getInterfaceManager().openComponent(325); - setVarp(player, 156, 11 - arrowsLeft); - setVarp(player, 157, points); - setVarp(player, 158, target); - player.getPacketDispatch().sendString(msg, 325, 32); - } - - @Override - public boolean pulse() { - if (player.getArcheryTargets() <= 0) { - return true; - } - if (getDelay() == 1) { - setDelay(player.getProperties().getAttackSpeed()); - } - if (player.getEquipment().remove(new Item(Items.BRONZE_ARROW_882, 1))) { - Projectile p = Ammunition.get(Items.BRONZE_ARROW_882).getProjectile().transform(player, object.getLocation()); - p.setEndLocation(object.getLocation()); - p.setEndHeight(25); - p.send(); - player.animate(new Animation(426)); - player.lock(getDelay()); - - int level = player.getSkills().getLevel(Skills.RANGE); - int bonus = player.getProperties().getBonuses()[14]; - double prayer = 1.0; - prayer += player.getPrayer().getSkillBonus(Skills.RANGE); - double cumulativeStr = Math.floor(level * prayer); - /*if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_RANGE_ACCURATE) { - cumulativeStr += 3; - } else if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_LONG_RANGE) { - cumulativeStr += 1; - }*/ - cumulativeStr *= 1.0; - int hit = (int) ((14 + cumulativeStr + (bonus / 8) + ((cumulativeStr * bonus) * 0.016865))) / 10 + 1; - hit = hit + RandomFunction.randomSign(RandomFunction.random(3)); - - int target = Math.max(0, 13 - hit); - int points = 0; - String msg = ""; - switch (target) { - case 0: - points = 100; - msg = "Bulls-Eye!"; - break; - case 1: - points = 50; - msg = "Hit Yellow!"; - break; - case 2: - case 3: - case 4: - points = 30; - msg = "Hit Red!"; - break; - case 5: - case 6: - case 7: - case 8: - points = 20; - msg = "Hit Blue!"; - break; - case 9: - case 10: - points = 10; - msg = "Hit Black!"; - break; - case 11: - case 12: - case 13: - points = 0; - msg = "Missed!"; - break; - } - int xp = points / 2; - - player.getSkills().addExperience(Skills.RANGE, xp, true); - player.setArcheryTotal(player.getArcheryTotal() + points); - player.setArcheryTargets(player.getArcheryTargets() - 1); - player.debug("Hit: " + hit); - player.debug("You have " + player.getArcheryTargets() + " targets left."); - player.debug("You have " + player.getArcheryTotal() + " score."); - - showInterface(player.getArcheryTotal(), player.getArcheryTargets(), target, msg); - - return true; //player.getArcheryTargets() <= 0; - } else { - return true; - } - } - - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + SceneryDefinition.forId(2514).getHandlers().put("option:open", this); + SceneryDefinition.forId(2511).getHandlers().put("option:climb-up", this); + SceneryDefinition.forId(2512).getHandlers().put("option:climb-down", this); + SceneryDefinition.forId(2513).getHandlers().put("option:fire-at", this); + new RangingGuildDoorman().init(); + new GuardDialogue().init(); + new LeatherWorkerDialogue().init(); + new ArmourSalesman().init(); + new TribalWeaponSalesman().init(); + new BowArrowSalesman().init(); + new WarningInterface().newInstance(arg); + new CompetitionJudge().init(); + ClassScanner.definePlugin(new TowerArcher()); + return this; + } + + @Override + public boolean handle(Player player, Node node, String option) { + final int id = node instanceof Scenery ? ((Scenery) node).getId() : 0; + switch (option) { + case "fire-at": + if (player.getArcheryTargets() <= 0) { + player.getDialogueInterpreter().sendDialogues(693, null, "Sorry, you may only use the targets for the", "competition, not for practicing."); + return true; + } + if (!player.getEquipment().containsItem(new Item(882)) + || player.getEquipment().get(EquipmentContainer.SLOT_WEAPON) == null + || (!player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("shortbow") + && !player.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getName().toLowerCase().contains("longbow"))) { + player.sendMessage("You must have bronze arrows and a bow equipped."); + return true; + } + player.getPulseManager().run(new ArcheryCompetitionPulse(player, (Scenery) node)); + break; + case "open": + switch (id) { + case 2514: + if (player.getLocation().getY() >= 3438) { + if (player.getSkills().getStaticLevel(Skills.RANGE) < 40) { + player.getDialogueInterpreter().sendDialogue("You need a Ranging level of 40 to enter here."); + return true; + } + } + DoorActionHandler.handleAutowalkDoor(player, (Scenery) node, player.getLocation().getY() >= 3438 ? Location.create(2659, 3437, 0) : Location.create(2657, 3439, 0)); + break; + } + break; + case "climb-up": + switch (id) { + case 2511: + player.setAttribute("ladder", node); + player.getInterfaceManager().open(new Component(564)); + break; + } + break; + case "climb-down": + switch (id) { + case 2512: + ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 0)); + break; + } + break; + } + return true; + } + + @Override + public Location getDestination(Node node, Node n) { + if (n instanceof Scenery) { + if (((Scenery) n).getDefinition().hasAction("open")) { + if (((Scenery) n).getId() == 2514) { + if (node.getLocation().getY() >= 3438) { + return Location.create(2657, 3439, 0); + } else { + return Location.create(2659, 3437, 0); + } + } + return DoorActionHandler.getDestination((Player) node, (Scenery) n); + } + if (((Scenery) n).getId() == 2513) + return Location.create(2673, 3420, 0); + } + return null; + } + + /** + * Represents the dialogue used for the ranging guild door man. + * + * @author 'Vexia + * @version 1.0 + */ + public class RangingGuildDoorman extends DialoguePlugin { + + /** + * Constructs a new {@code RangingGuildDoorman} {@code Object}. + */ + public RangingGuildDoorman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code RangingGuildDoorman} {@code Object}. + * + * @param player the player. + */ + public RangingGuildDoorman(Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new RangingGuildDoorman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello there."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Greetings. If you are an experienced archer, you may", "want to visit the guild here..."); + stage = 1; + break; + case 1: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{679}; + } + } + + /** + * Represents the tribal weapon salseman dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class TribalWeaponSalesman extends DialoguePlugin { + + /** + * Constructs a new {@code TribalWeaponSalesman} {@code Object}. + */ + public TribalWeaponSalesman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code TribalWeaponSalesman} {@code Object}. + * + * @param player the player. + */ + public TribalWeaponSalesman(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new TribalWeaponSalesman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + player("Hello there."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("Greetings, traveller. Are you interested in any throwing", "weapons?"); + stage = 1; + break; + case 1: + options("Yes I am.", "Not really."); + stage = 2; + break; + case 2: + switch (buttonId) { + case 1: + player("Yes I am."); + stage = 10; + break; + case 2: + player("Not really."); + stage = 20; + break; + } + break; + case 10: + npc("That is a good thing."); + stage = 11; + break; + case 11: + end(); + npc.openShop(player); + break; + case 20: + npc("No bother to me."); + stage = 21; + break; + case 21: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{692}; + } + + } + + /** + * Represents the guard dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class GuardDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code GuardDialogue} {@code Object}. + */ + public GuardDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code GuardDialogue} {@code Object}. + * + * @param player the player. + */ + public GuardDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new GuardDialogue(player); + } + + @Override + public boolean open(Object... args) { + player("Hello there."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("Greetings, traveller. Enjoy the time at the Ranging", "Guild."); + stage = 1; + break; + case 1: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{678}; + } + + } + + /** + * Represents the leather workers dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class LeatherWorkerDialogue extends DialoguePlugin { + + /** + * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. + */ + public LeatherWorkerDialogue() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code LeatherWorkerDialogue} {@code Object}. + * + * @param player the player. + */ + public LeatherWorkerDialogue(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new LeatherWorkerDialogue(player); + } + + @Override + public boolean open(Object... args) { + player("Hello."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("Can I help you?"); + stage = 1; + break; + case 1: + options("What do you do here?", "No thanks."); + stage = 2; + break; + case 2: + switch (buttonId) { + case 1: + player("What do you do here?"); + stage = 10; + break; + case 2: + player("No thanks."); + stage = 20; + break; + } + break; + case 10: + npc("Well, I can cure plain cowhides into pieces of leather", "ready for crafting."); + stage = 11; + break; + case 11: + npc("I work with ordinary, hard or dragonhide leather and", "also snakeskin."); + stage = 12; + break; + case 12: + end(); + TanningProduct.open(player, 680); + break; + case 20: + npc("Suit yourself."); + stage = 21; + break; + case 21: + end(); + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{680}; + } + + } + + /** + * Represents the armour salesman dialogue. + * + * @author 'Vexia + * @version 1.0 + */ + public final class ArmourSalesman extends DialoguePlugin { + + /** + * Constructs a new {@code ArmourSalesman} {@code Object}. + */ + public ArmourSalesman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code ArmourSalesman} {@code Object}. + * + * @param player the player. + */ + public ArmourSalesman(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new ArmourSalesman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + player("Good day to you."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("And to you. Can I help you?"); + stage = 1; + break; + case 1: + if (Skillcape.isMaster(player, Skills.RANGE)) { + options("What do you do here?", "I'd like to see what you sell.", "Can I buy a Skillcape of Range?", "I've seen enough, thanks."); + stage = 100; + } else { + options("What do you do here?", "I'd like to see what you sell.", "I've seen enough, thanks."); + stage = 2; + } + break; + case 2: + switch (buttonId) { + case 1: + player("What do you do here?"); + stage = 10; + break; + case 2: + player("I'd like to see what you sell."); + stage = 20; + break; + case 3: + player("I've seen enough, thanks."); + stage = 30; + break; + } + break; + case 10: + npc("I am a supplier of leather armours and accessories. Ask", "and I will tell you what I know."); + stage = 11; + break; + case 11: + options("Tell me about your armours.", "Tell me about your accessories.", "I've seen enough, thanks."); + stage = 12; + break; + case 12: + switch (buttonId) { + case 1: + player("Tell me about your armours."); + stage = 13; + break; + case 2: + player("Tell me about your accessories."); + stage = 15; + break; + case 3: + player("I've seen enough, thanks."); + stage = 30; + break; + } + break; + case 13: + npc("I have normal, studded and hard types."); + stage = 14; + break; + case 14: + case 31: + case 105: + end(); + break; + case 15: + npc("Ah yes we have a new range of accessories in stock.", "Essential items for an archer like you."); + stage = 14; + break; + case 20: + npc("Indeed, cast your eyes on my wares, adventurer."); + stage = 21; + break; + case 21: + end(); + npc.openShop(player); + break; + case 30: + npc("Very good, adventurer."); + stage = 31; + break; + case 100: + switch (buttonId) { + case 1: + player("What do you do here?"); + stage = 10; + break; + case 2: + player("I'd like to see what you sell."); + stage = 20; + break; + case 3: + player("Can I buy a Skillcape of Range?"); + stage = 101; + break; + case 4: + player("I've seen enough, thanks."); + stage = 30; + break; + } + break; + case 101: + npc("Certainly! Right when you give me 99000 coins."); + stage = 102; + break; + case 102: + options("Okay, here you go.", "No, thanks."); + stage = 103; + break; + case 103: + switch (buttonId) { + case 1: + player("Okay, here you go."); + stage = 104; + break; + case 2: + end(); + break; + } + break; + case 104: + if (Skillcape.purchase(player, Skills.RANGE)) { + npc("There you go! Enjoy."); + } + stage = 105; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{682}; + } + + } + + /** + * Represents the dialogue plugin used for the bow and arrow salesman. + * + * @author 'Vexia + * @version 1.0 + */ + public final class BowArrowSalesman extends DialoguePlugin { + + /** + * Constructs a new {@code BowArrowSalesman} {@code Object}. + */ + public BowArrowSalesman() { + /** + * empty. + */ + } + + /** + * Constructs a new {@code BowArrowSalesman} {@code Object}. + * + * @param player the player. + */ + public BowArrowSalesman(final Player player) { + super(player); + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new BowArrowSalesman(player); + } + + @Override + public boolean open(Object... args) { + npc = (NPC) args[0]; + player("Hello."); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 0: + npc("A fair day, traveller. Would you like to see my wares?"); + stage = 1; + break; + case 1: + options("Yes please.", "No thanks."); + stage = 2; + break; + case 2: + switch (buttonId) { + case 1: + end(); + npc.openShop(player); + + break; + case 2: + end(); + break; + } + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{683}; + } + + } + + /** + * Represents the waring interface used in the guild. + * + * @author 'Vexia + * @version 1.0 + */ + public final class WarningInterface extends ComponentPlugin { + + @Override + public Plugin newInstance(Object arg) throws Throwable { + ComponentDefinition.forId(564).setPlugin(this); + return this; + } + + @Override + public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) { + switch (button) { + case 17: + ClimbActionHandler.climb(player, null, Location.create(2668, 3427, 2)); + player.getInterfaceManager().close(); + List npcs = RegionManager.getLocalNPCs(Location.create(2668, 3427, 2)); + String dir = ""; + for (NPC n : npcs) { + if (n.getId() >= 684 && n.getId() <= 687) { + switch (n.getId()) { + case 684: + dir = "north"; + break; + case 685: + dir = "east"; + break; + case 686: + dir = "south"; + break; + case 687: + dir = "west"; + break; + } + n.sendChat("The " + dir + " tower is occupied, get them!"); + } + } + break; + case 18: + player.getInterfaceManager().close(); + break; + } + return true; + } + + } + + /** + * Represents the competition judge. + * + * @author afaroutdude + */ + public final class CompetitionJudge extends DialoguePlugin { + + /** + * Constructs a new {@code CompetitionJudge} {@code Object}. + * + * @param player the player. + */ + public CompetitionJudge(final Player player) { + super(player); + } + + /** + * Constructs a new {@code CompetitionJudge} {@code Object}. + */ + public CompetitionJudge() { + /** + * empty. + */ + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new CompetitionJudge(player); + } + + @Override + public boolean open(Object... args) { + if (player.getInventory().getAmount(1464) >= 1000 + && !player.getAchievementDiaryManager().hasCompletedTask(DiaryType.SEERS_VILLAGE, 1, 7)) { + npc("Wow! I see that you've got yourself a whole load of ", "archery tickets. Well done!"); + player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 7); + stage = -1; + } else if (player.getArcheryTargets() > 0) { + npc("Hello again, do you need reminding of the rules?"); + stage = 20; + } else if (player.getArcheryTotal() == 0) { + npc("Hello there, would you like to take part in the", + "archery competition? It only costs 200 coins to", + "enter."); + stage = 0; + } else { + int reward = player.getArcheryTotal() / 10; + npc("Well done. Your score is: " + player.getArcheryTotal() + ".", + "For that score you will receive " + reward + " Archery tickets."); + player.setArcheryTargets(-1); + player.setArcheryTotal(0); + if (!player.getInventory().add(new Item(1464, reward))) { + player.getBank().add(new Item(1464, reward)); + player.sendMessage("Your reward was sent to your bank."); + } + stage = 999; + } + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 999: + end(); + break; + case -1: + if (player.getArcheryTargets() > 0) { + npc("Hello again, do you need reminding of the rules?"); + stage = 20; + } else if (player.getArcheryTotal() == 0) { + npc("Hello there, would you like to take part in the", + "archery competition? It only costs 200 coins to", + "enter."); + stage = 0; + } else { + int reward = player.getArcheryTotal() / 10; + npc("Well done. Your score is: " + player.getArcheryTotal() + ".", + "For that score you will receive " + reward + " Archery tickets."); + if (!player.getInventory().add(new Item(1464, reward))) { + player.getBank().add(new Item(1464, reward)); + player.sendMessage("Your reward was sent to your bank."); + } + stage = 999; + } + break; + case 0: + options("Sure, I'll give it a go.", "What are the rules?", "No thanks."); + stage++; + break; + case 1: + switch (buttonId) { + case 1: + player("Sure, I'll give it a go."); + stage = 2; + break; + case 2: + player("What are the rules?"); + stage = 5; + break; + case 3: + player("No thanks."); + stage = 999; + break; + } + break; + case 2: + npc("Great! That will be 200 coins then please."); + stage++; + break; + case 3: + if (player.getInventory().getAmount(995) < 200) { + player("Oops, I don't have enough coins on me..."); + stage++; + } else { + end(); + player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); + player.getInventory().remove(new Item(995, 200)); + player.getInventory().add(new Item(882, 10)); + player.setArcheryTargets(10); + player.setArcheryTotal(0); + } + break; + case 4: + npc("Never mind, come back when you've got enough."); + stage = 999; + break; + case 5: + case 22: + npc("The rules are very simple:"); + stage++; + break; + case 6: + case 23: + npc("You're given 10 shots at the targets, for each hit", "you will receive points. At the end you'll be", "rewarded 1 ticket for every 10 points."); + stage++; + break; + case 7: + npc("The tickets can be exchanged for goods from our stores.", "Do you want to give it a go? Only 200 coins."); + stage++; + break; + case 8: + options("Sure, I'll give it a go.", "No thanks."); + stage++; + break; + case 9: + switch (buttonId) { + case 1: + player("Sure, I'll give it a go."); + stage = 2; + break; + case 3: + player("No thanks."); + stage = 999; + break; + } + break; + case 20: + int arrows = player.getInventory().getAmount(Items.BRONZE_ARROW_882) + + player.getEquipment().getAmount(Items.BRONZE_ARROW_882); + if (arrows < 1) { + player("Well, I actually don't have any more arrows. Could I", "get some more?"); + stage = 25; + } else { + options("Yes please.", "No thanks, I've got it.", "How am I doing so far?"); + stage++; + } + break; + case 21: + switch (buttonId) { + case 1: + player("Yes please."); + stage++; + break; + case 2: + player("No thanks, I've got it."); + stage = 30; + break; + case 3: + player("How am I doing so far?"); + stage = 40; + break; + } + break; + case 24: + npc("The tickets can be exchanged for goods from our stores.", "Good Luck!"); + stage = 999; + break; + case 25: + npc("Ok, but it'll cost you 100 coins."); + stage++; + break; + case 26: + options("Sure, I'll take some.", "No thanks."); + stage++; + break; + case 27: + switch (buttonId) { + case 1: + player("Sure, I'll take some."); + stage++; + break; + case 2: + player("No thanks."); + stage = 999; + break; + } + break; + case 28: + if (player.getInventory().getAmount(995) < 100) { + player("Oops, I don't have enough coins on me..."); + stage++; + } else { + end(); + player.getPacketDispatch().sendMessage("You pay the judge and he gives you 10 bronze arrows."); + player.getInventory().remove(new Item(995, 100)); + player.getInventory().add(new Item(882, 10)); + } + break; + case 30: + npc("Glad to hear it, good luck!"); + stage = 999; + break; + case 40: + String msg; + if (player.getArcheryTotal() <= 0) { + msg = "You haven't started yet."; + } else if (player.getArcheryTotal() <= 80) { + msg = "Not bad, keep going."; + } else { + msg = "You're pretty good, keep it up."; + } + npc("So far your score is: " + player.getArcheryTotal(), msg); + stage = 999; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{693}; + } + + } + + /** + * Represents the tower advisors. + * + * @author afaroutdude + */ + public final class TowerAdvisor extends DialoguePlugin { + + /** + * Constructs a new {@code TowerAdvisor} {@code Object}. + * + * @param player the player. + */ + public TowerAdvisor(final Player player) { + super(player); + } + + /** + * Constructs a new {@code TowerAdvisor} {@code Object}. + */ + public TowerAdvisor() { + } + + @Override + public DialoguePlugin newInstance(Player player) { + return new TowerAdvisor(player); + } + + @Override + public boolean open(Object... args) { + player("Hello there, what do you do here?"); + stage = 0; + return true; + } + + @Override + public boolean handle(int interfaceId, int buttonId) { + switch (stage) { + case 999: + end(); + case 0: + npc("Hi. We are in charge of this practice area."); + stage++; + break; + case 1: + player("This is a practice area?"); + break; + case 2: + npc("Surrounding us are four towers. Each tower contains", + "trained archers of a different level. You'll notice", + "it's quite a distance, so you'll need a longbow."); + stage++; + break; + case 3: + int rangeLevel = player.getSkills().getLevel(Skills.RANGE); + if (rangeLevel < 50) { // north + npc("As you're not very skilled, I advise you to practice", + "on the north tower. That'll provide the best", + "challenge for you."); + } else if (rangeLevel < 60) { // east + npc("You appear to be somewhat skilled with a bow, so I", + "advise you to practice on the south tower. That'll", + "provide the best challenge for you."); + } else if (rangeLevel < 70) { // south + npc("You appear to be fairly skilled with a bow, so I", + "advise you to practice on the south tower. That'll", + "provide the best challenge for you."); + } else { // west + npc("Looks like you're very skilled, so I advise you to", + "practice on the west tower. That'll provide the best", + "challenge for you."); + } + stage = 999; + break; + } + return true; + } + + @Override + public int[] getIds() { + return new int[]{684, 685, 686, 687}; + } + + } + + + /** + * Represents all the tower archers + * + * @author afaroutdude + */ + public final class TowerArcher extends AbstractNPC { + + public TowerArcher() { + super(-1, null); + } + public TowerArcher(int id, Location location) { + super(id, location); + } + + + @Override + public AbstractNPC construct(int id, Location location, Object... objects) { + return new TowerArcher(id, location); + } + + @Override + public int[] getIds() { + return new int[]{688, 689, 690, 691}; + } + } + + /** + * Represents the archery target pulse. + * + * @author Jamix77 + */ + public static final class ArcheryCompetitionPulse extends Pulse { + + /** + * Represents the player instance. + */ + private final Player player; + + /** + * Represents the scenery. + */ + private final Scenery object; + + /** + * Constructs a new {@code ArcheryCompetitionPulse} {@code Object}. + * + * @param player the player. + * @param object the object. + */ + public ArcheryCompetitionPulse(final Player player, final Scenery object) { + super(1, player, object); + this.player = player; + this.object = object; + } + + private void showInterface(int points, int arrowsLeft, int target, String msg) { + player.getInterfaceManager().openComponent(325); + setVarp(player, 156, 11 - arrowsLeft); + setVarp(player, 157, points); + setVarp(player, 158, target); + player.getPacketDispatch().sendString(msg, 325, 32); + } + + @Override + public boolean pulse() { + if (player.getArcheryTargets() <= 0) { + return true; + } + if (getDelay() == 1) { + setDelay(player.getProperties().getAttackSpeed()); + } + if (player.getEquipment().remove(new Item(Items.BRONZE_ARROW_882, 1))) { + Projectile p = Ammunition.get(Items.BRONZE_ARROW_882).getProjectile().transform(player, object.getLocation()); + p.setEndLocation(object.getLocation()); + p.setEndHeight(25); + p.send(); + player.animate(new Animation(426)); + player.lock(getDelay()); + + int level = player.getSkills().getLevel(Skills.RANGE); + int bonus = player.getProperties().getBonuses()[14]; + double prayer = 1.0; + prayer += player.getPrayer().getSkillBonus(Skills.RANGE); + double cumulativeStr = Math.floor(level * prayer); + /*if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_RANGE_ACCURATE) { + cumulativeStr += 3; + } else if (player.getProperties().getAttackStyle().getStyle() == WeaponInterface.STYLE_LONG_RANGE) { + cumulativeStr += 1; + }*/ + cumulativeStr *= 1.0; + int hit = (int) ((14 + cumulativeStr + (bonus / 8) + ((cumulativeStr * bonus) * 0.016865))) / 10 + 1; + hit = hit + RandomFunction.randomSign(RandomFunction.random(3)); + + int target = Math.max(0, 13 - hit); + int points = 0; + String msg = ""; + switch (target) { + case 0: + points = 100; + msg = "Bulls-Eye!"; + break; + case 1: + points = 50; + msg = "Hit Yellow!"; + break; + case 2: + case 3: + case 4: + points = 30; + msg = "Hit Red!"; + break; + case 5: + case 6: + case 7: + case 8: + points = 20; + msg = "Hit Blue!"; + break; + case 9: + case 10: + points = 10; + msg = "Hit Black!"; + break; + case 11: + case 12: + case 13: + points = 0; + msg = "Missed!"; + break; + } + int xp = points / 2; + + player.getSkills().addExperience(Skills.RANGE, xp, true); + player.setArcheryTotal(player.getArcheryTotal() + points); + player.setArcheryTargets(player.getArcheryTargets() - 1); + player.debug("Hit: " + hit); + player.debug("You have " + player.getArcheryTargets() + " targets left."); + player.debug("You have " + player.getArcheryTotal() + " score."); + + showInterface(player.getArcheryTotal(), player.getArcheryTargets(), target, msg); + + return true; //player.getArcheryTargets() <= 0; + } else { + return true; + } + } + + } } diff --git a/Server/src/main/core/game/bots/PvMBots.java b/Server/src/main/core/game/bots/PvMBots.java index 8aeef372c..9962d5461 100644 --- a/Server/src/main/core/game/bots/PvMBots.java +++ b/Server/src/main/core/game/bots/PvMBots.java @@ -17,131 +17,131 @@ import core.tools.RandomFunction; public class PvMBots extends AIPlayer { - //Used so the bot doesn't spam actions - private int tick = 0; + //Used so the bot doesn't spam actions + private int tick = 0; - public PvMBots(Location l) { - super(l); - } + public PvMBots(Location l) { + super(l); + } - public PvMBots(String copyFromFile, Location l) { - super(copyFromFile, l); - } + public PvMBots(String copyFromFile, Location l) { + super(copyFromFile, l); + } - public List FindTargets(Entity entity, int radius) { - List targets = new ArrayList<>(20); - Object[] localNPCs = RegionManager.getLocalNPCs(entity.getLocation(), radius).toArray(); - int length = localNPCs.length; - if(length > 5){length = 5;} - for (int i = 0; i < length; i++) { - NPC npc = (NPC) localNPCs[i]; - { - if (checkValidTargets(npc)) - targets.add(npc); - } - } - if (targets.size() == 0) - return null; - return targets; - } + public List FindTargets(Entity entity, int radius) { + List targets = new ArrayList<>(20); + Object[] localNPCs = RegionManager.getLocalNPCs(entity.getLocation(), radius).toArray(); + int length = localNPCs.length; + if(length > 5){length = 5;} + for (int i = 0; i < length; i++) { + NPC npc = (NPC) localNPCs[i]; + { + if (checkValidTargets(npc)) + targets.add(npc); + } + } + if (targets.size() == 0) + return null; + return targets; + } - public boolean checkValidTargets(NPC target) { - if (!target.isActive()) { - return false; - } - if (!target.getProperties().isMultiZone() && target.inCombat()) { - return false; - } - if (!target.getDefinition().hasAction("attack")) { - return false; - } - return true; - } + public boolean checkValidTargets(NPC target) { + if (!target.isActive()) { + return false; + } + if (!target.getProperties().isMultiZone() && target.inCombat()) { + return false; + } + if (!target.getDefinition().hasAction("attack")) { + return false; + } + return true; + } - public boolean AttackNpcsInRadius(int radius) - { - return AttackNpcsInRadius(this, radius); - } + public boolean AttackNpcsInRadius(int radius) + { + return AttackNpcsInRadius(this, radius); + } - /** - * Attacks NPCs in radius of bot - * @param bot - * @param radius - * @return true if bot will be fighting - */ - public boolean AttackNpcsInRadius(Player bot, int radius) { - if (bot.inCombat()) - return true; - List creatures = FindTargets(bot, radius); - if (creatures == null) { - return false; - } - bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); - if (!creatures.isEmpty()) { - return true; - } else { - creatures = FindTargets(bot, radius); - if (!creatures.isEmpty()) - { - bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); - return true; - } - return false; - } - } + /** + * Attacks NPCs in radius of bot + * @param bot + * @param radius + * @return true if bot will be fighting + */ + public boolean AttackNpcsInRadius(Player bot, int radius) { + if (bot.inCombat()) + return true; + List creatures = FindTargets(bot, radius); + if (creatures == null) { + return false; + } + bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); + if (!creatures.isEmpty()) { + return true; + } else { + creatures = FindTargets(bot, radius); + if (!creatures.isEmpty()) + { + bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1)))); + return true; + } + return false; + } + } - @Override - public void tick() { - super.tick(); + @Override + public void tick() { + super.tick(); - this.tick++; + this.tick++; - //Despawn - if (this.getSkills().getLifepoints() <= 5){ - //TODO: Just respawn a new bot (not sure how you'd do that :L) - // Maybe make all PvMBots know what to do if they aren't in right area? I.e. pest control bots teleport to PC - //this.teleport(new Location(500, 500)); - //Despawning not being delayed causes 3 errors in the console - this.getSkills().setLifepoints(20); - } + //Despawn + if (this.getSkills().getLifepoints() <= 5){ + //TODO: Just respawn a new bot (not sure how you'd do that :L) + // Maybe make all PvMBots know what to do if they aren't in right area? I.e. pest control bots teleport to PC + //this.teleport(new Location(500, 500)); + //Despawning not being delayed causes 3 errors in the console + this.getSkills().setLifepoints(20); + } - //Npc Combat - /*if (this.tick % 10 == 0) { - if (!this.inCombat()) - AttackNpcsInRadius(this, 5); - }*/ + //Npc Combat + /*if (this.tick % 10 == 0) { + if (!this.inCombat()) + AttackNpcsInRadius(this, 5); + }*/ - if (this.tick == 100) this.tick = 0; + if (this.tick == 100) this.tick = 0; - //this.eat(); - //this.getPrayer().toggle() - } + //this.eat(); + //this.getPrayer().toggle() + } - public void CheckPrayer(PrayerType type[]) { - for (int i = 0; i < type.length; i++) - this.getPrayer().toggle(type[i]); - } + public void CheckPrayer(PrayerType type[]) { + for (int i = 0; i < type.length; i++) + this.getPrayer().toggle(type[i]); + } - public void eat(int foodId) { - Item foodItem = new Item(foodId); + public void eat(int foodId) { + Item foodItem = new Item(foodId); - if ((this.getSkills().getStaticLevel(Skills.HITPOINTS) >= this.getSkills().getLifepoints() * 3) && this.getInventory().containsItem(foodItem)) { - this.lock(3); - //this.animate(new Animation(829)); - Item food = this.getInventory().getItem(foodItem); + if ((this.getSkills().getStaticLevel(Skills.HITPOINTS) >= this.getSkills().getLifepoints() * 3) && this.getInventory().containsItem(foodItem)) { + this.lock(3); + //this.animate(new Animation(829)); + Item food = this.getInventory().getItem(foodItem); - Consumable consumable = Consumables.getConsumableById(food.getId()).getConsumable(); + Consumable consumable = Consumables.getConsumableById(food.getId()).getConsumable(); - if (consumable == null) { - return; - } + if (consumable == null) { + return; + } - consumable.consume(food, this); - this.getProperties().getCombatPulse().delayNextAttack(3); - } - if (this.checkVictimIsPlayer() == false) - if (!(this.getInventory().contains(foodId, 1))) - this.getInventory().add(new Item(foodId, 5)); //Add Food to Inventory - } + consumable.consume(food, this); + this.getProperties().getCombatPulse().delayNextAttack(3); + } + if (this.checkVictimIsPlayer() == false) + if (!(this.getInventory().contains(foodId, 1))) + this.getInventory().add(new Item(foodId, 5)); //Add Food to Inventory + } } diff --git a/Server/src/main/core/game/interaction/MovementPulse.java b/Server/src/main/core/game/interaction/MovementPulse.java index b9acb88fd..9d7688306 100644 --- a/Server/src/main/core/game/interaction/MovementPulse.java +++ b/Server/src/main/core/game/interaction/MovementPulse.java @@ -202,145 +202,145 @@ public abstract class MovementPulse extends Pulse { mover.scripts.removeNormalScripts(); } - @Override - public boolean update() { - if (!mover.getLocation().getRegion().isActive()) - return false; + @Override + public boolean update() { + if (!mover.getLocation().getRegion().isActive()) + return false; - if (!isRunning()) return true; + if (!isRunning()) return true; - if (!validate()) { - stop(); - return true; - } + if (!validate()) { + stop(); + return true; + } - clearInferiorScripts(); + clearInferiorScripts(); - mover.face(null); - if (canInteractWithoutMoving()) { - if (interactImmediately()) { - stop(); - return true; - } - } - updatePath(); + mover.face(null); + if (canInteractWithoutMoving()) { + if (interactImmediately()) { + stop(); + return true; + } + } + updatePath(); - if (tryInteract()) { - stop(); - return true; - } + if (tryInteract()) { + stop(); + return true; + } - return false; - } + return false; + } - private boolean tryInteract() { - Location ml = mover.getLocation(); - if (ml == null) { - return false; - } - // Allow being within 1 square of moving entities to interact with them. - int radius = destination instanceof Entity && ((Entity) destination).getWalkingQueue().hasPath() ? 1 : 0; - if (interactLocation == null) - return false; - boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; - // Check if already in a valid interaction position for entity destinations - boolean canInteractFromCurrentPosition = false; - if (!atInteractLocation && destination instanceof Entity) { - Entity target = (Entity) destination; - Location dl = target.getLocation(); - if (dl == null) { - return false; - } - boolean onSameTile = ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ(); - if (!onSameTile) { - canInteractFromCurrentPosition = Pathfinder.canInteract( - ml.getX(), ml.getY(), mover.size(), - dl.getX(), dl.getY(), target.size(), target.size(), - 0, // walkFlag - "can interact from any unblocked direction" - ml.getZ(), - RegionManager::getClippingFlag); - } - } - if (atInteractLocation || canInteractFromCurrentPosition) { - try { - if (near || pulse()) { - if (mover instanceof Player) { - if (near) { - ((Player) mover).getPacketDispatch().sendMessage("I can't reach that."); - } - PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); - } - stop(); - return true; - } - } catch (Exception e) { - e.printStackTrace(); - stop(); - } - } - return false; - } + private boolean tryInteract() { + Location ml = mover.getLocation(); + if (ml == null) { + return false; + } + // Allow being within 1 square of moving entities to interact with them. + int radius = destination instanceof Entity && ((Entity) destination).getWalkingQueue().hasPath() ? 1 : 0; + if (interactLocation == null) + return false; + boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; + // Check if already in a valid interaction position for entity destinations + boolean canInteractFromCurrentPosition = false; + if (!atInteractLocation && destination instanceof Entity) { + Entity target = (Entity) destination; + Location dl = target.getLocation(); + if (dl == null) { + return false; + } + boolean onSameTile = ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ(); + if (!onSameTile) { + canInteractFromCurrentPosition = Pathfinder.canInteract( + ml.getX(), ml.getY(), mover.size(), + dl.getX(), dl.getY(), target.size(), target.size(), + 0, // walkFlag - "can interact from any unblocked direction" + ml.getZ(), + RegionManager::getClippingFlag); + } + } + if (atInteractLocation || canInteractFromCurrentPosition) { + try { + if (near || pulse()) { + if (mover instanceof Player) { + if (near) { + ((Player) mover).getPacketDispatch().sendMessage("I can't reach that."); + } + PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); + } + stop(); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + stop(); + } + } + return false; + } - /** - * Checks if the mover can interact with an entity destination from their - * current position without needing to move. - * - * @return true if the mover can interact without moving - */ - private boolean canInteractWithoutMoving() { - if (!(destination instanceof Entity)) { - return false; - } - Entity target = (Entity) destination; - Location ml = mover.getLocation(); - Location dl = target.getLocation(); - if (ml == null || dl == null) { - return false; - } - if (ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ()) { - return false; - } - if (isInsideEntity(ml)) { - return false; - } - if (target.getWalkingQueue().hasPath()) { // For moving entities, allow interaction from 1 tile away - int distance = Math.max( - Math.abs(ml.getX() - dl.getX()), - Math.abs(ml.getY() - dl.getY())); - if (distance <= target.size()) { - return true; - } - } - return Pathfinder.canInteract( - ml.getX(), ml.getY(), mover.size(), - dl.getX(), dl.getY(), target.size(), target.size(), - 0, // walkFlag - "can interact from any unblocked direction" - ml.getZ(), - RegionManager::getClippingFlag); - } + /** + * Checks if the mover can interact with an entity destination from their + * current position without needing to move. + * + * @return true if the mover can interact without moving + */ + private boolean canInteractWithoutMoving() { + if (!(destination instanceof Entity)) { + return false; + } + Entity target = (Entity) destination; + Location ml = mover.getLocation(); + Location dl = target.getLocation(); + if (ml == null || dl == null) { + return false; + } + if (ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ()) { + return false; + } + if (isInsideEntity(ml)) { + return false; + } + if (target.getWalkingQueue().hasPath()) { // For moving entities, allow interaction from 1 tile away + int distance = Math.max( + Math.abs(ml.getX() - dl.getX()), + Math.abs(ml.getY() - dl.getY())); + if (distance <= target.size()) { + return true; + } + } + return Pathfinder.canInteract( + ml.getX(), ml.getY(), mover.size(), + dl.getX(), dl.getY(), target.size(), target.size(), + 0, // walkFlag - "can interact from any unblocked direction" + ml.getZ(), + RegionManager::getClippingFlag); + } - /** - * Immediately performs the interaction without pathfinding. - * Called when the player is already in a valid interaction position. - * - * @return true if interaction was successful and pulse should stop - */ - private boolean interactImmediately() { - if (destination instanceof Entity) { - mover.face((Entity) destination); - } - try { - if (pulse()) { - if (mover instanceof Player) { - PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); - } - return true; - } - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } + /** + * Immediately performs the interaction without pathfinding. + * Called when the player is already in a valid interaction position. + * + * @return true if interaction was successful and pulse should stop + */ + private boolean interactImmediately() { + if (destination instanceof Entity) { + mover.face((Entity) destination); + } + try { + if (pulse()) { + if (mover instanceof Player) { + PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); + } + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } private boolean validate() { if (mover == null || destination == null || mover.getLocation().getRegion() == null || hasInactiveNode()) { @@ -466,49 +466,49 @@ public abstract class MovementPulse extends Pulse { return canMove; } - private Location checkForEntityPathInterrupt(Location loc) { - Location ml = mover.getLocation(); - Location dl = destination.getLocation(); - // Lead the target if they're walking/running, unless they're already within interaction range - if (loc != null && destination instanceof Entity) { - WalkingQueue wq = ((Entity) destination).getWalkingQueue(); - if (wq.hasPath()) { - Point[] points = wq.getQueue().toArray(new Point[0]); - if (points.length > 0) { - Point p = points[0]; - Point predictiveIntersection = null; - for (int i = 0; i < points.length; i++) { - Location closestBorder = getClosestBorderToPoint(points[i], loc.getZ()); + private Location checkForEntityPathInterrupt(Location loc) { + Location ml = mover.getLocation(); + Location dl = destination.getLocation(); + // Lead the target if they're walking/running, unless they're already within interaction range + if (loc != null && destination instanceof Entity) { + WalkingQueue wq = ((Entity) destination).getWalkingQueue(); + if (wq.hasPath()) { + Point[] points = wq.getQueue().toArray(new Point[0]); + if (points.length > 0) { + Point p = points[0]; + Point predictiveIntersection = null; + for (int i = 0; i < points.length; i++) { + Location closestBorder = getClosestBorderToPoint(points[i], loc.getZ()); - if (!RegionManager.isTeleportPermitted(closestBorder)) { // A nasty hack to discard invalid intersection points - continue; - } - int moverDist = Math.max(Math.abs(ml.getX() - closestBorder.getX()), Math.abs(ml.getY() - closestBorder.getY())); - float movementRatio = moverDist / (float) ((i + 1) / (mover.getWalkingQueue().isRunning() ? 2 : 1)); - if (predictiveIntersection == null && movementRatio <= 1.0) { //try to predict an intersection point on the path if possible - predictiveIntersection = points[i]; - break; - } - // Otherwise, we target the farthest point along target's planned movement that's within 1 tick's running, - // this ensures the player will run to catch up to the target if able. - if (moverDist <= 2) { - p = points[i]; - } - } - if (predictiveIntersection != null) - p = predictiveIntersection; + if (!RegionManager.isTeleportPermitted(closestBorder)) { // A nasty hack to discard invalid intersection points + continue; + } + int moverDist = Math.max(Math.abs(ml.getX() - closestBorder.getX()), Math.abs(ml.getY() - closestBorder.getY())); + float movementRatio = moverDist / (float) ((i + 1) / (mover.getWalkingQueue().isRunning() ? 2 : 1)); + if (predictiveIntersection == null && movementRatio <= 1.0) { //try to predict an intersection point on the path if possible + predictiveIntersection = points[i]; + break; + } + // Otherwise, we target the farthest point along target's planned movement that's within 1 tick's running, + // this ensures the player will run to catch up to the target if able. + if (moverDist <= 2) { + p = points[i]; + } + } + if (predictiveIntersection != null) + p = predictiveIntersection; - Location endLoc = getClosestBorderToPoint(p, loc.getZ()); + Location endLoc = getClosestBorderToPoint(p, loc.getZ()); - if (!RegionManager.isTeleportPermitted(endLoc)) { // Basically a prayer - return loc; - } - return endLoc; - } - } - } - return loc; - } + if (!RegionManager.isTeleportPermitted(endLoc)) { // Basically a prayer + return loc; + } + return endLoc; + } + } + } + return loc; + } private Location getClosestBorderToPoint (Point p, int plane) { Vector pathDiff = Vector.betweenLocs (destination.getLocation(), Location.create(p.getX(), p.getY(), plane)); diff --git a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java index dc3fcb107..4a7c87c91 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java +++ b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java @@ -39,271 +39,271 @@ import content.data.Quests; */ public final class LoginConfiguration { - /** - * The login plugins. - */ - private static final List> LOGIN_PLUGINS = new ArrayList<>(20); + /** + * The login plugins. + */ + private static final List> LOGIN_PLUGINS = new ArrayList<>(20); - /** - * The lobby pane component. - */ - private static final Component LOBBY_PANE = new Component(549); + /** + * The lobby pane component. + */ + private static final Component LOBBY_PANE = new Component(549); - /** - * The lobby interface component. - */ - private static final Component LOBBY_INTERFACE = new Component(378); + /** + * The lobby interface component. + */ + private static final Component LOBBY_INTERFACE = new Component(378); - /** - * The lobby message of the week models & constant to be set for auto selecting the models - */ - private static final int[] MESSAGE_MODEL = {15, 16, 17, 18, 19, 20, 21, 22, 23, 405, 447, 622, 623, 679, 715, 800}; - private static int messModel; + /** + * The lobby message of the week models & constant to be set for auto selecting the models + */ + private static final int[] MESSAGE_MODEL = {15, 16, 17, 18, 19, 20, 21, 22, 23, 405, 447, 622, 623, 679, 715, 800}; + private static int messModel; - /** - * Constructs a new {@Code LoginConfiguration} {@Code Object} - */ - public LoginConfiguration() { - /* - * empty. - */ - } + /** + * Constructs a new {@Code LoginConfiguration} {@Code Object} + */ + public LoginConfiguration() { + /* + * empty. + */ + } - /** - * Configures the lobby login. - * - * @param player The player. - */ - public static void configureLobby(Player player) { - player.updateSceneGraph(true); - if (!player.isArtificial() && player.getAttribute("tutorial:complete",false) && player.getAttribute("login_type", LoginType.NORMAL_LOGIN) != LoginType.RECONNECT_TYPE) { - sendLobbyScreen(player); - } else { - configureGameWorld(player); - } - } + /** + * Configures the lobby login. + * + * @param player The player. + */ + public static void configureLobby(Player player) { + player.updateSceneGraph(true); + if (!player.isArtificial() && player.getAttribute("tutorial:complete",false) && player.getAttribute("login_type", LoginType.NORMAL_LOGIN) != LoginType.RECONNECT_TYPE) { + sendLobbyScreen(player); + } else { + configureGameWorld(player); + } + } - /** - * Sends the lobby interface-related packets. - * - * @param player The player. - */ - public static void sendLobbyScreen(Player player) { - messModel = autoSelect(); - for(Player p : Repository.getLobbyPlayers()){ - if(p.getName().equals(player.getName())){ - p.clear(); - Repository.getLobbyPlayers().remove(p); - break; - } - } - Repository.getLobbyPlayers().add(player); - setInterfaceText(player, "Welcome to " + ServerConstants.SERVER_NAME, 378, 115); - setInterfaceText(player, getLastLogin(player), 378, 116); - setInterfaceText(player, "", 378, 37); - setInterfaceText(player, "Want to stay up to date with the latest news and updates? Join our discord by using the link on our website!", 378, 38); - setInterfaceText(player, "", 378, 39); - setInterfaceText(player, "Discord Invite", 378, 14); - setInterfaceText(player, "Discord Invite", 378, 129); - setInterfaceText(player, "You can gain more credits by reporting bugs and various other methods of contribution.", 378, 93); - setInterfaceText(player, player.getDetails().getCredits() + "", 378, 96); - setInterfaceText(player, "Credits", 378, 94); - setInterfaceText(player, "", 378, 229); - setInterfaceText(player, "Want to contribute to " + ServerConstants.SERVER_NAME + "? Visit the GitLab using the link on our website!", 378, 230); - setInterfaceText(player, "", 378, 231); - setInterfaceText(player, "Github", 378, 240); - setInterfaceText(player, GameWorld.getSettings().getMessage_string(), messModel, getMessageChild(messModel)); - player.getInterfaceManager().openWindowsPane(LOBBY_PANE); - player.getInterfaceManager().setOpened(LOBBY_INTERFACE); - PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 2, 378, true)); - PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 3, messModel, true));//UPDATE `configs` SET `value`=FLOOR(RAND()*(25-10)+10) WHERE key_="messageInterface" - player.getDetails().setLastLogin(System.currentTimeMillis()); - } + /** + * Sends the lobby interface-related packets. + * + * @param player The player. + */ + public static void sendLobbyScreen(Player player) { + messModel = autoSelect(); + for(Player p : Repository.getLobbyPlayers()){ + if(p.getName().equals(player.getName())){ + p.clear(); + Repository.getLobbyPlayers().remove(p); + break; + } + } + Repository.getLobbyPlayers().add(player); + setInterfaceText(player, "Welcome to " + ServerConstants.SERVER_NAME, 378, 115); + setInterfaceText(player, getLastLogin(player), 378, 116); + setInterfaceText(player, "", 378, 37); + setInterfaceText(player, "Want to stay up to date with the latest news and updates? Join our discord by using the link on our website!", 378, 38); + setInterfaceText(player, "", 378, 39); + setInterfaceText(player, "Discord Invite", 378, 14); + setInterfaceText(player, "Discord Invite", 378, 129); + setInterfaceText(player, "You can gain more credits by reporting bugs and various other methods of contribution.", 378, 93); + setInterfaceText(player, player.getDetails().getCredits() + "", 378, 96); + setInterfaceText(player, "Credits", 378, 94); + setInterfaceText(player, "", 378, 229); + setInterfaceText(player, "Want to contribute to " + ServerConstants.SERVER_NAME + "? Visit the GitLab using the link on our website!", 378, 230); + setInterfaceText(player, "", 378, 231); + setInterfaceText(player, "Github", 378, 240); + setInterfaceText(player, GameWorld.getSettings().getMessage_string(), messModel, getMessageChild(messModel)); + player.getInterfaceManager().openWindowsPane(LOBBY_PANE); + player.getInterfaceManager().setOpened(LOBBY_INTERFACE); + PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 2, 378, true)); + PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 3, messModel, true));//UPDATE `configs` SET `value`=FLOOR(RAND()*(25-10)+10) WHERE key_="messageInterface" + player.getDetails().setLastLogin(System.currentTimeMillis()); + } - /** - * Configures the game world. - * - * @param player The player. - */ - public static void configureGameWorld(final Player player) { - sendGameConfiguration(player); - Repository.getLobbyPlayers().remove(player); - player.setPlaying(true); - UpdateSequence.getRenderablePlayers().add(player); - RegionManager.move(player, ServerConstants.START_LOCATION, player.getLocation()); - player.getMusicPlayer().init(); - player.updateAppearance(); - player.getPlayerFlags().setUpdateSceneGraph(true); - player.getPacketDispatch().sendInterfaceConfig(226, 1, true); + /** + * Configures the game world. + * + * @param player The player. + */ + public static void configureGameWorld(final Player player) { + sendGameConfiguration(player); + Repository.getLobbyPlayers().remove(player); + player.setPlaying(true); + UpdateSequence.getRenderablePlayers().add(player); + RegionManager.move(player, ServerConstants.START_LOCATION, player.getLocation()); + player.getMusicPlayer().init(); + player.updateAppearance(); + player.getPlayerFlags().setUpdateSceneGraph(true); + player.getPacketDispatch().sendInterfaceConfig(226, 1, true); - if (player.getGlobalData().getTestStage() == 3 && !player.getEmoteManager().isUnlocked(Emotes.SAFETY_FIRST)) { - //TODO: port this to save version later. when you do, please also do this for the Explore emote, which has a similar problem (e.g. player_name.json has this). - player.getEmoteManager().unlock(Emotes.SAFETY_FIRST); - } + if (player.getGlobalData().getTestStage() == 3 && !player.getEmoteManager().isUnlocked(Emotes.SAFETY_FIRST)) { + //TODO: port this to save version later. when you do, please also do this for the Explore emote, which has a similar problem (e.g. player_name.json has this). + player.getEmoteManager().unlock(Emotes.SAFETY_FIRST); + } - for (Item item : player.getEquipment().toArray()) { - //Run equip hooks for all items equipped on login. - //We should have already been doing this. - //Frankly, I don't even want to imagine the number of bugs us *not* doing this has caused. - if (item == null) continue; - player.getEquipment().remove(item); - if (!InteractionListeners.run(item.getId(), player, item, true) || !player.getEquipment().add(item, true, false)) { - player.sendMessage(colorize("%RAs you can no longer wear " + item.getName() + ", it has been unequipped.")); - addItemOrBank(player, item.getId(), item.getAmount()); - } - } + for (Item item : player.getEquipment().toArray()) { + //Run equip hooks for all items equipped on login. + //We should have already been doing this. + //Frankly, I don't even want to imagine the number of bugs us *not* doing this has caused. + if (item == null) continue; + player.getEquipment().remove(item); + if (!InteractionListeners.run(item.getId(), player, item, true) || !player.getEquipment().add(item, true, false)) { + player.sendMessage(colorize("%RAs you can no longer wear " + item.getName() + ", it has been unequipped.")); + addItemOrBank(player, item.getId(), item.getAmount()); + } + } - SpellBookManager.SpellBook currentSpellBook = SpellBookManager.SpellBook.forInterface(player.getSpellBookManager().getSpellBook()); - if (currentSpellBook == SpellBookManager.SpellBook.ANCIENT && !hasRequirement(player, Quests.DESERT_TREASURE)) { - player.sendMessage(colorize("%RAs you can no longer use Ancient Magic, you have been set back to Modern.")); - player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); - } else if (currentSpellBook == SpellBookManager.SpellBook.LUNAR && !hasRequirement(player, Quests.LUNAR_DIPLOMACY)) { - player.sendMessage(colorize("%RAs you can no longer use Lunar Magic, you have been set back to Modern.")); - player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); - } - player.getSpellBookManager().update(player); + SpellBookManager.SpellBook currentSpellBook = SpellBookManager.SpellBook.forInterface(player.getSpellBookManager().getSpellBook()); + if (currentSpellBook == SpellBookManager.SpellBook.ANCIENT && !hasRequirement(player, Quests.DESERT_TREASURE)) { + player.sendMessage(colorize("%RAs you can no longer use Ancient Magic, you have been set back to Modern.")); + player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); + } else if (currentSpellBook == SpellBookManager.SpellBook.LUNAR && !hasRequirement(player, Quests.LUNAR_DIPLOMACY)) { + player.sendMessage(colorize("%RAs you can no longer use Lunar Magic, you have been set back to Modern.")); + player.getSpellBookManager().setSpellBook(SpellBookManager.SpellBook.MODERN); + } + player.getSpellBookManager().update(player); - // 1050 is checked client-side for making piety/chivalry disallowed sfx, likely due to the minigame requirement. - // Set it here unconditionally until the minigame is implemented. - if (hasRequirement(player, Quests.KINGS_RANSOM, false)) { - setVarbit(player, 3909, 8, false); - } - if(ServerConstants.RULES_AND_INFO_ENABLED) - RulesAndInfo.openFor(player); - /*if (TutorialSession.getExtension(player).getStage() != 73) { - TutorialStage.load(player, TutorialSession.getExtension(player).getStage(), true); - }*/ - } + // 1050 is checked client-side for making piety/chivalry disallowed sfx, likely due to the minigame requirement. + // Set it here unconditionally until the minigame is implemented. + if (hasRequirement(player, Quests.KINGS_RANSOM, false)) { + setVarbit(player, 3909, 8, false); + } + if(ServerConstants.RULES_AND_INFO_ENABLED) + RulesAndInfo.openFor(player); + /*if (TutorialSession.getExtension(player).getStage() != 73) { + TutorialStage.load(player, TutorialSession.getExtension(player).getStage(), true); + }*/ + } - /** - * Sends the game configuration packets. - * - * @param player The player to send to. - */ - public static void sendGameConfiguration(final Player player) { - player.getInterfaceManager().openWindowsPane(new Component(player.getInterfaceManager().isResizable() ? 746 : 548)); - player.getInterfaceManager().openChatbox(137); - player.getInterfaceManager().openDefaultTabs(); - welcome(player); - config(player); - for (Plugin plugin : LOGIN_PLUGINS) { - try { - plugin.newInstance(player); - } catch (Throwable e) { - e.printStackTrace(); - } - } - player.getAppearance().sync(); - } + /** + * Sends the game configuration packets. + * + * @param player The player to send to. + */ + public static void sendGameConfiguration(final Player player) { + player.getInterfaceManager().openWindowsPane(new Component(player.getInterfaceManager().isResizable() ? 746 : 548)); + player.getInterfaceManager().openChatbox(137); + player.getInterfaceManager().openDefaultTabs(); + welcome(player); + config(player); + for (Plugin plugin : LOGIN_PLUGINS) { + try { + plugin.newInstance(player); + } catch (Throwable e) { + e.printStackTrace(); + } + } + player.getAppearance().sync(); + } - /** - * Method used to welcome the player. - * - * @param player the player. Fullscreen mode Object id: - */ - public static final void welcome(final Player player) { - if (player.isArtificial()) { - return; - } - player.getPacketDispatch().sendMessage("Welcome to " + ServerConstants.SERVER_NAME + "."); - if (player.getDetails().isMuted()) { - player.getPacketDispatch().sendMessage("You are muted."); - player.getPacketDispatch().sendMessage("To prevent further mutes please read the rules."); - } - } + /** + * Method used to welcome the player. + * + * @param player the player. Fullscreen mode Object id: + */ + public static final void welcome(final Player player) { + if (player.isArtificial()) { + return; + } + player.getPacketDispatch().sendMessage("Welcome to " + ServerConstants.SERVER_NAME + "."); + if (player.getDetails().isMuted()) { + player.getPacketDispatch().sendMessage("You are muted."); + player.getPacketDispatch().sendMessage("To prevent further mutes please read the rules."); + } + } - /** - * Method used to configure all possible settings for the player. - * - * @param player the player. - */ - public static final void config(final Player player) { - if(!player.isArtificial()) - log(LoginConfiguration.class, Log.INFO, "configuring player " + player.getUsername()); - player.getInventory().refresh(); - player.getEquipment().refresh(); - player.getSkills().refresh(); - player.getSkills().configure(); - player.getSettings().update(); - player.getInteraction().setDefault(); - player.getPacketDispatch().sendRunEnergy(); - player.getFamiliarManager().login(); - player.getInterfaceManager().openDefaultTabs(); - setInterfaceText(player, "Friends List - " + ServerConstants.SERVER_NAME + " " + GameWorld.getSettings().getWorldId(), 550, 3); - setInterfaceText(player, "When you have finished playing " + ServerConstants.SERVER_NAME + ", always use the button below to logout safely.", 182, 0); - player.getQuestRepository().syncronizeTab(player); - player.getInterfaceManager().close(); - player.getEmoteManager().refresh(); - player.getInterfaceManager().openInfoBars(); - if(!player.isArtificial()) - log(LoginConfiguration.class, Log.INFO, "finished configuring player " + player.getUsername()); - } + /** + * Method used to configure all possible settings for the player. + * + * @param player the player. + */ + public static final void config(final Player player) { + if(!player.isArtificial()) + log(LoginConfiguration.class, Log.INFO, "configuring player " + player.getUsername()); + player.getInventory().refresh(); + player.getEquipment().refresh(); + player.getSkills().refresh(); + player.getSkills().configure(); + player.getSettings().update(); + player.getInteraction().setDefault(); + player.getPacketDispatch().sendRunEnergy(); + player.getFamiliarManager().login(); + player.getInterfaceManager().openDefaultTabs(); + setInterfaceText(player, "Friends List - " + ServerConstants.SERVER_NAME + " " + GameWorld.getSettings().getWorldId(), 550, 3); + setInterfaceText(player, "When you have finished playing " + ServerConstants.SERVER_NAME + ", always use the button below to logout safely.", 182, 0); + player.getQuestRepository().syncronizeTab(player); + player.getInterfaceManager().close(); + player.getEmoteManager().refresh(); + player.getInterfaceManager().openInfoBars(); + if(!player.isArtificial()) + log(LoginConfiguration.class, Log.INFO, "finished configuring player " + player.getUsername()); + } - /** - * Gets the message child for the inter id. - * @notice GameSettings.kt contains the list of what these are - * @param interfaceId The interface id. - * @return The child id. - */ - public static int getMessageChild(int interfaceId) { - if (interfaceId == 622) { - return 8; - } else if (interfaceId == 16) { - return 6; - } else if (interfaceId == 20 || interfaceId == 623) { - return 5; - } else if (interfaceId == 15 || interfaceId == 18 || interfaceId == 19 || interfaceId == 21 || interfaceId == 22 || interfaceId == 447 || interfaceId == 405) { - return 4; - } else if (interfaceId == 17 || interfaceId == 23 || interfaceId == 800) { - return 3; - } else if (interfaceId == 715) { - return 2; - } else if (interfaceId == 679) { - return 1; - } - return 0; - } + /** + * Gets the message child for the inter id. + * @notice GameSettings.kt contains the list of what these are + * @param interfaceId The interface id. + * @return The child id. + */ + public static int getMessageChild(int interfaceId) { + if (interfaceId == 622) { + return 8; + } else if (interfaceId == 16) { + return 6; + } else if (interfaceId == 20 || interfaceId == 623) { + return 5; + } else if (interfaceId == 15 || interfaceId == 18 || interfaceId == 19 || interfaceId == 21 || interfaceId == 22 || interfaceId == 447 || interfaceId == 405) { + return 4; + } else if (interfaceId == 17 || interfaceId == 23 || interfaceId == 800) { + return 3; + } else if (interfaceId == 715) { + return 2; + } else if (interfaceId == 679) { + return 1; + } + return 0; + } - /** - * Sets a random interface id for the "message of the week" models - */ - private final static int autoSelect() { - boolean contains = IntStream.of(MESSAGE_MODEL).anyMatch(x -> x == GameWorld.getSettings().getMessage_model()); - return contains ? GameWorld.getSettings().getMessage_model():MESSAGE_MODEL[new Random().nextInt(MESSAGE_MODEL.length)]; - } + /** + * Sets a random interface id for the "message of the week" models + */ + private final static int autoSelect() { + boolean contains = IntStream.of(MESSAGE_MODEL).anyMatch(x -> x == GameWorld.getSettings().getMessage_model()); + return contains ? GameWorld.getSettings().getMessage_model():MESSAGE_MODEL[new Random().nextInt(MESSAGE_MODEL.length)]; + } - /** - * Gets the last login string for the lobby. - * - * @param player the player. - * @return the last login. - */ - public static String getLastLogin(Player player) { - player.getPacketDispatch().sendLastLoginInfo(); - String string = "You last logged in @timeAgo from:"; - long time = player.getDetails().getLastLogin(); - Date lastLogin = new Date(time); - Date current = new Date(); - long diff = current.getTime() - lastLogin.getTime(); - int days = (int) TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS); - if (days < 1) { - string = string.replace("@timeAgo", "earlier today"); - } else if (days == 1) { - string = string.replace("@timeAgo", "yesterday"); - } else { - string = string.replace("@timeAgo", days + " days ago"); - } - return string; - } + /** + * Gets the last login string for the lobby. + * + * @param player the player. + * @return the last login. + */ + public static String getLastLogin(Player player) { + player.getPacketDispatch().sendLastLoginInfo(); + String string = "You last logged in @timeAgo from:"; + long time = player.getDetails().getLastLogin(); + Date lastLogin = new Date(time); + Date current = new Date(); + long diff = current.getTime() - lastLogin.getTime(); + int days = (int) TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS); + if (days < 1) { + string = string.replace("@timeAgo", "earlier today"); + } else if (days == 1) { + string = string.replace("@timeAgo", "yesterday"); + } else { + string = string.replace("@timeAgo", days + " days ago"); + } + return string; + } - /** - * Gets the loginPlugins. - * - * @return The loginPlugins. - */ - public static List> getLoginPlugins() { - return LOGIN_PLUGINS; - } + /** + * Gets the loginPlugins. + * + * @return The loginPlugins. + */ + public static List> getLoginPlugins() { + return LOGIN_PLUGINS; + } } From 23b3fd76c6f1a915572c1b8e5ee5398c7327beee Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 20:03:56 +0200 Subject: [PATCH 13/94] Extend house loading screen --- .../main/content/global/skill/construction/HouseManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/content/global/skill/construction/HouseManager.java b/Server/src/main/content/global/skill/construction/HouseManager.java index 884ce5a7f..48786ae1c 100644 --- a/Server/src/main/content/global/skill/construction/HouseManager.java +++ b/Server/src/main/content/global/skill/construction/HouseManager.java @@ -172,7 +172,7 @@ public final class HouseManager { } private void submitCloseLoadInterfacePulse(Player player) { - GameWorld.getPulser().submit(new Pulse(1, player) { + GameWorld.getPulser().submit(new Pulse(2, player) { @Override public boolean pulse() { player.getInterfaceManager().close(); From 445281776e83e768a3c4cba1941f68979f45b887 Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 21:47:31 +0200 Subject: [PATCH 14/94] Undo star changes to make diff smaller --- .../content/global/activity/shootingstar/ShootingStar.kt | 9 ++------- .../global/activity/shootingstar/ShootingStarPlugin.kt | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt b/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt index 52cbfd52a..6a7b8802a 100644 --- a/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt +++ b/Server/src/main/content/global/activity/shootingstar/ShootingStar.kt @@ -63,16 +63,11 @@ class ShootingStar(var level: ShootingStarType = ShootingStarType.values().rando "Lava Maze mining site" to Location.create(3062, 3885, 0), // Wilderness rune mine "Mage Arena bank" to Location.create(3093, 3962, 0) // Mage Arena bank ) + val starSprite = NPC(8091) var location = "Canifis Bank" - val loc = crash_locations[location] - val starSprite = let { - val npc = NPC(8091) - npc.location = loc - npc - } var maxDust = level.totalStardust var dustLeft = level.totalStardust - var starObject = Scenery(level.objectId, loc) + var starObject = Scenery(level.objectId, crash_locations.get(location)) var isDiscovered = false var ticks = 0 var isSpawned = false diff --git a/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt b/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt index 0c938aec5..57849d1db 100644 --- a/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt +++ b/Server/src/main/content/global/activity/shootingstar/ShootingStarPlugin.kt @@ -135,8 +135,8 @@ class ShootingStarPlugin : LoginListener, InteractionListener, TickListener, Com } override fun defineCommands() { - define("tostar", Privilege.ADMIN, description = "Teleports you inside the currently active star.") { player, _ -> - teleport(player, star.starObject.location.transform(0, 0, 0)) + define("tostar", Privilege.ADMIN, description = "Teleports you adjacent to the currently active star.") { player, _ -> + teleport(player, star.starObject.location.transform(1,1,0)) } define("submit", Privilege.ADMIN, description = "Rebuilds and fires the shooting star event immediately.") { _, _ -> From 20d26e67e025bb19db8df7c4517cb340ad8db4e4 Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 22:42:48 +0200 Subject: [PATCH 15/94] This breaks map rendering more --- .../core/game/node/entity/player/Player.java | 2 +- .../game/world/update/MapChunkRenderer.kt | 62 ++++++------------- .../game/world/update/flag/PlayerFlags.java | 8 ++- 3 files changed, 25 insertions(+), 47 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index cb94a83bd..77d205b01 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -856,7 +856,7 @@ public class Player extends Entity { getZoneMonitor().getZones().clear(); playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); - playerFlags.setLastViewport(new RegionChunk[13][13]); + playerFlags.setLastViewport(new LinkedList<>()); renderInfo.getLocalNpcs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 47e93ff53..cf18cc8a3 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -13,6 +13,8 @@ import kotlin.math.abs * @author Emperor */ object MapChunkRenderer { + const val buildAreaDepth = 6 + /** * Sends the map chunk rendering packet. * @param player The player. @@ -21,61 +23,35 @@ object MapChunkRenderer { fun render(player: Player) { val last = player.playerFlags.lastViewport val updated: MutableList = ArrayList() - val current: MutableList> = ArrayList() + val current: MutableList = ArrayList() - val buildAreaDepth = 6 for (dcx in -buildAreaDepth..+buildAreaDepth) { - val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { val newloc = player.location.chunkBase.transform(dcx*8, dcy*8, 0) - addX.add(newloc.chunk) + current.add(newloc.chunk) } - current.add(addX) } - var sizeX = last.size - for (x in 0 until sizeX) { - val sizeY: Int = last[x].size - for (y in 0 until sizeY) { - val previous = last[x][y] ?: continue - if (!containsChunk(current, previous)) { - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) - } else { - updated.add(previous) - } + val removeList = LinkedList() + for (chunk in last) { + if (current.contains(chunk)) { + updated.add(chunk) + } else { + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, chunk)) + removeList.add(chunk) } } - sizeX = current.size - for (x in 0 until sizeX) { - val sizeY: Int = current[x].size - for (y in 0 until sizeY) { - val chunk = current[x][y] - if (!updated.contains(chunk)) { - chunk.synchronize(player) - } else { - chunk.update(player) - } - last[x][y] = current[x][y] - } + for (chunk in removeList) { + last.remove(chunk) } - } - /** - * Checks if the chunks list contains the specified region chunk. - * @param list The list to search. - * @param c The region chunk. - * @return `True` if so. - */ - private fun containsChunk(list: MutableList>, c: RegionChunk): Boolean { - val sizeList = list.size - for (x in 0 until sizeList) { - val chunkSize: Int = list[x].size - for (y in 0 until chunkSize) { - if (list[x][y] === c) { - return true - } + for (chunk in current) { + if (updated.contains(chunk)) { + chunk.update(player) + } else { + chunk.synchronize(player) } + last.add(chunk) } - return false } } \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags.java b/Server/src/main/core/game/world/update/flag/PlayerFlags.java index 41d0cb441..4c75ac71f 100644 --- a/Server/src/main/core/game/world/update/flag/PlayerFlags.java +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags.java @@ -3,6 +3,8 @@ package core.game.world.update.flag; import core.game.world.map.Location; import core.game.world.map.RegionChunk; +import java.util.LinkedList; + /** * A class holding a player's updating flags. * @author Emperor @@ -17,7 +19,7 @@ public final class PlayerFlags { /** * The last viewport. */ - private RegionChunk[][] lastViewport = new RegionChunk[13][13]; + private LinkedList lastViewport = new LinkedList<>(); /** * The location the player was standing on when last scene graph update @@ -70,7 +72,7 @@ public final class PlayerFlags { * Gets the lastViewport. * @return The lastViewport. */ - public RegionChunk[][] getLastViewport() { + public LinkedList getLastViewport() { return lastViewport; } @@ -78,7 +80,7 @@ public final class PlayerFlags { * Sets the lastViewport. * @param lastViewport The lastViewport to set. */ - public void setLastViewport(RegionChunk[][] lastViewport) { + public void setLastViewport(LinkedList lastViewport) { this.lastViewport = lastViewport; } From 9cade64ad934eb99911ab35739c2f3a0a897c397 Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 22:43:30 +0200 Subject: [PATCH 16/94] Revert --- .../core/game/node/entity/player/Player.java | 2 +- .../game/world/update/MapChunkRenderer.kt | 66 +++++++++++++------ .../game/world/update/flag/PlayerFlags.java | 8 +-- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index 77d205b01..cb94a83bd 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -856,7 +856,7 @@ public class Player extends Entity { getZoneMonitor().getZones().clear(); playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); - playerFlags.setLastViewport(new LinkedList<>()); + playerFlags.setLastViewport(new RegionChunk[13][13]); renderInfo.getLocalNpcs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index cf18cc8a3..47e93ff53 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -13,8 +13,6 @@ import kotlin.math.abs * @author Emperor */ object MapChunkRenderer { - const val buildAreaDepth = 6 - /** * Sends the map chunk rendering packet. * @param player The player. @@ -23,35 +21,61 @@ object MapChunkRenderer { fun render(player: Player) { val last = player.playerFlags.lastViewport val updated: MutableList = ArrayList() - val current: MutableList = ArrayList() + val current: MutableList> = ArrayList() + val buildAreaDepth = 6 for (dcx in -buildAreaDepth..+buildAreaDepth) { + val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { val newloc = player.location.chunkBase.transform(dcx*8, dcy*8, 0) - current.add(newloc.chunk) + addX.add(newloc.chunk) } + current.add(addX) } - val removeList = LinkedList() - for (chunk in last) { - if (current.contains(chunk)) { - updated.add(chunk) - } else { - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, chunk)) - removeList.add(chunk) + var sizeX = last.size + for (x in 0 until sizeX) { + val sizeY: Int = last[x].size + for (y in 0 until sizeY) { + val previous = last[x][y] ?: continue + if (!containsChunk(current, previous)) { + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) + } else { + updated.add(previous) + } } } - for (chunk in removeList) { - last.remove(chunk) - } - - for (chunk in current) { - if (updated.contains(chunk)) { - chunk.update(player) - } else { - chunk.synchronize(player) + sizeX = current.size + for (x in 0 until sizeX) { + val sizeY: Int = current[x].size + for (y in 0 until sizeY) { + val chunk = current[x][y] + if (!updated.contains(chunk)) { + chunk.synchronize(player) + } else { + chunk.update(player) + } + last[x][y] = current[x][y] } - last.add(chunk) } } + + /** + * Checks if the chunks list contains the specified region chunk. + * @param list The list to search. + * @param c The region chunk. + * @return `True` if so. + */ + private fun containsChunk(list: MutableList>, c: RegionChunk): Boolean { + val sizeList = list.size + for (x in 0 until sizeList) { + val chunkSize: Int = list[x].size + for (y in 0 until chunkSize) { + if (list[x][y] === c) { + return true + } + } + } + return false + } } \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags.java b/Server/src/main/core/game/world/update/flag/PlayerFlags.java index 4c75ac71f..41d0cb441 100644 --- a/Server/src/main/core/game/world/update/flag/PlayerFlags.java +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags.java @@ -3,8 +3,6 @@ package core.game.world.update.flag; import core.game.world.map.Location; import core.game.world.map.RegionChunk; -import java.util.LinkedList; - /** * A class holding a player's updating flags. * @author Emperor @@ -19,7 +17,7 @@ public final class PlayerFlags { /** * The last viewport. */ - private LinkedList lastViewport = new LinkedList<>(); + private RegionChunk[][] lastViewport = new RegionChunk[13][13]; /** * The location the player was standing on when last scene graph update @@ -72,7 +70,7 @@ public final class PlayerFlags { * Gets the lastViewport. * @return The lastViewport. */ - public LinkedList getLastViewport() { + public RegionChunk[][] getLastViewport() { return lastViewport; } @@ -80,7 +78,7 @@ public final class PlayerFlags { * Sets the lastViewport. * @param lastViewport The lastViewport to set. */ - public void setLastViewport(LinkedList lastViewport) { + public void setLastViewport(RegionChunk[][] lastViewport) { this.lastViewport = lastViewport; } From ea4eccafd227a7f2eef3b09cdc399575ae358b61 Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 22:47:38 +0200 Subject: [PATCH 17/94] Fix map rendering --- Server/src/main/core/game/world/update/MapChunkRenderer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 47e93ff53..23b428672 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -27,7 +27,7 @@ object MapChunkRenderer { for (dcx in -buildAreaDepth..+buildAreaDepth) { val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { - val newloc = player.location.chunkBase.transform(dcx*8, dcy*8, 0) + val newloc = player.location.chunkBase.transform(dcx*8, dcy*8, player.location.z) addX.add(newloc.chunk) } current.add(addX) From 0ca71d6bca36fbfb65db9259a36ef435daec917f Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 19 Jun 2026 22:51:09 +0200 Subject: [PATCH 18/94] build area depth nudge --- Server/src/main/core/game/world/update/MapChunkRenderer.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 23b428672..fadf94fb1 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -13,6 +13,8 @@ import kotlin.math.abs * @author Emperor */ object MapChunkRenderer { + const val buildAreaDepth = 6 + /** * Sends the map chunk rendering packet. * @param player The player. @@ -23,7 +25,6 @@ object MapChunkRenderer { val updated: MutableList = ArrayList() val current: MutableList> = ArrayList() - val buildAreaDepth = 6 for (dcx in -buildAreaDepth..+buildAreaDepth) { val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { From 7c4b0f19dd70a0fb99506136f235fa88e6c79e94 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 20 Jun 2026 19:27:23 +0200 Subject: [PATCH 19/94] Fix flashing --- .../global/skill/construction/HouseManager.java | 2 +- Server/src/main/core/game/world/map/RegionChunk.java | 4 ++-- .../main/core/game/world/update/MapChunkRenderer.kt | 10 ++++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Server/src/main/content/global/skill/construction/HouseManager.java b/Server/src/main/content/global/skill/construction/HouseManager.java index 48786ae1c..884ce5a7f 100644 --- a/Server/src/main/content/global/skill/construction/HouseManager.java +++ b/Server/src/main/content/global/skill/construction/HouseManager.java @@ -172,7 +172,7 @@ public final class HouseManager { } private void submitCloseLoadInterfacePulse(Player player) { - GameWorld.getPulser().submit(new Pulse(2, player) { + GameWorld.getPulser().submit(new Pulse(1, player) { @Override public boolean pulse() { player.getInterfaceManager().close(); diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 7ee787878..cf406ffca 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -393,11 +393,11 @@ public class RegionChunk { if (dyn == stat) { continue; } - if (stat != null) { + if (stat != null && (dyn == null || !dyn.isRenderable())) { ClearScenery.write(buffer, stat); updated = true; } - if (dyn != null) { + if (dyn != null && dyn.isRenderable()) { ConstructScenery.write(buffer, dyn); updated = true; } diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index fadf94fb1..9f6f0cff6 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -2,6 +2,8 @@ package core.game.world.update import core.game.node.entity.player.Player import core.game.world.map.RegionChunk +import core.game.world.map.RegionManager +import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk @@ -28,7 +30,7 @@ object MapChunkRenderer { for (dcx in -buildAreaDepth..+buildAreaDepth) { val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { - val newloc = player.location.chunkBase.transform(dcx*8, dcy*8, player.location.z) + val newloc = player.location.transform(dcx*8, dcy*8, 0) addX.add(newloc.chunk) } current.add(addX) @@ -39,10 +41,10 @@ object MapChunkRenderer { val sizeY: Int = last[x].size for (y in 0 until sizeY) { val previous = last[x][y] ?: continue - if (!containsChunk(current, previous)) { - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) - } else { + if (containsChunk(current, previous)) { updated.add(previous) + } else if (previous.region !is DynamicRegion) { //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) } } } From 1a48009b8507a551bfca96019fa5336291e5a39f Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 27 Jun 2026 15:28:37 +0200 Subject: [PATCH 20/94] barrage debugging --- .../node/entity/combat/spell/CombatSpell.java | 2 +- .../main/core/game/world/map/RegionManager.kt | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java index 6ac567b15..ce84e520d 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java @@ -121,7 +121,7 @@ public abstract class CombatSpell extends MagicSpell { List victims = new ArrayList<>(20); victims.add(target); - List surrounding = RegionManager.getLocalEntities(target.getLocation(), 1); + List surrounding = RegionManager.getLocalEntitiesIce(target.getLocation(), 1); for (Entity e : surrounding) { if (e == target || e == entity) { continue; diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 5586549f2..fa242a789 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -453,6 +453,37 @@ object RegionManager { @JvmStatic fun getSurroundingNPCs(npc: Entity, maximum: Int): List = getLocalEntities(npc.location, 1, maximum, null) @JvmStatic fun getLocalPlayersBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum, null) + @JvmStatic fun getLocalEntitiesIce(location: Location, distance: Int): List { + val maximum = 0 + val ignore = null + + val entities: MutableList = ArrayList(20) + for (cx in (location.absChunkX - 0)..(location.absChunkX + 0)) { + for (cy in (location.absChunkY - 0)..(location.absChunkY + 0)) { + println("cx = $cx, cy = $cy, loc = $location, cx shl 3 = ${cx shl 3}, cy shl 3 = ${cy shl 3}") + val loc = Location(cx shl 3, cy shl 3, location.z) + println("Grabbing chunk at $cx,$cy, which is location $loc") + val chunk = Location(cx shl 3, cy shl 3, location.z).chunk + if (Entity::class.java.isAssignableFrom(Player::class.java)) { + println("adding players, of which there are ${chunk.players.size}") + entities.addAll(chunk.players as Collection) + } + if (Entity::class.java.isAssignableFrom(NPC::class.java)) { + println("adding npcs, of which there are ${chunk.npcs.size}") + entities.addAll(chunk.npcs as Collection) + } + println("Processed a chunk, now have ${entities.size} entities") + } + } + val b = ZoneBorders(location.x - distance, location.y - distance, location.x + distance, location.y + distance) + var filtered = entities.filter { it != ignore && b.insideBorder(it.location.x, it.location.y) } + if (maximum > 0 && filtered.size > maximum) { + filtered = filtered.slice(0 until maximum) + } + println("After filtering, ${entities.size} entities") + return filtered + } + /** * Gets a random teleport location in the radius around the given location. * @param location The centre location. From fb7f569445982bac4c332305dbd97257ee4eccf7 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 27 Jun 2026 15:31:01 +0200 Subject: [PATCH 21/94] Fix barrage --- .../node/entity/combat/spell/CombatSpell.java | 2 +- .../main/core/game/world/map/RegionManager.kt | 35 ++----------------- 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java index ce84e520d..6ac567b15 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java @@ -121,7 +121,7 @@ public abstract class CombatSpell extends MagicSpell { List victims = new ArrayList<>(20); victims.add(target); - List surrounding = RegionManager.getLocalEntitiesIce(target.getLocation(), 1); + List surrounding = RegionManager.getLocalEntities(target.getLocation(), 1); for (Entity e : surrounding) { if (e == target || e == entity) { continue; diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index fa242a789..0407a569f 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -429,10 +429,10 @@ object RegionManager { for (cx in (location.absChunkX - 2)..(location.absChunkX + 2)) { for (cy in (location.absChunkY - 2)..(location.absChunkY + 2)) { val chunk = Location(cx shl 3, cy shl 3, location.z).chunk - if (Player::class.java.isAssignableFrom(T::class.java)) { + if (T::class.java.isAssignableFrom(Player::class.java)) { entities.addAll(chunk.players as Collection) } - if (NPC::class.java.isAssignableFrom(T::class.java)) { + if (T::class.java.isAssignableFrom(NPC::class.java)) { entities.addAll(chunk.npcs as Collection) } } @@ -453,37 +453,6 @@ object RegionManager { @JvmStatic fun getSurroundingNPCs(npc: Entity, maximum: Int): List = getLocalEntities(npc.location, 1, maximum, null) @JvmStatic fun getLocalPlayersBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum, null) - @JvmStatic fun getLocalEntitiesIce(location: Location, distance: Int): List { - val maximum = 0 - val ignore = null - - val entities: MutableList = ArrayList(20) - for (cx in (location.absChunkX - 0)..(location.absChunkX + 0)) { - for (cy in (location.absChunkY - 0)..(location.absChunkY + 0)) { - println("cx = $cx, cy = $cy, loc = $location, cx shl 3 = ${cx shl 3}, cy shl 3 = ${cy shl 3}") - val loc = Location(cx shl 3, cy shl 3, location.z) - println("Grabbing chunk at $cx,$cy, which is location $loc") - val chunk = Location(cx shl 3, cy shl 3, location.z).chunk - if (Entity::class.java.isAssignableFrom(Player::class.java)) { - println("adding players, of which there are ${chunk.players.size}") - entities.addAll(chunk.players as Collection) - } - if (Entity::class.java.isAssignableFrom(NPC::class.java)) { - println("adding npcs, of which there are ${chunk.npcs.size}") - entities.addAll(chunk.npcs as Collection) - } - println("Processed a chunk, now have ${entities.size} entities") - } - } - val b = ZoneBorders(location.x - distance, location.y - distance, location.x + distance, location.y + distance) - var filtered = entities.filter { it != ignore && b.insideBorder(it.location.x, it.location.y) } - if (maximum > 0 && filtered.size > maximum) { - filtered = filtered.slice(0 until maximum) - } - println("After filtering, ${entities.size} entities") - return filtered - } - /** * Gets a random teleport location in the radius around the given location. * @param location The centre location. From c794cb9fee7545871bbf039a012255336b1e4bed Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 27 Jun 2026 15:44:46 +0200 Subject: [PATCH 22/94] Improve vinesweeper hole restoration --- .../minigame/vinesweeper/Vinesweeper.kt | 9 ++++++- .../main/core/game/world/map/RegionChunk.java | 24 +++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt index d4461b424..7d3fec4a0 100644 --- a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt +++ b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt @@ -665,7 +665,14 @@ class VinesweeperNPC : AbstractNPC { 1 -> { animate(Animation(Animations.GNOME_FARMER_SPADE_SMACK_8732)) sendChat(FARMER_FLAG_LINES.DEAD_PLANT.line) - SceneryBuilder.replace(scenery, scenery.transform(HOLES[0])) + var originalHoleId = HOLES[0] + for (obj in scenery.location.chunk.getStatObjects(scenery.location.chunkOffsetX, scenery.location.chunkOffsetY)) { + if (obj?.id != null) { + originalHoleId = obj.id + break + } + } + SceneryBuilder.replace(scenery, scenery.transform(originalHoleId)) } 2 -> { animate(Animation(Animations.GNOME_FARMER_CLEAR_HOLES_8724)) diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index cf406ffca..111ce88b8 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -509,15 +509,29 @@ public class RegionChunk { } /** - * Gets the sceneries located on the coordinates in this chunk. - * @param chunkX The chunk x-coordinate (0-7). - * @param chunkY The chunk y-coordinate (0-7). + * Gets the dynamic sceneries located on the coordinates in this chunk. + * @param chunkOffsetX The x coordinate within the chunk (0-7). + * @param chunkOffsetY The y coordinate within the chunk (0-7). * @return The objects. */ - public Scenery[] getObjects(int chunkX, int chunkY) { + public Scenery[] getObjects(int chunkOffsetX, int chunkOffsetY) { Scenery[] result = new Scenery[ARRAY_SIZE]; for (int i = 0; i < objects.length; i++) { - result[i] = objects[i][chunkX][chunkY]; + result[i] = objects[i][chunkOffsetX][chunkOffsetY]; + } + return result; + } + + /** + * Gets the static sceneries located on the coordinates in this chunk. + * @param chunkOffsetX The x coordinate within the chunk (0-7). + * @param chunkOffsetY The y coordinate within the chunk (0-7). + * @return The objects. + */ + public Scenery[] getStatObjects(int chunkOffsetX, int chunkOffsetY) { + Scenery[] result = new Scenery[ARRAY_SIZE]; + for (int i = 0; i < statObjects.length; i++) { + result[i] = statObjects[i][chunkOffsetX][chunkOffsetY]; } return result; } From 97afdb4bb00d2e47c83c1f5ac3688ec232e11967 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 27 Jun 2026 18:59:20 +0200 Subject: [PATCH 23/94] Random and irrelevant changes --- .../skill/summoning/familiar/ForgeRegentNPC.java | 2 +- .../main/core/game/world/map/RegionChunk.java | 6 +++--- .../core/game/world/update/MapChunkRenderer.kt | 16 ++++++++++------ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java b/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java index 294a535fd..3217290a8 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java @@ -152,7 +152,7 @@ public class ForgeRegentNPC extends Familiar { familiar.moveStep(); GroundItemManager.destroy(ground); player.getSkills().addExperience(Skills.FIREMAKING, log.getXp() + 10); - familiar.faceLocation(object.getFaceLocation(familiar.getLocation())); + familiar.faceLocation(object.getFaceLocation(familiar.getLocation())); SceneryBuilder.add(object, log.getLife(), FireMakingPulse.getAsh(player, log, object)); if (player.getLocation().getRegionId() == 10806) { player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 9); diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 111ce88b8..89813e385 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -81,7 +81,7 @@ public class RegionChunk { /** * The update flags. */ - private List> updateFlags = new ArrayList<>(20); + private final List> updateFlags = new ArrayList<>(20); /** * The region flags. @@ -481,8 +481,8 @@ public class RegionChunk { IoBuffer buffer = UpdateAreaPosition.getChunkUpdateBuffer(player, currentBase); Object[] flagsArray = updateFlags.toArray(); int size = flagsArray.length; - for (Object o : flagsArray) { - UpdateFlag flag = (UpdateFlag) o; + for (int i = 0; i < size; i++) { + UpdateFlag flag = (UpdateFlag) flagsArray[i]; flag.writeDynamic(buffer, player); } player.getSession().write(buffer); diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 9f6f0cff6..d87a7b295 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -43,9 +43,12 @@ object MapChunkRenderer { val previous = last[x][y] ?: continue if (containsChunk(current, previous)) { updated.add(previous) - } else if (previous.region !is DynamicRegion) { //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) + continue } + if (previous.region is DynamicRegion) { + continue //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one + } + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) } } sizeX = current.size @@ -53,12 +56,13 @@ object MapChunkRenderer { val sizeY: Int = current[x].size for (y in 0 until sizeY) { val chunk = current[x][y] - if (!updated.contains(chunk)) { - chunk.synchronize(player) - } else { + if (updated.contains(chunk)) { chunk.update(player) + } else { + println("Syncing ${chunk.currentBase}") + chunk.synchronize(player) } - last[x][y] = current[x][y] + last[x][y] = chunk } } } From 5f008442219189cb30dad539455de1caa12dd1db Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 27 Jun 2026 19:46:41 +0200 Subject: [PATCH 24/94] Simpler renderer but same issue --- .../core/game/node/entity/player/Player.java | 3 +- .../game/world/update/MapChunkRenderer.kt | 81 ++++++------------- .../game/world/update/flag/PlayerFlags.java | 13 ++- 3 files changed, 37 insertions(+), 60 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index cb94a83bd..2303a150b 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -93,6 +93,7 @@ import static core.api.utils.PermadeathKt.permadeath; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_BASE; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_DEATHS; import static core.tools.GlobalsKt.colorize; +import static java.util.Collections.emptySet; import static org.rs09.consts.Items.BONES_526; /** @@ -856,7 +857,7 @@ public class Player extends Entity { getZoneMonitor().getZones().clear(); playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); - playerFlags.setLastViewport(new RegionChunk[13][13]); + playerFlags.setLastViewport(emptySet()); renderInfo.getLocalNpcs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index d87a7b295..9b9f66a74 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -23,66 +23,37 @@ object MapChunkRenderer { */ @JvmStatic fun render(player: Player) { - val last = player.playerFlags.lastViewport - val updated: MutableList = ArrayList() - val current: MutableList> = ArrayList() - - for (dcx in -buildAreaDepth..+buildAreaDepth) { - val addX = ArrayList() - for (dcy in -buildAreaDepth..+buildAreaDepth) { - val newloc = player.location.transform(dcx*8, dcy*8, 0) - addX.add(newloc.chunk) + val lastSet = player.playerFlags.lastViewport + val currentSet = HashSet() + for (dcx in -buildAreaDepth..buildAreaDepth) { + for (dcy in -buildAreaDepth..buildAreaDepth) { + val loc = player.location.transform(dcx * 8, dcy * 8, 0) + currentSet.add(loc.chunk) } - current.add(addX) } - var sizeX = last.size - for (x in 0 until sizeX) { - val sizeY: Int = last[x].size - for (y in 0 until sizeY) { - val previous = last[x][y] ?: continue - if (containsChunk(current, previous)) { - updated.add(previous) - continue - } - if (previous.region is DynamicRegion) { - continue //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one - } - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) - } - } - sizeX = current.size - for (x in 0 until sizeX) { - val sizeY: Int = current[x].size - for (y in 0 until sizeY) { - val chunk = current[x][y] - if (updated.contains(chunk)) { - chunk.update(player) - } else { - println("Syncing ${chunk.currentBase}") - chunk.synchronize(player) - } - last[x][y] = chunk - } - } - } + // Compute diffs + val entered = currentSet - lastSet + val stayed = currentSet intersect lastSet + val exited = lastSet - currentSet - /** - * Checks if the chunks list contains the specified region chunk. - * @param list The list to search. - * @param c The region chunk. - * @return `True` if so. - */ - private fun containsChunk(list: MutableList>, c: RegionChunk): Boolean { - val sizeList = list.size - for (x in 0 until sizeList) { - val chunkSize: Int = list[x].size - for (y in 0 until chunkSize) { - if (list[x][y] === c) { - return true - } + // 1. New chunks → synchronize + for (c in entered) { + c.synchronize(player) + } + + // 2. Existing chunks → update + for (c in stayed) { + c.update(player) + } + + // 3. Exited chunks → clear + for (c in exited) { + if (c.region !is DynamicRegion) { + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, c)) } } - return false + + player.playerFlags.lastViewport = currentSet } } \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags.java b/Server/src/main/core/game/world/update/flag/PlayerFlags.java index 41d0cb441..86feac373 100644 --- a/Server/src/main/core/game/world/update/flag/PlayerFlags.java +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags.java @@ -1,7 +1,13 @@ package core.game.world.update.flag; import core.game.world.map.Location; +import core.game.world.map.Region; import core.game.world.map.RegionChunk; +import core.game.world.update.MapChunkRenderer; + +import java.util.Set; + +import static java.util.Collections.emptySet; /** * A class holding a player's updating flags. @@ -17,7 +23,7 @@ public final class PlayerFlags { /** * The last viewport. */ - private RegionChunk[][] lastViewport = new RegionChunk[13][13]; + private Set lastViewport = emptySet(); /** * The location the player was standing on when last scene graph update @@ -70,7 +76,7 @@ public final class PlayerFlags { * Gets the lastViewport. * @return The lastViewport. */ - public RegionChunk[][] getLastViewport() { + public Set getLastViewport() { return lastViewport; } @@ -78,8 +84,7 @@ public final class PlayerFlags { * Sets the lastViewport. * @param lastViewport The lastViewport to set. */ - public void setLastViewport(RegionChunk[][] lastViewport) { + public void setLastViewport(Set lastViewport) { this.lastViewport = lastViewport; } - } \ No newline at end of file From 5beca2839c590cf1dff3aeff7fa9fca18d6ee6b9 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 00:06:19 +0200 Subject: [PATCH 25/94] I fucking hate arios --- .../game/node/entity/impl/WalkingQueue.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java index d10215b40..d0062cc8e 100644 --- a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java +++ b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java @@ -247,9 +247,7 @@ public final class WalkingQueue { if (last == null) { last = p.getLocation(); } - if ((last.getRegionX() - entity.getLocation().getRegionX()) >= 4 || (last.getRegionX() - entity.getLocation().getRegionX()) <= -4) { - p.getPlayerFlags().setUpdateSceneGraph(true); - } else if ((last.getRegionY() - entity.getLocation().getRegionY()) >= 4 || (last.getRegionY() - entity.getLocation().getRegionY()) <= -4) { + if (last.getChunk() != p.getLocation().getChunk()) { p.getPlayerFlags().setUpdateSceneGraph(true); } } @@ -272,18 +270,7 @@ public final class WalkingQueue { if (lastRegion == null) { lastRegion = location; } - int rx = lastRegion.getRegionX(); - int ry = lastRegion.getRegionY(); - int cx = location.getRegionX(); - int cy = location.getRegionY(); - if ((rx - cx) >= 4) { - p.getPlayerFlags().setUpdateSceneGraph(true); - } else if ((rx - cx) <= -4) { - p.getPlayerFlags().setUpdateSceneGraph(true); - } - if ((ry - cy) >= 4) { - p.getPlayerFlags().setUpdateSceneGraph(true); - } else if ((ry - cy) <= -4) { + if (lastRegion.getChunk() != location.getChunk()) { p.getPlayerFlags().setUpdateSceneGraph(true); } if (move && p.getPlayerFlags().isUpdateSceneGraph()) { From b9b350ef3a1966d5ae3577dc261b2de9d44150d0 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 00:14:12 +0200 Subject: [PATCH 26/94] Revert "Simpler renderer but same issue" This reverts commit 78f287e5ca27ec4a8d17cf6fd50869d6f6348ce3. --- .../core/game/node/entity/player/Player.java | 3 +- .../game/world/update/MapChunkRenderer.kt | 83 +++++++++++++------ .../game/world/update/flag/PlayerFlags.java | 13 +-- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index 2303a150b..cb94a83bd 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -93,7 +93,6 @@ import static core.api.utils.PermadeathKt.permadeath; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_BASE; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_DEATHS; import static core.tools.GlobalsKt.colorize; -import static java.util.Collections.emptySet; import static org.rs09.consts.Items.BONES_526; /** @@ -857,7 +856,7 @@ public class Player extends Entity { getZoneMonitor().getZones().clear(); playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); - playerFlags.setLastViewport(emptySet()); + playerFlags.setLastViewport(new RegionChunk[13][13]); renderInfo.getLocalNpcs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 9b9f66a74..d87a7b295 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -23,37 +23,66 @@ object MapChunkRenderer { */ @JvmStatic fun render(player: Player) { - val lastSet = player.playerFlags.lastViewport - val currentSet = HashSet() - for (dcx in -buildAreaDepth..buildAreaDepth) { - for (dcy in -buildAreaDepth..buildAreaDepth) { - val loc = player.location.transform(dcx * 8, dcy * 8, 0) - currentSet.add(loc.chunk) + val last = player.playerFlags.lastViewport + val updated: MutableList = ArrayList() + val current: MutableList> = ArrayList() + + for (dcx in -buildAreaDepth..+buildAreaDepth) { + val addX = ArrayList() + for (dcy in -buildAreaDepth..+buildAreaDepth) { + val newloc = player.location.transform(dcx*8, dcy*8, 0) + addX.add(newloc.chunk) + } + current.add(addX) + } + + var sizeX = last.size + for (x in 0 until sizeX) { + val sizeY: Int = last[x].size + for (y in 0 until sizeY) { + val previous = last[x][y] ?: continue + if (containsChunk(current, previous)) { + updated.add(previous) + continue + } + if (previous.region is DynamicRegion) { + continue //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one + } + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) } } - - // Compute diffs - val entered = currentSet - lastSet - val stayed = currentSet intersect lastSet - val exited = lastSet - currentSet - - // 1. New chunks → synchronize - for (c in entered) { - c.synchronize(player) - } - - // 2. Existing chunks → update - for (c in stayed) { - c.update(player) - } - - // 3. Exited chunks → clear - for (c in exited) { - if (c.region !is DynamicRegion) { - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, c)) + sizeX = current.size + for (x in 0 until sizeX) { + val sizeY: Int = current[x].size + for (y in 0 until sizeY) { + val chunk = current[x][y] + if (updated.contains(chunk)) { + chunk.update(player) + } else { + println("Syncing ${chunk.currentBase}") + chunk.synchronize(player) + } + last[x][y] = chunk } } + } - player.playerFlags.lastViewport = currentSet + /** + * Checks if the chunks list contains the specified region chunk. + * @param list The list to search. + * @param c The region chunk. + * @return `True` if so. + */ + private fun containsChunk(list: MutableList>, c: RegionChunk): Boolean { + val sizeList = list.size + for (x in 0 until sizeList) { + val chunkSize: Int = list[x].size + for (y in 0 until chunkSize) { + if (list[x][y] === c) { + return true + } + } + } + return false } } \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags.java b/Server/src/main/core/game/world/update/flag/PlayerFlags.java index 86feac373..41d0cb441 100644 --- a/Server/src/main/core/game/world/update/flag/PlayerFlags.java +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags.java @@ -1,13 +1,7 @@ package core.game.world.update.flag; import core.game.world.map.Location; -import core.game.world.map.Region; import core.game.world.map.RegionChunk; -import core.game.world.update.MapChunkRenderer; - -import java.util.Set; - -import static java.util.Collections.emptySet; /** * A class holding a player's updating flags. @@ -23,7 +17,7 @@ public final class PlayerFlags { /** * The last viewport. */ - private Set lastViewport = emptySet(); + private RegionChunk[][] lastViewport = new RegionChunk[13][13]; /** * The location the player was standing on when last scene graph update @@ -76,7 +70,7 @@ public final class PlayerFlags { * Gets the lastViewport. * @return The lastViewport. */ - public Set getLastViewport() { + public RegionChunk[][] getLastViewport() { return lastViewport; } @@ -84,7 +78,8 @@ public final class PlayerFlags { * Sets the lastViewport. * @param lastViewport The lastViewport to set. */ - public void setLastViewport(Set lastViewport) { + public void setLastViewport(RegionChunk[][] lastViewport) { this.lastViewport = lastViewport; } + } \ No newline at end of file From c81bd3cd7c5c9efa1c1dbd509a0030c12307a5b1 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 00:20:08 +0200 Subject: [PATCH 27/94] fix --- Server/src/main/core/game/world/update/MapChunkRenderer.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index d87a7b295..001327a93 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -2,13 +2,11 @@ package core.game.world.update import core.game.node.entity.player.Player import core.game.world.map.RegionChunk -import core.game.world.map.RegionManager import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk import java.util.* -import kotlin.math.abs /** * Handles the rendering of the player's surrounding map chunks. @@ -59,7 +57,6 @@ object MapChunkRenderer { if (updated.contains(chunk)) { chunk.update(player) } else { - println("Syncing ${chunk.currentBase}") chunk.synchronize(player) } last[x][y] = chunk From c96673989ca8d4729ca5deaaed1c179d6ff93c9b Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 01:01:27 +0200 Subject: [PATCH 28/94] Fix POH flashing correctly --- Server/src/main/core/game/node/entity/player/Player.java | 5 +++++ .../src/main/core/game/world/update/MapChunkRenderer.kt | 8 ++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index cb94a83bd..ea08ea6bf 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -545,6 +545,11 @@ public class Player extends Entity { super.update(); if (playerFlags.isUpdateSceneGraph()) { updateSceneGraph(false); + // The scene graph rebuild wipes the client's build area. Reset lastViewport so MapChunkRenderer + // re-synchronizes every visible chunk this tick (restoring scenery immediately and re-sending + // each ground item exactly once), rather than only sending incremental updates for overlap. + // This fixes POHs flashing their cached states (hotspots) on z transition. + playerFlags.setLastViewport(new RegionChunk[13][13]); } PlayerRenderer.render(this); NPCRenderer.render(this); diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 001327a93..8f1b84171 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -2,7 +2,6 @@ package core.game.world.update import core.game.node.entity.player.Player import core.game.world.map.RegionChunk -import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk @@ -41,12 +40,9 @@ object MapChunkRenderer { val previous = last[x][y] ?: continue if (containsChunk(current, previous)) { updated.add(previous) - continue + } else { + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) } - if (previous.region is DynamicRegion) { - continue //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one - } - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) } } sizeX = current.size From 4eeda96ff23a29a60c75f71b521b2b905344188f Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 01:18:54 +0200 Subject: [PATCH 29/94] Critical fix because Devin problems --- .../core/game/node/entity/impl/WalkingQueue.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java index d0062cc8e..5a68c1f6c 100644 --- a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java +++ b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java @@ -6,13 +6,8 @@ import core.game.node.entity.player.Player; import core.game.node.entity.skill.Skills; import core.game.node.item.Item; import core.game.node.item.GroundItem; -import core.game.world.map.Direction; -import core.game.world.map.Location; -import core.game.world.map.Point; -import core.game.world.map.RegionManager; -import core.game.world.update.flag.chunk.ItemUpdateFlag; +import core.game.world.map.*; import core.tools.Log; -import core.tools.SystemLogger; import java.util.Deque; import java.util.ArrayDeque; @@ -247,7 +242,9 @@ public final class WalkingQueue { if (last == null) { last = p.getLocation(); } - if (last.getChunk() != p.getLocation().getChunk()) { + int rx = last.getRegionX(), ry = last.getRegionY(); + int cx = p.getLocation().getRegionX(), cy = p.getLocation().getRegionY(); + if (Math.abs(rx - cx) >= 4 || Math.abs(ry - cy) >= 4) { p.getPlayerFlags().setUpdateSceneGraph(true); } } @@ -270,7 +267,9 @@ public final class WalkingQueue { if (lastRegion == null) { lastRegion = location; } - if (lastRegion.getChunk() != location.getChunk()) { + int rx = lastRegion.getRegionX(), ry = lastRegion.getRegionY(); + int cx = location.getRegionX(), cy = location.getRegionY(); + if (Math.abs(rx - cx) >= 4 || Math.abs(ry - cy) >= 4) { p.getPlayerFlags().setUpdateSceneGraph(true); } if (move && p.getPlayerFlags().isUpdateSceneGraph()) { From a22fd8185f4c8b083ddefca92ad16eaf5a2deab1 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 01:55:33 +0200 Subject: [PATCH 30/94] Critical fixes that fix all the current problems: no flashing POHs, no duplicate items, no missing items when transitioning >3 chunks, no accidental goddamn game protocol changes --- .../core/game/node/entity/player/Player.java | 5 ---- .../main/core/game/world/map/RegionChunk.java | 17 +++++++------ .../game/world/update/MapChunkRenderer.kt | 25 ++++++++++++------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index ea08ea6bf..cb94a83bd 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -545,11 +545,6 @@ public class Player extends Entity { super.update(); if (playerFlags.isUpdateSceneGraph()) { updateSceneGraph(false); - // The scene graph rebuild wipes the client's build area. Reset lastViewport so MapChunkRenderer - // re-synchronizes every visible chunk this tick (restoring scenery immediately and re-sending - // each ground item exactly once), rather than only sending incremental updates for overlap. - // This fixes POHs flashing their cached states (hotspots) on z transition. - playerFlags.setLastViewport(new RegionChunk[13][13]); } PlayerRenderer.render(this); NPCRenderer.render(this); diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 89813e385..f5d57337c 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -252,7 +252,7 @@ public class RegionChunk { * @param item The item. */ public void add(GroundItem item) { - items.add(item); + getItems().add(item); if (item.isPrivate()) { if (item.getDropper() != null) { PacketRepository.send(ConstructGroundItem.class, new BuildItemContext(item.getDropper(), item)); @@ -404,12 +404,15 @@ public class RegionChunk { } } } - ArrayList totalItems = drawItems(items, player); - for (GroundItem item : totalItems) { - if (item != null && item.isActive() && item.getLocation() != null) { - if (!item.isPrivate() || item.droppedBy(player)) { - ConstructGroundItem.write(buffer, item); - updated = true; + // Dynamic regions (POHs etc.) deliver items once via add(GroundItem) and the client retains them across scene rebuilds; + // re-sending here would duplicate them (the client doesn't de-dup). Static regions still need it for chunks entering view. + if (!(getRegion() instanceof DynamicRegion)) { + ArrayList totalItems = drawItems(items, player); + for (GroundItem item : totalItems) { + if (item != null && item.isActive() && item.getLocation() != null) { + if (!item.isPrivate() || item.droppedBy(player)) { + ConstructGroundItem.write(buffer, item); + } } } } diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 8f1b84171..7d8976905 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -1,7 +1,8 @@ package core.game.world.update - import core.game.node.entity.player.Player +import core.game.world.map.Location import core.game.world.map.RegionChunk +import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk @@ -13,21 +14,23 @@ import java.util.* */ object MapChunkRenderer { const val buildAreaDepth = 6 - - /** - * Sends the map chunk rendering packet. - * @param player The player. - */ @JvmStatic fun render(player: Player) { val last = player.playerFlags.lastViewport val updated: MutableList = ArrayList() val current: MutableList> = ArrayList() + // Center the build area on the loaded scene anchor (lastSceneGraph), NOT the live player position. + // The client's 13x13 build area is anchored at lastSceneGraph; addressing chunks relative to it keeps + // every chunk packet inside the client's scene window even when the player has drifted up to 3 chunks + // from the anchor (the scene graph only rebuilds at a drift of 4). Using player.location here instead + // pushes the viewport edge to drift+6 chunks from the anchor, off-window, so edge items never render. + val anchor = player.playerFlags.lastSceneGraph ?: player.location + val center = Location.create(anchor.x, anchor.y, player.location.z) for (dcx in -buildAreaDepth..+buildAreaDepth) { val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { - val newloc = player.location.transform(dcx*8, dcy*8, 0) + val newloc = center.transform(dcx * 8, dcy * 8, 0) addX.add(newloc.chunk) } current.add(addX) @@ -40,11 +43,15 @@ object MapChunkRenderer { val previous = last[x][y] ?: continue if (containsChunk(current, previous)) { updated.add(previous) - } else { - PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) + continue } + if (previous.region is DynamicRegion) { + continue //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one + } + PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) } } + sizeX = current.size for (x in 0 until sizeX) { val sizeY: Int = current[x].size From 8a7aa2a1b937acdb3e065d5f5292b7cd5d1f8674 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 06:30:54 +0200 Subject: [PATCH 31/94] Fix dumb crap --- Server/src/main/core/game/world/map/RegionChunk.java | 1 + Server/src/main/core/game/world/update/MapChunkRenderer.kt | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index f5d57337c..94abe9189 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -412,6 +412,7 @@ public class RegionChunk { if (item != null && item.isActive() && item.getLocation() != null) { if (!item.isPrivate() || item.droppedBy(player)) { ConstructGroundItem.write(buffer, item); + updated = true; } } } diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 7d8976905..ff26864e6 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -1,4 +1,5 @@ package core.game.world.update + import core.game.node.entity.player.Player import core.game.world.map.Location import core.game.world.map.RegionChunk @@ -14,6 +15,11 @@ import java.util.* */ object MapChunkRenderer { const val buildAreaDepth = 6 + + /** + * Sends the map chunk rendering packet. + * @param player The player. + */ @JvmStatic fun render(player: Player) { val last = player.playerFlags.lastViewport From bd2887919b1bed1938eb60033ac14b4aff67196f Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 07:11:23 +0200 Subject: [PATCH 32/94] small fixes --- .../content/global/ame/events/evilchicken/EvilChickenNPC.kt | 3 +-- .../content/region/morytania/handlers/MortMyreGhastNPC.kt | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt b/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt index c945d2f6e..4ae677997 100644 --- a/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt +++ b/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt @@ -40,8 +40,7 @@ class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventN sendMessage(player, "The Evil Chicken realises you're out of range and vanishes.") sentMessage = true terminate() - } - if (getWorldTicks() % 10 == 0) { + } else if (getWorldTicks() % 10 == 0) { sendChat(phrases.random().replace("@name", player.username.capitalize())) } } diff --git a/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt b/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt index bd94c1de3..8aeac41fd 100644 --- a/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt +++ b/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt @@ -38,7 +38,7 @@ class MortMyreGhastNPC : AbstractNPC { super.handleTickActions() if(id == ids[0] && RandomFunction.roll(35)){ val players = RegionManager.getLocalPlayers(location, 5).filter { - return@filter it.inCombat() + return@filter !it.inCombat() } if(players.isNotEmpty()){ val player = players.random() @@ -106,4 +106,4 @@ class MortMyreGhastNPC : AbstractNPC { } } } -} \ No newline at end of file +} From d1550675bfa28cd2dce659d8455ef9d3c6401efb Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 07:49:29 +0200 Subject: [PATCH 33/94] fix remaining bugs --- .../ardougne/quest/hazeelcult/HazeelCultListeners.kt | 10 ++++------ Server/src/main/core/game/node/entity/npc/NPC.java | 1 - .../main/core/game/world/map/build/DynamicRegion.java | 9 ++++++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/HazeelCultListeners.kt b/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/HazeelCultListeners.kt index cd6ac6007..53ed92a3d 100644 --- a/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/HazeelCultListeners.kt +++ b/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/HazeelCultListeners.kt @@ -173,18 +173,16 @@ class HazeelCultListeners : InteractionListener { } // chest with hazeel scroll. unlocks with key, opens, and contains the scroll. - onUseWith(IntType.SCENERY, CHEST_KEY, Scenery.CHEST_2856) { player, _, _ -> + onUseWith(IntType.SCENERY, CHEST_KEY, Scenery.CHEST_2856) { player, _, node -> sendMessage(player, "You unlock the chest.") animate(player, Animations.HUMAN_OPEN_CHEST_536) - addScenery(Scenery.CHEST_2857,CHEST_LOCATION, 2, 10) - removeScenery(core.game.node.scenery.Scenery(Scenery.CHEST_2856, Location(2565, 3272, 2))) + replaceScenery(node.asScenery(), Scenery.CHEST_2857, 20) return@onUseWith true } // chest with hazeel scroll. unlocks with key, opens, and contains the scroll. - on(Scenery.CHEST_2857, IntType.SCENERY, "Close") { _, _ -> - addScenery(Scenery.CHEST_2856, CHEST_LOCATION, 2, 10) - removeScenery(core.game.node.scenery.Scenery(Scenery.CHEST_2857, CHEST_LOCATION)) + on(Scenery.CHEST_2857, IntType.SCENERY, "Close") { _, node -> + replaceScenery(node.asScenery(), Scenery.CHEST_2856, 20) return@on true } diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index 59629bdde..6fa12f211 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -1059,5 +1059,4 @@ public class NPC extends Entity { public void setNeverWalks(boolean neverWalks) { this.neverWalks = neverWalks; } - } diff --git a/Server/src/main/core/game/world/map/build/DynamicRegion.java b/Server/src/main/core/game/world/map/build/DynamicRegion.java index 6e0d06031..7e5ce124a 100644 --- a/Server/src/main/core/game/world/map/build/DynamicRegion.java +++ b/Server/src/main/core/game/world/map/build/DynamicRegion.java @@ -292,7 +292,14 @@ public final class DynamicRegion extends Region { replacement.rebaseObjects(); replacement.rebuildFlags(orig); replacement.syncFlagsToRegionManager(); - replacement.getNpcs().addAll(orig.getNpcs()); //DO NOT create a copy npc, because it won't be initialized! + for (NPC npc : orig.getNpcs()) { + Location newLoc = currentBase.transform(npc.getLocation().getChunkOffsetX(), npc.getLocation().getChunkOffsetY(), 0); + NPC copy = NPC.create(npc.getId(), newLoc, npc.getDirection()); + copy.setAggressive(npc.isAggressive()); + copy.setRespawn(npc.isRespawn()); + copy.setWalks(npc.isWalks()); + copy.init(); + } } @Override From 868845eaa90998fc282e6737baf26f0ab796c54c Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 08:21:34 +0200 Subject: [PATCH 34/94] undo incorrect tabs/spaces conversion --- .../item/withitem/SoftclayPlugin.java | 218 +++++++++--------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java index bf445c470..fc63daa34 100644 --- a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java +++ b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java @@ -21,127 +21,127 @@ import java.util.Objects; @Initializable public final class SoftclayPlugin extends UseWithHandler { - /** - * Represents the clay item. - */ - private static final Item CLAY = new Item(Items.CLAY_434); + /** + * Represents the clay item. + */ + private static final Item CLAY = new Item(Items.CLAY_434); - /** - * Represents the soft clay item. - */ - private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); + /** + * Represents the soft clay item. + */ + private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); - /** - * Represents the bowl of water item. - */ - private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); + /** + * Represents the bowl of water item. + */ + private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); - /** - * Represents the empty bowl item. - */ - private static final Item BOWL = new Item(Items.BOWL_1923); + /** + * Represents the empty bowl item. + */ + private static final Item BOWL = new Item(Items.BOWL_1923); - /** - * Represents the empty bucket item. - */ - private static final Item BUCKET = new Item(Items.BUCKET_1925); + /** + * Represents the empty bucket item. + */ + private static final Item BUCKET = new Item(Items.BUCKET_1925); - /** - * Represents the bucket of water item. - */ - private static final Item BUCKET_OF_WATER = new Item(Items.BUCKET_OF_WATER_1929); + /** + * Represents the bucket of water item. + */ + private static final Item BUCKET_OF_WATER = new Item(Items.BUCKET_OF_WATER_1929); - /** - * Represents the jug item. - */ - private static final Item JUG = new Item(Items.JUG_1935); + /** + * Represents the jug item. + */ + private static final Item JUG = new Item(Items.JUG_1935); - /** - * Represents the jug of water item. - */ - private static final Item JUG_OF_WATER = new Item(Items.JUG_OF_WATER_1937); + /** + * Represents the jug of water item. + */ + private static final Item JUG_OF_WATER = new Item(Items.JUG_OF_WATER_1937); - /** - * Constructs a new {@code SoftclayPlugin} {@code Object}. - */ - public SoftclayPlugin() { - super(434); - } + /** + * Constructs a new {@code SoftclayPlugin} {@code Object}. + */ + public SoftclayPlugin() { + super(434); + } - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(1921, ITEM_TYPE, this); - addHandler(1929, ITEM_TYPE, this); - addHandler(1937, ITEM_TYPE, this); - return this; - } + @Override + public Plugin newInstance(Object arg) throws Throwable { + addHandler(1921, ITEM_TYPE, this); + addHandler(1929, ITEM_TYPE, this); + addHandler(1937, ITEM_TYPE, this); + return this; + } - @Override - public boolean handle(final NodeUsageEvent event) { - final Player player = event.getPlayer(); - SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, SOFT_CLAY) { - @Override - public void create(final int amount, int index) { - player.getPulseManager().run(new Pulse(2, player) { - int count; + @Override + public boolean handle(final NodeUsageEvent event) { + final Player player = event.getPlayer(); + SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, SOFT_CLAY) { + @Override + public void create(final int amount, int index) { + player.getPulseManager().run(new Pulse(2, player) { + int count; - @Override - public boolean pulse() { - if (!SoftclayPlugin.this.create(player, event)) { - return true; - } - return ++count >= amount; - } - }); - } + @Override + public boolean pulse() { + if (!SoftclayPlugin.this.create(player, event)) { + return true; + } + return ++count >= amount; + } + }); + } - @Override - public int getAll(int index) { - return player.getInventory().getAmount(CLAY); - } - }; - if (player.getInventory().getAmount(CLAY) == 1) { - create(player, event); - } else { - handler.open(); - } - return true; - } + @Override + public int getAll(int index) { + return player.getInventory().getAmount(CLAY); + } + }; + if (player.getInventory().getAmount(CLAY) == 1) { + create(player, event); + } else { + handler.open(); + } + return true; + } - /** - * Creates a soft clay. - * @param player the player. - * @param event the event. - * @return {@code True} if so. - */ - private boolean create(final Player player, NodeUsageEvent event) { - Item removeItem = null; - Item returnItem = null; - if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { - removeItem = BUCKET_OF_WATER; - returnItem = BUCKET; - } - if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { - removeItem = BOWL_OF_WATER; - returnItem = BOWL; - } - if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { - removeItem = JUG_OF_WATER; - returnItem = JUG; - } + /** + * Creates a soft clay. + * @param player the player. + * @param event the event. + * @return {@code True} if so. + */ + private boolean create(final Player player, NodeUsageEvent event) { + Item removeItem = null; + Item returnItem = null; + if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { + removeItem = BUCKET_OF_WATER; + returnItem = BUCKET; + } + if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { + removeItem = BOWL_OF_WATER; + returnItem = BOWL; + } + if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { + removeItem = JUG_OF_WATER; + returnItem = JUG; + } - if (player.getInventory().containsItem(CLAY) && player.getInventory().containsItem(Objects.requireNonNull(removeItem))) { - player.getInventory().remove(removeItem); - player.getInventory().remove(CLAY); - player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); - player.getInventory().add(SOFT_CLAY); - player.getInventory().add(returnItem); - if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { - player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); - } - return true; - } else { - return false; - } - } + if (player.getInventory().containsItem(CLAY) && player.getInventory().containsItem(Objects.requireNonNull(removeItem))) { + player.getInventory().remove(removeItem); + player.getInventory().remove(CLAY); + player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); + player.getInventory().add(SOFT_CLAY); + player.getInventory().add(returnItem); + if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { + player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); + } + return true; + } else { + return false; + } + } } From f76ac0efcf0b07f2e0cc750af5a18394f0cc4405 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 17:58:58 +0200 Subject: [PATCH 35/94] Allow poofClear to cope with regions not being loaded, preventing the anim from being queued until somebody enters the region --- .../wilderness/handlers/revenants/RevenantController.kt | 4 +++- Server/src/main/core/api/ContentAPI.kt | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt index fed2f91ec..2ccfbb61c 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt @@ -372,7 +372,9 @@ class RevenantController : TickListener, Commands { if (routeIdx == -1) { GameWorld.Pulser.submit(object : Pulse() { override fun pulse(): Boolean { - Graphics.send(Graphics(86), revenantNPC.location) + if (revenantNPC.location.region.isActive) { + Graphics.send(Graphics(86), revenantNPC.location) + } return true } }) diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 6e905d67a..7e1d6f813 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -541,7 +541,10 @@ fun poofClear(npc: NPC) { override fun pulse(): Boolean { when (counter++) { 2 -> { - npc.isInvisible = true; Graphics.send(Graphics(86), npc.location) + npc.isInvisible = true; + if (npc.location.region.isActive) { + Graphics.send(Graphics(86), npc.location) + } } 3 -> npc.clear().also { return true } } From fe8612b35f4117d7ee3897909cfb5c4a5e2b9a81 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 20:59:33 +0200 Subject: [PATCH 36/94] map chunk render debug --- .../game/world/update/MapChunkRenderer.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index ff26864e6..4d3e747af 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -1,5 +1,6 @@ package core.game.world.update +import core.api.log import core.game.node.entity.player.Player import core.game.world.map.Location import core.game.world.map.RegionChunk @@ -7,6 +8,7 @@ import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk +import core.tools.Log import java.util.* /** @@ -33,20 +35,45 @@ object MapChunkRenderer { // pushes the viewport edge to drift+6 chunks from the anchor, off-window, so edge items never render. val anchor = player.playerFlags.lastSceneGraph ?: player.location val center = Location.create(anchor.x, anchor.y, player.location.z) + + log(MapChunkRenderer::class.java, Log.FINE, + "anchor=${anchor} center=${center} " + + "anchorChunk=(${anchor.absChunkX},${anchor.absChunkY}) " + + "anchorOffset=(${anchor.chunkOffsetX},${anchor.chunkOffsetY}) " + + "playerLoc=${player.location}") + val itemChunkX = 392 + val itemChunkY = 476 + var itemChunkSamples = 0 + for (dcx in -buildAreaDepth..+buildAreaDepth) { val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { val newloc = center.transform(dcx * 8, dcy * 8, 0) addX.add(newloc.chunk) + if (newloc.absChunkX == itemChunkX && newloc.absChunkY == itemChunkY) { + itemChunkSamples++ + if (true) { + log(MapChunkRenderer::class.java, Log.FINE, + "item chunk sampled at grid[$dcx+6][$dcy+6] newloc=${newloc}") + } + } } current.add(addX) } + if (true) { + log(MapChunkRenderer::class.java, Log.FINE, "itemChunkSamples=$itemChunkSamples") + } var sizeX = last.size for (x in 0 until sizeX) { val sizeY: Int = last[x].size for (y in 0 until sizeY) { val previous = last[x][y] ?: continue + val isItemChunk = previous.currentBase.absChunkX == itemChunkX && previous.currentBase.absChunkY == itemChunkY + if (isItemChunk) { + log(MapChunkRenderer::class.java, Log.FINE, + "last has item chunk at [$x][$y], containsChunk=${containsChunk(current, previous)}") + } if (containsChunk(current, previous)) { updated.add(previous) continue @@ -63,6 +90,12 @@ object MapChunkRenderer { val sizeY: Int = current[x].size for (y in 0 until sizeY) { val chunk = current[x][y] + val isItemChunk = chunk.currentBase.absChunkX == itemChunkX && chunk.currentBase.absChunkY == itemChunkY + if (isItemChunk) { + log(MapChunkRenderer::class.java, Log.FINE, + "item chunk at grid[$x][$y] -> ${if (updated.contains(chunk)) "UPDATE" else "SYNCHRONIZE"} " + + "(inLast=${updated.contains(chunk)}) ") + } if (updated.contains(chunk)) { chunk.update(player) } else { From 25842c75189b4b54260716f508068fe847a887e9 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 21:20:30 +0200 Subject: [PATCH 37/94] AI slop fix --- .../core/game/node/entity/player/Player.java | 4 +++ .../main/core/game/world/map/RegionManager.kt | 35 ++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index cb94a83bd..8c90934ba 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -380,6 +380,10 @@ public class Player extends Entity { } interfaceManager.close(); interfaceManager.closeSingleTab(); + if (getAttribute("region-viewcounted", false)) { + RegionManager.decrementViewBlock(getLocation().getRegionX(), getLocation().getRegionY()); + removeAttribute("region-viewcounted"); + } super.clear(); getZoneMonitor().clear(); HouseManager.leave(this); diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 0407a569f..63d05f7b2 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -399,23 +399,50 @@ object RegionManager { when (entity) { is Player -> { src.chunk.removePlayer(entity) - src.region.decrementViewAmount() dst.chunk.addPlayer(entity) - dst.region.incrementViewAmount() - dst.region.flagActive() + // Compare at region granularity to detect a region (not just chunk) change. + if ((src.regionX shr 3) != (dst.regionX shr 3) || (src.regionY shr 3) != (dst.regionY shr 3)) { + if (entity.getAttribute("region-viewcounted", false)) { + forViewedRegions(src.regionX, src.regionY) { it.decrementViewAmount(); it.checkInactive() } + } + forViewedRegions(dst.regionX, dst.regionY) { it.incrementViewAmount(); it.flagActive() } + entity.setAttribute("region-viewcounted", true) + } } is NPC -> { src.chunk.remove(entity) dst.chunk.add(entity) } else -> { - throw (IllegalStateException("Tried to move an Entity that was neither Player nor NPC")) + throw IllegalStateException("Tried to move an Entity that was neither Player nor NPC") } } } entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint) } + /** + * Iterates the 3x3 block of regions surrounding the region containing the given chunk coordinates, + * running the action on each. Mirrors the pre-MR view-counting loop. + * @param chunkRegionX chunk-granularity x (i.e. Location.regionX, which is x >> 3). + * @param chunkRegionY chunk-granularity y (i.e. Location.regionY, which is y >> 3). + */ + private inline fun forViewedRegions(chunkRegionX: Int, chunkRegionY: Int, action: (Region) -> Unit) { + val regionX = chunkRegionX shr 3 // chunk -> region granularity + val regionY = chunkRegionY shr 3 + for (rx in (regionX - 1)..(regionX + 1)) { + for (ry in (regionY - 1)..(regionY + 1)) { + if (rx < 0 || ry < 0) continue + action(forId((rx shl 8) or ry)) + } + } + } + + @JvmStatic + fun decrementViewBlock(chunkRegionX: Int, chunkRegionY: Int) { + forViewedRegions(chunkRegionX, chunkRegionY) { it.decrementViewAmount(); it.checkInactive() } + } + /** * Gets local entities. You never call the below function directly (it's inlined); instead, you use one of the typed helpers defined directly below this function. * @param location the location. From 8af95dbd4d5c2587d9f05e1afde7c0c93a755912 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 21:20:54 +0200 Subject: [PATCH 38/94] Revert "map chunk render debug" This reverts commit aa4d62a556d09c20013485a874475a2fa3e0d824. --- .../game/world/update/MapChunkRenderer.kt | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 4d3e747af..ff26864e6 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -1,6 +1,5 @@ package core.game.world.update -import core.api.log import core.game.node.entity.player.Player import core.game.world.map.Location import core.game.world.map.RegionChunk @@ -8,7 +7,6 @@ import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk -import core.tools.Log import java.util.* /** @@ -35,45 +33,20 @@ object MapChunkRenderer { // pushes the viewport edge to drift+6 chunks from the anchor, off-window, so edge items never render. val anchor = player.playerFlags.lastSceneGraph ?: player.location val center = Location.create(anchor.x, anchor.y, player.location.z) - - log(MapChunkRenderer::class.java, Log.FINE, - "anchor=${anchor} center=${center} " + - "anchorChunk=(${anchor.absChunkX},${anchor.absChunkY}) " + - "anchorOffset=(${anchor.chunkOffsetX},${anchor.chunkOffsetY}) " + - "playerLoc=${player.location}") - val itemChunkX = 392 - val itemChunkY = 476 - var itemChunkSamples = 0 - for (dcx in -buildAreaDepth..+buildAreaDepth) { val addX = ArrayList() for (dcy in -buildAreaDepth..+buildAreaDepth) { val newloc = center.transform(dcx * 8, dcy * 8, 0) addX.add(newloc.chunk) - if (newloc.absChunkX == itemChunkX && newloc.absChunkY == itemChunkY) { - itemChunkSamples++ - if (true) { - log(MapChunkRenderer::class.java, Log.FINE, - "item chunk sampled at grid[$dcx+6][$dcy+6] newloc=${newloc}") - } - } } current.add(addX) } - if (true) { - log(MapChunkRenderer::class.java, Log.FINE, "itemChunkSamples=$itemChunkSamples") - } var sizeX = last.size for (x in 0 until sizeX) { val sizeY: Int = last[x].size for (y in 0 until sizeY) { val previous = last[x][y] ?: continue - val isItemChunk = previous.currentBase.absChunkX == itemChunkX && previous.currentBase.absChunkY == itemChunkY - if (isItemChunk) { - log(MapChunkRenderer::class.java, Log.FINE, - "last has item chunk at [$x][$y], containsChunk=${containsChunk(current, previous)}") - } if (containsChunk(current, previous)) { updated.add(previous) continue @@ -90,12 +63,6 @@ object MapChunkRenderer { val sizeY: Int = current[x].size for (y in 0 until sizeY) { val chunk = current[x][y] - val isItemChunk = chunk.currentBase.absChunkX == itemChunkX && chunk.currentBase.absChunkY == itemChunkY - if (isItemChunk) { - log(MapChunkRenderer::class.java, Log.FINE, - "item chunk at grid[$x][$y] -> ${if (updated.contains(chunk)) "UPDATE" else "SYNCHRONIZE"} " + - "(inLast=${updated.contains(chunk)}) ") - } if (updated.contains(chunk)) { chunk.update(player) } else { From 81faf292cc7e54187b816159e6c88e79d6ac83ac Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 21:26:57 +0200 Subject: [PATCH 39/94] Revert overengineered AI slop fix --- .../core/game/node/entity/player/Player.java | 4 --- .../main/core/game/world/map/RegionManager.kt | 35 +++---------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index 8c90934ba..cb94a83bd 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -380,10 +380,6 @@ public class Player extends Entity { } interfaceManager.close(); interfaceManager.closeSingleTab(); - if (getAttribute("region-viewcounted", false)) { - RegionManager.decrementViewBlock(getLocation().getRegionX(), getLocation().getRegionY()); - removeAttribute("region-viewcounted"); - } super.clear(); getZoneMonitor().clear(); HouseManager.leave(this); diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 63d05f7b2..0407a569f 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -399,50 +399,23 @@ object RegionManager { when (entity) { is Player -> { src.chunk.removePlayer(entity) + src.region.decrementViewAmount() dst.chunk.addPlayer(entity) - // Compare at region granularity to detect a region (not just chunk) change. - if ((src.regionX shr 3) != (dst.regionX shr 3) || (src.regionY shr 3) != (dst.regionY shr 3)) { - if (entity.getAttribute("region-viewcounted", false)) { - forViewedRegions(src.regionX, src.regionY) { it.decrementViewAmount(); it.checkInactive() } - } - forViewedRegions(dst.regionX, dst.regionY) { it.incrementViewAmount(); it.flagActive() } - entity.setAttribute("region-viewcounted", true) - } + dst.region.incrementViewAmount() + dst.region.flagActive() } is NPC -> { src.chunk.remove(entity) dst.chunk.add(entity) } else -> { - throw IllegalStateException("Tried to move an Entity that was neither Player nor NPC") + throw (IllegalStateException("Tried to move an Entity that was neither Player nor NPC")) } } } entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint) } - /** - * Iterates the 3x3 block of regions surrounding the region containing the given chunk coordinates, - * running the action on each. Mirrors the pre-MR view-counting loop. - * @param chunkRegionX chunk-granularity x (i.e. Location.regionX, which is x >> 3). - * @param chunkRegionY chunk-granularity y (i.e. Location.regionY, which is y >> 3). - */ - private inline fun forViewedRegions(chunkRegionX: Int, chunkRegionY: Int, action: (Region) -> Unit) { - val regionX = chunkRegionX shr 3 // chunk -> region granularity - val regionY = chunkRegionY shr 3 - for (rx in (regionX - 1)..(regionX + 1)) { - for (ry in (regionY - 1)..(regionY + 1)) { - if (rx < 0 || ry < 0) continue - action(forId((rx shl 8) or ry)) - } - } - } - - @JvmStatic - fun decrementViewBlock(chunkRegionX: Int, chunkRegionY: Int) { - forViewedRegions(chunkRegionX, chunkRegionY) { it.decrementViewAmount(); it.checkInactive() } - } - /** * Gets local entities. You never call the below function directly (it's inlined); instead, you use one of the typed helpers defined directly below this function. * @param location the location. From 4d9243884f05b73877179e24c0b42e4e47d7e099 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sun, 28 Jun 2026 21:51:03 +0200 Subject: [PATCH 40/94] A nicer fix involving tracking dirty chunks. --- Server/src/main/core/game/world/GameWorld.kt | 3 +++ .../main/core/game/world/map/RegionChunk.java | 7 +++++++ .../main/core/game/world/map/RegionManager.kt | 16 ---------------- .../game/world/update/ChunkDirtyListener.kt | 7 +++++++ .../game/world/update/ChunkUpdateTracker.kt | 19 +++++++++++++++++++ .../core/game/world/update/UpdateSequence.kt | 2 +- 6 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 Server/src/main/core/game/world/update/ChunkDirtyListener.kt create mode 100644 Server/src/main/core/game/world/update/ChunkUpdateTracker.kt diff --git a/Server/src/main/core/game/world/GameWorld.kt b/Server/src/main/core/game/world/GameWorld.kt index 2c0b55e2c..a7b5e1f0b 100644 --- a/Server/src/main/core/game/world/GameWorld.kt +++ b/Server/src/main/core/game/world/GameWorld.kt @@ -18,7 +18,9 @@ import core.ServerStore import core.auth.AuthProvider import core.auth.Auth import core.game.system.config.ConfigParser +import core.game.world.map.RegionChunk import core.game.world.repository.Repository +import core.game.world.update.ChunkUpdateTracker import core.plugin.ClassScanner import core.storage.AccountStorageProvider import core.tools.Log @@ -164,6 +166,7 @@ object GameWorld { fun prompt(run: Boolean, directory: String?){ log(GameWorld::class.java, Log.FINE, "Prompting ${settings?.name} Game World...") Cache.init(ServerConstants.CACHE_PATH) + RegionChunk.dirtyListener = ChunkUpdateTracker //go overboard with checks to make sure dev mode authenticator never triggers on live Auth.configure() ConfigParser().prePlugin() diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 94abe9189..35aa5c707 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -9,6 +9,7 @@ import core.game.node.scenery.Constructed; import core.game.node.scenery.Scenery; import core.game.node.scenery.SceneryBuilder; import core.game.world.map.build.ChunkFlags; +import core.game.world.update.ChunkDirtyListener; import core.game.world.update.flag.chunk.ItemUpdateFlag; import core.net.packet.PacketRepository; import core.net.packet.context.BuildItemContext; @@ -41,6 +42,11 @@ public class RegionChunk { */ public static final int SIZE = 8; + /** + * Notified whenever a chunk is flagged, so the rendering pipeline can reset only the chunks that were actually touched. + */ + public static ChunkDirtyListener dirtyListener = chunk -> {}; + /** * The base location of the copied region chunk. */ @@ -345,6 +351,7 @@ public class RegionChunk { */ public void flag(UpdateFlag flag) { updateFlags.add(flag); + dirtyListener.onFlagged(this); } /** diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 0407a569f..e60c43296 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -62,22 +62,6 @@ object RegionManager { } } - /** - * Pulses the active regions. - */ - @JvmStatic - fun pulse() { - apply { r -> - for (x in 0 until 8) { - for (y in 0 until 8) { - for (z in 0 until 4) { - r.chunks[x][y][z]?.resetFlags() - } - } - } - } - } - /** * Gets the clipping flag. * @param z The plane. diff --git a/Server/src/main/core/game/world/update/ChunkDirtyListener.kt b/Server/src/main/core/game/world/update/ChunkDirtyListener.kt new file mode 100644 index 000000000..668c73ce7 --- /dev/null +++ b/Server/src/main/core/game/world/update/ChunkDirtyListener.kt @@ -0,0 +1,7 @@ +package core.game.world.update + +import core.game.world.map.RegionChunk + +fun interface ChunkDirtyListener { + fun onFlagged(chunk: RegionChunk) +} diff --git a/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt b/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt new file mode 100644 index 000000000..03a3d9d0d --- /dev/null +++ b/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt @@ -0,0 +1,19 @@ +package core.game.world.update + +import core.game.world.map.RegionChunk +import java.util.Collections +import java.util.IdentityHashMap + +object ChunkUpdateTracker : ChunkDirtyListener { + private val dirty = Collections.newSetFromMap(IdentityHashMap()) + + override fun onFlagged(chunk: RegionChunk) { + dirty.add(chunk) + } + + /** Resets flags on exactly the chunks flagged this tick. Must run after all per-player flushes. */ + fun resetAll() { + dirty.forEach { it.resetFlags() } + dirty.clear() + } +} diff --git a/Server/src/main/core/game/world/update/UpdateSequence.kt b/Server/src/main/core/game/world/update/UpdateSequence.kt index bc17fbd65..775900633 100644 --- a/Server/src/main/core/game/world/update/UpdateSequence.kt +++ b/Server/src/main/core/game/world/update/UpdateSequence.kt @@ -59,7 +59,7 @@ class UpdateSequence playersList!!.forEach(Player::reset) npcList!!.forEach(NPC::reset) renderablePlayers.sync() - RegionManager.pulse() + ChunkUpdateTracker.resetAll() GroundItemManager.pulse() } From 3edce274492c300bc35257c6eb7f51c0db20789f Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 29 Jun 2026 15:16:54 +0200 Subject: [PATCH 41/94] Correct too narrow guards for clear region chunk --- Server/src/main/core/net/packet/out/ClearRegionChunk.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Server/src/main/core/net/packet/out/ClearRegionChunk.java b/Server/src/main/core/net/packet/out/ClearRegionChunk.java index f94a7a4df..77fe6456c 100644 --- a/Server/src/main/core/net/packet/out/ClearRegionChunk.java +++ b/Server/src/main/core/net/packet/out/ClearRegionChunk.java @@ -1,6 +1,7 @@ package core.net.packet.out; import core.game.world.map.Location; +import core.game.world.update.MapChunkRenderer; import core.net.packet.IoBuffer; import core.net.packet.OutgoingPacket; import core.net.packet.context.ClearChunkContext; @@ -10,13 +11,14 @@ import core.net.packet.context.ClearChunkContext; * @author Emperor */ public final class ClearRegionChunk implements OutgoingPacket { + static final int buildAreaDepth = MapChunkRenderer.buildAreaDepth; @Override public void send(ClearChunkContext context) { Location l = context.getPlayer().getPlayerFlags().getLastSceneGraph(); int x = context.getChunk().getCurrentBase().getSceneX(l); int y = context.getChunk().getCurrentBase().getSceneY(l); - if (x >= 0 && y >= 0 && x < 96 && y < 96) { + if (x >= 0 && y >= 0 && x < buildAreaDepth && y < buildAreaDepth) { IoBuffer buffer = new IoBuffer(112).put(x).putC(y); buffer.cypherOpcode(context.getPlayer().getSession().getIsaacPair().getOutput());context.getPlayer().getSession().write(buffer); } From 59edcb5c4f56e704437f35054adb82089d671837 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 29 Jun 2026 22:48:04 +0200 Subject: [PATCH 42/94] fix stray dogs --- .../content/region/misthalin/varrock/handlers/StrayDogNPC.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java b/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java index 1d8530d2a..843984cac 100644 --- a/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java +++ b/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java @@ -72,7 +72,7 @@ public class StrayDogNPC extends AbstractNPC { target = null; players = RegionManager.getLocalPlayers(location, 7); if (players.size() != 0) { - Player target = players.get(RandomFunction.random(players.size())); + target = players.get(RandomFunction.random(players.size())); getPulseManager().run(getFollowPulse(target), PulseType.STANDARD); delay = System.currentTimeMillis() + 150000; } From 287f1d04d5312f87611d07ed5fd40a590472bb81 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 30 Jun 2026 15:25:36 +0200 Subject: [PATCH 43/94] I am retarded --- Server/src/main/core/net/packet/out/ClearRegionChunk.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Server/src/main/core/net/packet/out/ClearRegionChunk.java b/Server/src/main/core/net/packet/out/ClearRegionChunk.java index 77fe6456c..5d20d0546 100644 --- a/Server/src/main/core/net/packet/out/ClearRegionChunk.java +++ b/Server/src/main/core/net/packet/out/ClearRegionChunk.java @@ -11,16 +11,17 @@ import core.net.packet.context.ClearChunkContext; * @author Emperor */ public final class ClearRegionChunk implements OutgoingPacket { - static final int buildAreaDepth = MapChunkRenderer.buildAreaDepth; + static final int buildAreaDepthInTiles = (2*MapChunkRenderer.buildAreaDepth+1) * 8; @Override public void send(ClearChunkContext context) { Location l = context.getPlayer().getPlayerFlags().getLastSceneGraph(); int x = context.getChunk().getCurrentBase().getSceneX(l); int y = context.getChunk().getCurrentBase().getSceneY(l); - if (x >= 0 && y >= 0 && x < buildAreaDepth && y < buildAreaDepth) { + if (x >= 0 && y >= 0 && x < buildAreaDepthInTiles && y < buildAreaDepthInTiles) { IoBuffer buffer = new IoBuffer(112).put(x).putC(y); - buffer.cypherOpcode(context.getPlayer().getSession().getIsaacPair().getOutput());context.getPlayer().getSession().write(buffer); + buffer.cypherOpcode(context.getPlayer().getSession().getIsaacPair().getOutput()); + context.getPlayer().getSession().write(buffer); } } From 2cfb3f926ae206be1a82665cad208f56e6149aeb Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 30 Jun 2026 16:33:53 +0200 Subject: [PATCH 44/94] I am more retarded --- Server/src/main/core/game/node/entity/npc/NPC.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index 6fa12f211..15877b6f8 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -214,8 +214,7 @@ public class NPC extends Entity { getProperties().setSpawnLocation(getLocation()); initConfig(); Repository.getNpcs().add(this); - RegionManager.move(this, ServerConstants.START_LOCATION, this.location); - getLocation().getChunk().add(this); + RegionManager.move(this, ServerConstants.START_LOCATION, location); if (getLocation().getRegion().isActive()) { Repository.addRenderableNPC(this); } From 016908604f76ab230fb6fb93ab8565c4e1056e34 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 30 Jun 2026 16:45:44 +0200 Subject: [PATCH 45/94] Fix ravagers building doors --- .../main/content/minigame/pestcontrol/PestControlSession.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java index 3d8591916..7aca85763 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java @@ -31,6 +31,7 @@ public final class PestControlSession { */ public static final int[] INVALID_OBJECT_IDS = {14230, 14231, 14232, // Barricades 14245, 14246, 14247, 14248, // Gates + 25636 // Strange phantom object that shares a tile with a barricade }; /** From d3be31b5fbb0d049a67314492a8a5264cf8cba35 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 30 Jun 2026 17:20:30 +0200 Subject: [PATCH 46/94] Janitorial cleanup --- .../main/core/game/node/entity/player/Player.java | 4 ++-- .../game/node/entity/player/info/RenderInfo.java | 12 ++++++------ .../src/main/core/game/world/update/NPCRenderer.kt | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index cb94a83bd..301ad724f 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -857,7 +857,7 @@ public class Player extends Entity { playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); playerFlags.setLastViewport(new RegionChunk[13][13]); - renderInfo.getLocalNpcs().clear(); + renderInfo.getLocalNPCs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); renderInfo.setOnFirstCycle(true); @@ -891,7 +891,7 @@ public class Player extends Entity { */ public void updateSceneGraph(boolean login) { Region region = getLocation().getRegion(); - if (region instanceof DynamicRegion || region == null && (region = RegionManager.forId(location.getRegionId())) instanceof DynamicRegion) { + if (region instanceof DynamicRegion) { PacketRepository.send(BuildDynamicScene.class, new DynamicSceneContext(this, login)); } else { PacketRepository.send(UpdateSceneGraph.class, new SceneGraphContext(this, login)); diff --git a/Server/src/main/core/game/node/entity/player/info/RenderInfo.java b/Server/src/main/core/game/node/entity/player/info/RenderInfo.java index 3aa6a7a07..b72c2fcc7 100644 --- a/Server/src/main/core/game/node/entity/player/info/RenderInfo.java +++ b/Server/src/main/core/game/node/entity/player/info/RenderInfo.java @@ -28,7 +28,7 @@ public final class RenderInfo { /** * The list of local NPCs. */ - private List localNpcs = new LinkedList(); + private List localNPCs = new LinkedList(); /** * The appearance time stamps (in millisecond). @@ -89,16 +89,16 @@ public final class RenderInfo { * Gets the localNpcs. * @return The localNpcs. */ - public List getLocalNpcs() { - return localNpcs; + public List getLocalNPCs() { + return localNPCs; } /** * Sets the localNpcs. - * @param localNpcs The localNpcs to set. + * @param localNPCs The localNpcs to set. */ - public void setLocalNpcs(List localNpcs) { - this.localNpcs = localNpcs; + public void setLocalNPCs(List localNPCs) { + this.localNPCs = localNPCs; } /** diff --git a/Server/src/main/core/game/world/update/NPCRenderer.kt b/Server/src/main/core/game/world/update/NPCRenderer.kt index 815066844..026c8860f 100644 --- a/Server/src/main/core/game/world/update/NPCRenderer.kt +++ b/Server/src/main/core/game/world/update/NPCRenderer.kt @@ -22,7 +22,7 @@ object NPCRenderer { fun render(player: Player) { val buffer = IoBuffer(32, PacketHeader.SHORT) val info = player.renderInfo - val localNPCs = info.localNpcs + val localNPCs = info.localNPCs val maskBuffer = IoBuffer(-1, PacketHeader.NORMAL, ByteBuffer.allocate(1 shl 16)) buffer.setBitAccess() buffer.putBits(8, localNPCs.size) From 38ec74d178ef1ebd6e49d9be8858a417ce7fb1aa Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 30 Jun 2026 20:07:29 +0200 Subject: [PATCH 47/94] shire fix --- .../main/core/game/world/map/RegionChunk.java | 16 ++++++---------- .../core/game/world/update/MapChunkRenderer.kt | 3 --- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 35aa5c707..55b94e5c2 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -411,16 +411,12 @@ public class RegionChunk { } } } - // Dynamic regions (POHs etc.) deliver items once via add(GroundItem) and the client retains them across scene rebuilds; - // re-sending here would duplicate them (the client doesn't de-dup). Static regions still need it for chunks entering view. - if (!(getRegion() instanceof DynamicRegion)) { - ArrayList totalItems = drawItems(items, player); - for (GroundItem item : totalItems) { - if (item != null && item.isActive() && item.getLocation() != null) { - if (!item.isPrivate() || item.droppedBy(player)) { - ConstructGroundItem.write(buffer, item); - updated = true; - } + ArrayList totalItems = drawItems(items, player); + for (GroundItem item : totalItems) { + if (item != null && item.isActive() && item.getLocation() != null) { + if (!item.isPrivate() || item.droppedBy(player)) { + ConstructGroundItem.write(buffer, item); + updated = true; } } } diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index ff26864e6..883dd0d86 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -51,9 +51,6 @@ object MapChunkRenderer { updated.add(previous) continue } - if (previous.region is DynamicRegion) { - continue //dynamic regions do not need a clear packet and briefly flash their cached states (e.g. POH with only hotspots) if you do send one - } PacketRepository.send(ClearRegionChunk::class.java, ClearChunkContext(player, previous)) } } From 07c44680190e2d0b3504a5c17de124829abfa2c1 Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 1 Jul 2026 07:41:08 +0200 Subject: [PATCH 48/94] Fix ravagers building doors in a different way --- .../content/minigame/pestcontrol/PestControlSession.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java index 7aca85763..f29a8c314 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java @@ -31,7 +31,6 @@ public final class PestControlSession { */ public static final int[] INVALID_OBJECT_IDS = {14230, 14231, 14232, // Barricades 14245, 14246, 14247, 14248, // Gates - 25636 // Strange phantom object that shares a tile with a barricade }; /** @@ -275,7 +274,9 @@ public final class PestControlSession { for (Scenery object : objectList) { for (Point point : OBJECT_OFFSETS) { if (object.getLocation().getLocalX() == point.getX() && object.getLocation().getLocalY() == point.getY()) { - barricades.add(object); + if (object.getId() != 25636) { //strange phantom object that shares a tile with a barricade + barricades.add(object); + } } } } From 5d2292352ad6b8f274a49ac7534dc581c64b9eb1 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 09:52:37 +0200 Subject: [PATCH 49/94] surrounding typo --- .../asgarnia/goblinvillage/handlers/GoblinVillageNPC.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java b/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java index e5128d1ba..80865890c 100644 --- a/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java +++ b/Server/src/main/content/region/asgarnia/goblinvillage/handlers/GoblinVillageNPC.java @@ -103,8 +103,8 @@ public final class GoblinVillageNPC extends AbstractNPC { if (delay < System.currentTimeMillis() && !getProperties().getCombatPulse().isAttacking()) { final int rand = RandomFunction.random(1, 4); if (rand == 2) { - final List surronding = RegionManager.getLocalNPCs(location, 10); - for (NPC n : surronding) { + final List surrounding = RegionManager.getLocalNPCs(location, 10); + for (NPC n : surrounding) { if (n.getId() == getId()) { continue; } From fd45d829935198e3ebab611c20d877b285cd5ad0 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 11:03:48 +0200 Subject: [PATCH 50/94] low hanging fruit like unused imports --- .../global/ame/events/evilchicken/EvilChickenNPC.kt | 1 - .../main/content/global/ame/events/maze/MazeInterface.kt | 3 --- .../global/ame/events/rivertroll/RiverTrollRENPC.kt | 1 - .../global/ame/events/rockgolem/RockGolemRENPC.kt | 1 - .../main/content/global/ame/events/shade/ShadeRENPC.kt | 1 - .../global/ame/events/treespirit/TreeSpiritRENPC.kt | 1 - .../main/content/global/ame/events/zombie/ZombieRENPC.kt | 1 - Server/src/main/content/global/bots/Adventurer.kt | 5 ----- Server/src/main/content/global/bots/CannonballSmelter.kt | 4 ++-- .../skill/gather/woodcutting/WoodcuttingListener.kt | 1 - .../skill/gather/woodcutting/WoodcuttingSkillPulse.java | 9 ++------- .../main/content/global/skill/magic/lunar/HealSpell.java | 1 - .../content/global/skill/magic/lunar/StatBoostSpell.java | 1 - .../global/skill/magic/lunar/StatRestoreSpell.java | 1 - .../content/minigame/barrows/BarrowsActivityPlugin.java | 3 --- .../minigame/pestcontrol/PestControlActivityPlugin.java | 1 - .../minigame/pestcontrol/monsters/PCSpinnerNPC.java | 1 - .../content/minigame/puropuro/ImpDefenderBehavior.kt | 1 - .../minigame/sorceress/SorceressElementalNPC.java | 1 - .../region/asgarnia/falador/handlers/GiantMoleNPC.java | 1 - .../taverley/quest/witchshouse/NoraTHaggNPC.java | 1 - .../trollheim/handlers/gwd/GWDGraardorSwingHandler.java | 1 - .../trollheim/handlers/gwd/GWDKreeArraSwingHandler.java | 1 - .../trollheim/handlers/gwd/GWDZilyanaSwingHandler.java | 1 - .../content/region/desert/handlers/KalphiteQueenNPC.java | 1 - .../desert/quest/thetouristrap/DesertGuardDialogue.java | 1 - .../fremennik/waterbirth/handlers/DagannothKingNPC.java | 1 - .../misthalin/draynor/handlers/DraynorManorChairNPC.kt | 1 - .../misthalin/draynor/handlers/DraynorTreeNPC.java | 1 - .../region/misthalin/varrock/handlers/StrayDogNPC.java | 1 - .../region/morytania/handlers/MortMyreGhastNPC.kt | 1 - .../region/wilderness/handlers/CorporealBeastNPC.java | 1 - .../region/wilderness/handlers/DarkEnergyCoreNPC.java | 1 - .../wilderness/handlers/revenants/RevenantNPC.java | 1 - .../core/game/node/entity/combat/spell/CombatSpell.java | 2 -- .../game/node/entity/npc/agg/AggressiveBehavior.java | 1 - .../game/node/entity/player/link/PacketDispatch.java | 1 - .../core/game/world/map/zone/impl/ModeratorZone.java | 1 - Server/src/main/core/game/world/update/PlayerRenderer.kt | 1 - 39 files changed, 4 insertions(+), 55 deletions(-) diff --git a/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt b/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt index 4ae677997..7743500ef 100644 --- a/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt +++ b/Server/src/main/content/global/ame/events/evilchicken/EvilChickenNPC.kt @@ -10,7 +10,6 @@ import org.rs09.consts.Items import content.global.ame.RandomEventNPC import core.api.sendMessage import core.api.utils.WeightBasedTable -import core.game.world.map.MapDistance val ids = (2463..2468).toList() diff --git a/Server/src/main/content/global/ame/events/maze/MazeInterface.kt b/Server/src/main/content/global/ame/events/maze/MazeInterface.kt index 5376e870c..1d94c4238 100644 --- a/Server/src/main/content/global/ame/events/maze/MazeInterface.kt +++ b/Server/src/main/content/global/ame/events/maze/MazeInterface.kt @@ -12,10 +12,7 @@ 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.RegionManager import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneRestriction import core.game.world.update.flag.context.Graphics diff --git a/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt b/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt index 50888b63e..34b312148 100644 --- a/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt +++ b/Server/src/main/content/global/ame/events/rivertroll/RiverTrollRENPC.kt @@ -3,7 +3,6 @@ package content.global.ame.events.rivertroll import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC -import core.api.getWorldTicks import core.api.utils.WeightBasedTable import core.game.world.map.MapDistance diff --git a/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt b/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt index 68bd92beb..593a9f917 100644 --- a/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt +++ b/Server/src/main/content/global/ame/events/rockgolem/RockGolemRENPC.kt @@ -3,7 +3,6 @@ package content.global.ame.events.rockgolem import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC -import core.api.getWorldTicks import core.api.utils.WeightBasedTable import core.game.world.map.MapDistance diff --git a/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt b/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt index 14bcdd609..5a5bff4d1 100644 --- a/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt +++ b/Server/src/main/content/global/ame/events/shade/ShadeRENPC.kt @@ -3,7 +3,6 @@ package content.global.ame.events.shade import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC -import core.api.getWorldTicks import core.api.utils.WeightBasedTable import core.game.world.map.MapDistance diff --git a/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt b/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt index 0bba8e2b5..a3a078398 100644 --- a/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt +++ b/Server/src/main/content/global/ame/events/treespirit/TreeSpiritRENPC.kt @@ -3,7 +3,6 @@ package content.global.ame.events.treespirit import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC -import core.api.getWorldTicks import core.api.utils.WeightBasedTable import core.game.world.map.MapDistance diff --git a/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt b/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt index ebe4465bc..48ebacd81 100644 --- a/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt +++ b/Server/src/main/content/global/ame/events/zombie/ZombieRENPC.kt @@ -3,7 +3,6 @@ package content.global.ame.events.zombie import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import content.global.ame.RandomEventNPC -import core.api.getWorldTicks import core.api.utils.WeightBasedTable import core.game.world.map.MapDistance diff --git a/Server/src/main/content/global/bots/Adventurer.kt b/Server/src/main/content/global/bots/Adventurer.kt index 62464bbf2..86f157461 100644 --- a/Server/src/main/content/global/bots/Adventurer.kt +++ b/Server/src/main/content/global/bots/Adventurer.kt @@ -11,25 +11,20 @@ import core.game.world.GameWorld import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.map.zone.ZoneBorders -import core.game.world.update.flag.* import org.json.simple.JSONArray import org.json.simple.JSONObject import core.ServerConstants -import core.api.log import core.game.bots.AIRepository import core.game.bots.CombatBotAssembler import core.game.bots.Script import core.game.interaction.IntType import core.game.interaction.InteractionListeners -import core.game.world.repository.Repository -import core.tools.Log import java.io.File import java.io.FileReader import java.time.LocalDateTime import java.time.format.DateTimeFormatter import kotlin.random.Random - /** * A bot script for Adventurers who explore the world! * @param counter used in the bots random idling function. diff --git a/Server/src/main/content/global/bots/CannonballSmelter.kt b/Server/src/main/content/global/bots/CannonballSmelter.kt index bc921111b..38887ad2c 100644 --- a/Server/src/main/content/global/bots/CannonballSmelter.kt +++ b/Server/src/main/content/global/bots/CannonballSmelter.kt @@ -58,7 +58,7 @@ class CannonballSmelter : Script() { } else if(!coalMine.insideBorder(bot)){ scriptAPI.walkTo(coalMine.randomLoc) } else { - val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.COAL_453 }) + val rock = scriptAPI.getNearestObjectByPredicate { node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.COAL_453 } if(rock != null) { scriptAPI.interact(bot, rock, "mine") } else { @@ -75,7 +75,7 @@ class CannonballSmelter : Script() { var loc = ironMine.randomLoc scriptAPI.walkTo(loc) } else { - val rock = scriptAPI.getNearestObjectByPredicate({node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.IRON_ORE_440 }) + val rock = scriptAPI.getNearestObjectByPredicate { node -> node?.name?.equals("rocks", true)!! && MiningNode.forId(node.id)?.reward == Items.IRON_ORE_440 } //rock?.let { InteractionListeners.run(rock.id, IntType.SCENERY,"mine",bot,rock) } if(rock != null) { scriptAPI.interact(bot, rock, "mine") diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt index 41261ec05..301fc6799 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt @@ -29,7 +29,6 @@ import core.game.node.scenery.SceneryBuilder import core.game.system.command.sets.STATS_BASE import core.game.system.command.sets.STATS_LOGS import core.game.world.map.RegionManager -import core.game.world.repository.Repository import core.tools.RandomFunction import org.rs09.consts.Items import org.rs09.consts.NPCs diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java index 465912ee5..859a26308 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingSkillPulse.java @@ -11,7 +11,6 @@ import core.game.dialogue.FacialExpression; import core.game.node.entity.impl.Animator; import core.game.node.entity.impl.Projectile; import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.audio.Audio; import core.game.node.entity.player.link.diary.DiaryType; import core.game.node.entity.skill.Skills; import content.data.skill.SkillingTool; @@ -21,14 +20,10 @@ import core.game.node.scenery.SceneryBuilder; import core.game.system.task.Pulse; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; import org.rs09.consts.Sounds; -import java.util.List; -import java.util.stream.Collectors; - import static core.api.ContentAPIKt.playAudio; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_BASE; import static core.game.system.command.sets.StatAttributeKeysKt.STATS_LOGS; @@ -116,11 +111,11 @@ public class WoodcuttingSkillPulse extends Pulse { public void animate() { if (!player.getAnimator().isAnimating()) { player.animate(SkillingTool.getHatchet(player).getAnimation()); + int soundIndex = RandomFunction.random(0, woodcuttingSounds.length); for (Player p : RegionManager.getLocalPlayers(player.getLocation(), 2)) { - if (p.getName() == player.getName()) { + if (p == player) { continue; } - int soundIndex = RandomFunction.random(0, woodcuttingSounds.length); playAudio(p, woodcuttingSounds[soundIndex]); } } diff --git a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java index 82b036755..e7db4f75c 100644 --- a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java @@ -2,7 +2,6 @@ package content.global.skill.magic.lunar; import core.game.node.entity.combat.spell.MagicSpell; import core.game.node.entity.combat.spell.Runes; -import core.game.world.repository.Repository; import core.plugin.Initializable; import core.game.node.entity.skill.Skills; import core.game.node.Node; diff --git a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java index d86f83b07..b58529e77 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java @@ -12,7 +12,6 @@ import core.game.bots.AIPlayer; import core.game.node.entity.player.link.SpellBookManager.SpellBook; import core.game.node.item.Item; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; diff --git a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java index 71b9ebf82..b7aa4d15c 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java @@ -2,7 +2,6 @@ package content.global.skill.magic.lunar; import content.data.consumables.Consumables; import core.game.consumable.Potion; -import core.game.world.repository.Repository; import core.plugin.Initializable; import core.game.node.entity.combat.spell.MagicSpell; import core.game.node.entity.combat.spell.Runes; diff --git a/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java b/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java index 3654658bc..eaf43c940 100644 --- a/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java +++ b/Server/src/main/content/minigame/barrows/BarrowsActivityPlugin.java @@ -20,10 +20,8 @@ import core.game.node.scenery.Scenery; import core.game.system.task.Pulse; import core.game.world.map.Location; import core.game.world.map.Region; -import core.game.world.map.RegionChunk; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; import core.net.packet.context.CameraContext; @@ -35,7 +33,6 @@ import core.plugin.Initializable; import core.tools.RandomFunction; import core.game.world.GameWorld; import core.plugin.ClassScanner; -import org.jetbrains.annotations.NotNull; import java.util.stream.IntStream; diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java b/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java index a570ede1c..2f7b97e4c 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlActivityPlugin.java @@ -25,7 +25,6 @@ import core.game.world.map.build.DynamicRegion; import core.game.world.map.zone.RegionZone; import core.game.world.map.zone.ZoneBuilder; import core.game.world.map.zone.ZoneRestriction; -import core.game.world.repository.Repository; import core.plugin.Initializable; import core.plugin.ClassScanner; import core.tools.RandomFunction; diff --git a/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java b/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java index 4bfedb5e0..9407a61d7 100644 --- a/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java +++ b/Server/src/main/content/minigame/pestcontrol/monsters/PCSpinnerNPC.java @@ -15,7 +15,6 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; diff --git a/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt b/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt index 0dd282ed5..c01d48b28 100644 --- a/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt +++ b/Server/src/main/content/minigame/puropuro/ImpDefenderBehavior.kt @@ -11,7 +11,6 @@ import core.game.world.map.zone.ZoneBorders import core.game.world.map.RegionManager import core.game.system.task.Pulse import content.global.skill.hunter.bnet.BNetTypes -import core.game.world.repository.Repository import org.rs09.consts.Items diff --git a/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java b/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java index ce1c6133c..7c05215f2 100644 --- a/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java +++ b/Server/src/main/content/minigame/sorceress/SorceressElementalNPC.java @@ -11,7 +11,6 @@ import core.game.world.GameWorld; import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; diff --git a/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java b/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java index e9f3735e5..20edbb3ac 100644 --- a/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java +++ b/Server/src/main/content/region/asgarnia/falador/handlers/GiantMoleNPC.java @@ -26,7 +26,6 @@ import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.impl.DarkZone; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; diff --git a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java index 7cb1070e7..8a73079c3 100644 --- a/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java +++ b/Server/src/main/content/region/asgarnia/taverley/quest/witchshouse/NoraTHaggNPC.java @@ -10,7 +10,6 @@ import core.game.world.GameWorld; import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.net.packet.PacketRepository; diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java index 551b314b6..0e14342e9 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDGraardorSwingHandler.java @@ -15,7 +15,6 @@ import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java index 56176d84b..66f5e432c 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDKreeArraSwingHandler.java @@ -17,7 +17,6 @@ import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java index 4fa4fea33..bccf419f9 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GWDZilyanaSwingHandler.java @@ -13,7 +13,6 @@ import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; diff --git a/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java b/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java index 7637a1baf..63d971e66 100644 --- a/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java +++ b/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java @@ -19,7 +19,6 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; diff --git a/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java b/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java index 623a4ecef..80de1b845 100644 --- a/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java +++ b/Server/src/main/content/region/desert/quest/thetouristrap/DesertGuardDialogue.java @@ -12,7 +12,6 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.plugin.ClassScanner; import core.tools.RandomFunction; diff --git a/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java b/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java index 7a30ca024..7b5dc7809 100644 --- a/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java +++ b/Server/src/main/content/region/fremennik/waterbirth/handlers/DagannothKingNPC.java @@ -10,7 +10,6 @@ import core.game.node.entity.npc.AbstractNPC; import core.game.node.entity.player.Player; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.tools.RandomFunction; /** diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt index 8a3227c11..4d11f87e3 100644 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorManorChairNPC.kt @@ -9,7 +9,6 @@ import core.game.node.entity.player.Player import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.map.path.Pathfinder -import core.game.world.repository.Repository import core.plugin.Initializable /** diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java index 84c7d95f6..f0b270b2c 100644 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DraynorTreeNPC.java @@ -9,7 +9,6 @@ import core.game.node.entity.player.Player; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; import core.tools.RandomFunction; diff --git a/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java b/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java index 843984cac..c093b2ef2 100644 --- a/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java +++ b/Server/src/main/content/region/misthalin/varrock/handlers/StrayDogNPC.java @@ -12,7 +12,6 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.path.Pathfinder; import core.game.world.map.zone.impl.BankZone; -import core.game.world.repository.Repository; import core.plugin.Initializable; import core.tools.RandomFunction; diff --git a/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt b/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt index 8aeac41fd..19086cf8d 100644 --- a/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt +++ b/Server/src/main/content/region/morytania/handlers/MortMyreGhastNPC.kt @@ -20,7 +20,6 @@ import kotlinx.coroutines.launch import org.rs09.consts.Items import org.rs09.consts.NPCs import content.region.morytania.quest.naturespirit.NSUtils -import core.game.world.repository.Repository import org.rs09.consts.Sounds @Initializable diff --git a/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java b/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java index 8330ce597..2c1a3710d 100644 --- a/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/CorporealBeastNPC.java @@ -15,7 +15,6 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; diff --git a/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java b/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java index c0768ea8d..2dd7b2ba7 100644 --- a/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/DarkEnergyCoreNPC.java @@ -12,7 +12,6 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.path.Path; import core.game.world.map.path.Pathfinder; -import core.game.world.repository.Repository; import core.plugin.Initializable; import core.tools.RandomFunction; diff --git a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java index ef7fdf722..46d0013f8 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java @@ -13,7 +13,6 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; import core.game.world.map.zone.impl.WildernessZone; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; import core.tools.RandomFunction; diff --git a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java index 6ac567b15..09009b142 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java @@ -15,14 +15,12 @@ import core.game.node.entity.player.link.audio.Audio; import core.game.node.item.Item; import core.game.world.map.RegionManager; import core.game.world.map.zone.impl.WildernessZone; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import org.rs09.consts.Sounds; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import static core.api.ContentAPIKt.playGlobalAudio; diff --git a/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java b/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java index 0e8b8a1fe..16153b211 100644 --- a/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java +++ b/Server/src/main/core/game/node/entity/npc/agg/AggressiveBehavior.java @@ -6,7 +6,6 @@ import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.world.map.zone.impl.WildernessZone; import core.game.world.map.RegionManager; -import core.game.world.repository.Repository; import java.util.ArrayList; import java.util.List; diff --git a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java index 8f2557652..16e12e682 100644 --- a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java +++ b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java @@ -2,7 +2,6 @@ package core.game.node.entity.player.link; import core.game.node.entity.player.Player; import core.game.node.scenery.Scenery; -import core.game.world.repository.Repository; import core.tools.Log; import core.game.system.task.Pulse; import core.game.world.GameWorld; diff --git a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java index d44cc9f7c..56352e7b6 100644 --- a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java +++ b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java @@ -11,7 +11,6 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.MapZone; import core.game.world.map.zone.ZoneBorders; -import core.game.world.repository.Repository; /** * Represents the moderator zone. diff --git a/Server/src/main/core/game/world/update/PlayerRenderer.kt b/Server/src/main/core/game/world/update/PlayerRenderer.kt index b20ab8dd5..a3130646e 100644 --- a/Server/src/main/core/game/world/update/PlayerRenderer.kt +++ b/Server/src/main/core/game/world/update/PlayerRenderer.kt @@ -3,7 +3,6 @@ package core.game.world.update import core.game.node.entity.player.Player import core.game.node.entity.player.info.RenderInfo import core.game.world.map.RegionManager -import core.game.world.repository.Repository import core.net.packet.IoBuffer import core.net.packet.PacketHeader From ec41a9b56467351760bb03e8a1ddca2dd6804e84 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 12:30:11 +0200 Subject: [PATCH 51/94] rawtypes --- .../item/equipment/special/ChinchompaSwingHandler.java | 5 ++--- .../item/equipment/special/PowerstabSpecialHandler.java | 6 ++---- .../item/equipment/special/SpearWallSpecialHandler.java | 6 ++---- .../core/game/node/entity/player/link/prayer/Prayer.java | 6 ++---- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java index 0523f8753..953b9db04 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java @@ -56,7 +56,7 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { } // https://oldschool.runescape.wiki/w/Chinchompa - shit source but it's better than what was here before - @SuppressWarnings("rawtypes") List targetCandidates; + List targetCandidates; if (victim instanceof Player) { targetCandidates = RegionManager.getSurroundingPlayers(victim, 9); } else { @@ -64,8 +64,7 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { } BattleState[] targets = new BattleState[targetCandidates.size()]; int count = 0; - for (Object o : targetCandidates) { - Entity e = (Entity) o; + for (Entity e : targetCandidates) { if (e != entity && canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { BattleState s = targets[count++] = new BattleState(entity, e); s.setStyle(CombatStyle.RANGE); diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index 0b09a3c2c..7820d94d6 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -75,12 +75,10 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - @SuppressWarnings("rawtypes") - List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); + List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); BattleState[] targets = new BattleState[list.size()]; int count = 0; - for (Object o : list) { - Entity e = (Entity) o; + for (Entity e : list) { if (e != entity && CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { BattleState s = targets[count++] = new BattleState(entity, e); int hit = 0; diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java index 4ae69ddc2..27cd436ff 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java @@ -76,12 +76,10 @@ public final class SpearWallSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - @SuppressWarnings("rawtypes") - List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); + List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); BattleState[] targets = new BattleState[list.size()]; int count = 0; - for (Object o : list) { - Entity e = (Entity) o; + for (Entity e : list) { if (e != entity && CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { BattleState s = targets[count++] = new BattleState(entity, e); int hit = 0; diff --git a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java index 4f2780a7b..1a3ff9ff8 100644 --- a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java +++ b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java @@ -112,15 +112,13 @@ public final class Prayer { killer.getImpactHandler().manualHit(player, 1 + RandomFunction.randomize(maximum), HitsplatType.NORMAL); } if (player.getProperties().isMultiZone()) { - @SuppressWarnings("rawtypes") - List targets; + List targets; if (killer instanceof NPC) { targets = RegionManager.getLocalNPCs(player.getLocation(), 1); } else { targets = RegionManager.getLocalPlayers(player.getLocation(), 1); } - for (Object o : targets) { - Entity entity = (Entity) o; + for (Entity entity : targets) { if (entity == player) { continue; } From 7bd8a8b3e942c8723ae35831c8dad5d3fb8441ec Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 12:34:00 +0200 Subject: [PATCH 52/94] minimize change to soft clay --- .../item/withitem/SoftclayPlugin.java | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java index fc63daa34..73cd237fb 100644 --- a/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java +++ b/Server/src/main/content/global/handlers/item/withitem/SoftclayPlugin.java @@ -21,47 +21,47 @@ import java.util.Objects; @Initializable public final class SoftclayPlugin extends UseWithHandler { - /** - * Represents the clay item. - */ - private static final Item CLAY = new Item(Items.CLAY_434); + /** + * Represents the clay item. + */ + private static final Item CLAY = new Item(Items.CLAY_434); - /** - * Represents the soft clay item. - */ - private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); + /** + * Represents the soft clay item. + */ + private static final Item SOFT_CLAY = new Item(Items.SOFT_CLAY_1761); - /** - * Represents the bowl of water item. - */ - private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); + /** + * Represents the bowl of water item. + */ + private static final Item BOWL_OF_WATER = new Item(Items.BOWL_OF_WATER_1921); - /** - * Represents the empty bowl item. - */ - private static final Item BOWL = new Item(Items.BOWL_1923); + /** + * Represents the empty bowl item. + */ + private static final Item BOWL = new Item(Items.BOWL_1923); - /** - * Represents the empty bucket item. - */ - private static final Item BUCKET = new Item(Items.BUCKET_1925); + /** + * Represents the empty bucket item. + */ + private static final Item BUCKET = new Item(Items.BUCKET_1925); /** * Represents the bucket of water item. */ private static final Item BUCKET_OF_WATER = new Item(Items.BUCKET_OF_WATER_1929); - /** - * Represents the jug item. - */ - private static final Item JUG = new Item(Items.JUG_1935); + /** + * Represents the jug item. + */ + private static final Item JUG = new Item(Items.JUG_1935); /** * Represents the jug of water item. */ private static final Item JUG_OF_WATER = new Item(Items.JUG_OF_WATER_1937); - /** + /** * Constructs a new {@code SoftclayPlugin} {@code Object}. */ public SoftclayPlugin() { @@ -70,7 +70,7 @@ public final class SoftclayPlugin extends UseWithHandler { @Override public Plugin newInstance(Object arg) throws Throwable { - addHandler(1921, ITEM_TYPE, this); + addHandler(1921, ITEM_TYPE, this); addHandler(1929, ITEM_TYPE, this); addHandler(1937, ITEM_TYPE, this); return this; @@ -115,33 +115,33 @@ public final class SoftclayPlugin extends UseWithHandler { * @return {@code True} if so. */ private boolean create(final Player player, NodeUsageEvent event) { - Item removeItem = null; - Item returnItem = null; - if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { - removeItem = BUCKET_OF_WATER; - returnItem = BUCKET; - } - if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { - removeItem = BOWL_OF_WATER; - returnItem = BOWL; - } - if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { - removeItem = JUG_OF_WATER; - returnItem = JUG; - } + Item removeItem = null; + Item returnItem = null; + if (event.getUsedItem().getId() == Items.BUCKET_OF_WATER_1929 || event.getBaseItem().getId() == Items.BUCKET_OF_WATER_1929) { + removeItem = BUCKET_OF_WATER; + returnItem = BUCKET; + } + if (event.getUsedItem().getId() == Items.BOWL_OF_WATER_1921 || event.getBaseItem().getId() == Items.BOWL_OF_WATER_1921) { + removeItem = BOWL_OF_WATER; + returnItem = BOWL; + } + if (event.getUsedItem().getId() == Items.JUG_OF_WATER_1937 || event.getBaseItem().getId() == Items.JUG_OF_WATER_1937) { + removeItem = JUG_OF_WATER; + returnItem = JUG; + } if (player.getInventory().containsItem(CLAY) && player.getInventory().containsItem(Objects.requireNonNull(removeItem))) { - player.getInventory().remove(removeItem); - player.getInventory().remove(CLAY); - player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); - player.getInventory().add(SOFT_CLAY); - player.getInventory().add(returnItem); - if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { - player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); - } + player.getInventory().remove(removeItem); + player.getInventory().remove(CLAY); + player.getPacketDispatch().sendMessage("You mix the clay and water. You now have some soft, workable clay."); + player.getInventory().add(SOFT_CLAY); + player.getInventory().add(returnItem); + if (!player.getAchievementDiaryManager().hasCompletedTask(DiaryType.LUMBRIDGE, 0, 6) && player.getLocation().getRegionId() == 12341) { + player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 6); + } return true; } else { - return false; - } + return false; + } } } From 9daaeb780caa242d9487a4b12abb8376d4e9dda9 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 12:58:48 +0200 Subject: [PATCH 53/94] small changes based on review --- .../skill/construction/decoration/StaircasePlugin.java | 6 ++---- .../quest/thefremenniktrials/TFTInteractionListeners.kt | 2 +- .../kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java b/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java index 73a4cb12c..b98ed4e01 100644 --- a/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java +++ b/Server/src/main/content/global/skill/construction/decoration/StaircasePlugin.java @@ -73,7 +73,6 @@ public final class StaircasePlugin extends OptionHandler { SceneryBuilder.replace(object, object.transform(object.getId() - 3)); return true; case "remove-room": - int currentZ = player.getLocation().getZ(); int chunkX = player.getLocation().getChunkX(); int chunkY = player.getLocation().getChunkY(); @@ -91,7 +90,7 @@ public final class StaircasePlugin extends OptionHandler { // From ground floor (z=0), stairs could lead to 1st floor (z=1) or the dungeon (z=3) } else { // garden dungeon entrance and oubliette ladders don't need a height selection - if(node.getId() == 13409 || node.getId() == 13675 || node.getId() == 13676 || node.getId() == 13677 || node.getId() == 13678 || node.getId() == 13679 || node.getId() == 13680) { + if (node.getId() == 13409 || node.getId() == 13675 || node.getId() == 13676 || node.getId() == 13677 || node.getId() == 13678 || node.getId() == 13679 || node.getId() == 13680) { player.getDialogueInterpreter().open("con:remove", null, new int[]{chunkX, chunkY}, 3); } else { player.getDialogueInterpreter().sendOptions("Remove which room?", "Room Above", "Room Below", "Cancel"); @@ -111,7 +110,6 @@ public final class StaircasePlugin extends OptionHandler { } return true; - case "climb": if (HouseManager.isInDungeon(player)) { climb(player, 1, house, object); @@ -475,4 +473,4 @@ public final class StaircasePlugin extends OptionHandler { } } -} \ No newline at end of file +} diff --git a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt index 95d4b1827..a2f8ccf0e 100644 --- a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt +++ b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt @@ -283,7 +283,7 @@ class TFTInteractionListeners : InteractionListener { val objects = player.location.region.assembleObjectList(player.location.z) objects.shuffle() for (o in objects) { - if (o.id == 5138) { + if (o.id == Scenery.PORTAL_5138) { return o.location } } diff --git a/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt b/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt index 9997bb2b1..4f94a404e 100644 --- a/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt +++ b/Server/src/main/content/region/kandarin/ardougne/quest/hazeelcult/AlomoneDialogue.kt @@ -101,7 +101,7 @@ class AlomoneDialogue(player: Player? = null) : DialoguePlugin(player) { 26 -> { end() removeItem(player, HAZEEL_SCROLL) - val hazeel = player.findNpcInViewport(NPCs.HAZEEL_892) + val hazeel = player.findNearbyNPC(NPCs.HAZEEL_892) hazeel?.clear() removeAttribute(player,"hazeelSpawned") finishQuest(player, Quests.HAZEEL_CULT) @@ -130,7 +130,7 @@ class AlomoneDialogue(player: Player? = null) : DialoguePlugin(player) { // this has the potential to remove other players' hazeels, but the player could still complete the quest by either continuing their // active dialogue or speaking to alomone, and just dealing with the fact that their hazeel is not on the map. relogging and restarting // the dialogue would get these players a new hazeel. - private fun Player.findNpcInViewport(npcId: Int): NPC? { + private fun Player.findNearbyNPC(npcId: Int): NPC? { for (npc in RegionManager.getLocalNPCs(location)) { if (npc.id == npcId) { return npc From b8b84759548983c149fdb49b3a9fe56841317011 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 13:10:31 +0200 Subject: [PATCH 54/94] vinesweeper restore original hole --- .../minigame/vinesweeper/Vinesweeper.kt | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt index 7d3fec4a0..151a265da 100644 --- a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt +++ b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt @@ -388,7 +388,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { } } for (scenery in wipedHoles) { - SceneryBuilder.replace(scenery, scenery.transform(HOLES[0])) + restoreOriginalHole(scenery) } } @@ -652,6 +652,7 @@ class VinesweeperNPC : AbstractNPC { scheduleNPCs(dest.player, dest.loc, alive = true, rabbit = false) } } + fun handleFarmerSeed(scenery: Scenery, dest: Vinesweeper.SeedDestination) { lock() var i = 0 @@ -665,14 +666,7 @@ class VinesweeperNPC : AbstractNPC { 1 -> { animate(Animation(Animations.GNOME_FARMER_SPADE_SMACK_8732)) sendChat(FARMER_FLAG_LINES.DEAD_PLANT.line) - var originalHoleId = HOLES[0] - for (obj in scenery.location.chunk.getStatObjects(scenery.location.chunkOffsetX, scenery.location.chunkOffsetY)) { - if (obj?.id != null) { - originalHoleId = obj.id - break - } - } - SceneryBuilder.replace(scenery, scenery.transform(originalHoleId)) + restoreOriginalHole(scenery) } 2 -> { animate(Animation(Animations.GNOME_FARMER_CLEAR_HOLES_8724)) @@ -699,7 +693,7 @@ class VinesweeperNPC : AbstractNPC { sendChat(FARMER_FLAG_LINES.FIND_FLAG.line) } 1 -> { - SceneryBuilder.replace(scenery, scenery.transform(HOLES[0])) + restoreOriginalHole(scenery) if (SEED_LOCS.contains(dest.loc)) { sendChat(FARMER_FLAG_LINES.FIND_SEED.line) animate(Animation(Animations.GNOME_FARMER_HOORAY_8731)) @@ -733,7 +727,7 @@ class VinesweeperNPC : AbstractNPC { for (dy in -FARMER_CLEAR_RADIUS..FARMER_CLEAR_RADIUS) { val toClear = getScenery(dest.loc.transform(dx, dy, 0)) if (toClear != null && intArrayOf(Sceneries.DEAD_PLANT_29456, *NUMBERS).contains(toClear.id)) { - SceneryBuilder.replace(toClear, toClear.transform(HOLES[0])) + restoreOriginalHole(toClear) } } } @@ -742,6 +736,16 @@ class VinesweeperNPC : AbstractNPC { } } +fun restoreOriginalHole(scenery: Scenery) { + var originalHoleId = HOLES[0] + for (obj in scenery.location.chunk.getStatObjects(scenery.location.chunkOffsetX, scenery.location.chunkOffsetY)) { + if (obj?.id != null) { + originalHoleId = obj.id + break + } + } + SceneryBuilder.replace(scenery, scenery.transform(originalHoleId)) +} /* From bf6c40afad04a121953a29c7618590b35925fe8c Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 13:13:54 +0200 Subject: [PATCH 55/94] fix build --- .../rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt index a2f8ccf0e..cf5685f96 100644 --- a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt +++ b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt @@ -22,6 +22,7 @@ import core.game.world.GameWorld.Pulser import content.data.Quests import core.game.interaction.QueueStrength import core.game.node.Node +import org.rs09.consts.Scenery class TFTInteractionListeners : InteractionListener { From 5b4d699e363da4d63ddc7586cf7faf6c4ebe078f Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 18:28:33 +0200 Subject: [PATCH 56/94] fix retribution double dmg --- .../main/core/game/node/entity/player/link/prayer/Prayer.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java index 1a3ff9ff8..9d2a6f00a 100644 --- a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java +++ b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java @@ -108,9 +108,6 @@ public final class Prayer { playAudio(player, Sounds.FIREBREATH_159); player.graphics(Graphics.create(437)); int maximum = (int) (player.getSkills().getStaticLevel(Skills.PRAYER) * 0.25) - 1; - if (killer != player && killer.getLocation().withinDistance(player.getLocation(), 1)) { - killer.getImpactHandler().manualHit(player, 1 + RandomFunction.randomize(maximum), HitsplatType.NORMAL); - } if (player.getProperties().isMultiZone()) { List targets; if (killer instanceof NPC) { From 3a5a71f6af8a828b29ba9f58071fec023168056e Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 14 Jul 2026 19:16:00 +0200 Subject: [PATCH 57/94] fix retribution correctly --- .../core/game/node/entity/player/link/prayer/Prayer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java index 9d2a6f00a..b11eac8b2 100644 --- a/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java +++ b/Server/src/main/core/game/node/entity/player/link/prayer/Prayer.java @@ -108,6 +108,9 @@ public final class Prayer { playAudio(player, Sounds.FIREBREATH_159); player.graphics(Graphics.create(437)); int maximum = (int) (player.getSkills().getStaticLevel(Skills.PRAYER) * 0.25) - 1; + if (killer != player && killer.getLocation().withinDistance(player.getLocation(), 1)) { + killer.getImpactHandler().manualHit(player, 1 + RandomFunction.randomize(maximum), HitsplatType.NORMAL); + } if (player.getProperties().isMultiZone()) { List targets; if (killer instanceof NPC) { @@ -116,7 +119,7 @@ public final class Prayer { targets = RegionManager.getLocalPlayers(player.getLocation(), 1); } for (Entity entity : targets) { - if (entity == player) { + if (entity == player || entity == killer) { continue; } if (entity.isAttackable(player, CombatStyle.MAGIC, false)) { From 319b019ec313673c548a75aa655778b254fd493e Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 15 Jul 2026 07:48:20 +0200 Subject: [PATCH 58/94] fix dhally spec bug --- .../handlers/item/equipment/special/SweepSpecialHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index c51e3532e..f01773bd1 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -101,7 +101,7 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); for (Entity n : victim instanceof NPC ? RegionManager.getSurroundingNPCs(victim, 9) : RegionManager.getSurroundingPlayers(victim, 9)) { - if (n == entity) { + if (n == entity || n == victim) { continue; } if (n instanceof Familiar) { From 9c42c7e4c986611b5fce6d383bbae09942ffdd0d Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 15 Jul 2026 08:00:36 +0200 Subject: [PATCH 59/94] Improve lunar group spells --- .../global/skill/magic/lunar/HealSpell.java | 2 +- .../skill/magic/lunar/LunarListeners.kt | 12 ++++----- .../skill/magic/lunar/StatBoostSpell.java | 26 ++++++++++--------- .../skill/magic/lunar/StatRestoreSpell.java | 26 ++++++++++--------- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java index e7db4f75c..8485e6e06 100644 --- a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java @@ -118,7 +118,7 @@ public final class HealSpell extends MagicSpell { List players = RegionManager.getLocalPlayers(player.getLocation(), 1); for (Iterator it = players.iterator(); it.hasNext();) { Player p = it.next(); - if (p.getName() == player.getName() || !p.getSettings().isAcceptAid() || !p.isActive() || p.getSkills().getLifepoints() == p.getSkills().getMaximumLifepoints()) { + if (p == player || !p.getSettings().isAcceptAid() || !p.isActive() || p.getSkills().getLifepoints() == p.getSkills().getMaximumLifepoints()) { it.remove(); } } diff --git a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt index c32a4b69d..3bbfa2881 100644 --- a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt +++ b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt @@ -497,16 +497,16 @@ class LunarListeners : SpellListener("lunar"), Commands { removeRunes(player, true) visualizeSpell(player, Animations.LUNAR_SPELLBOOK_CURE_GROUP_4409, Graphics.LUNAR_SPELLBOOK_CURE_GROUP_744, 130, Sounds.LUNAR_CURE_GROUP_2882) curePoison(player) - for (player in RegionManager.getLocalPlayers(player.location, 1)) { - if (!player.isActive || player.locks.isInteractionLocked) { + for (otherPlayer in RegionManager.getLocalPlayers(player.location, 1)) { + if (otherPlayer == player || !otherPlayer.isActive || otherPlayer.locks.isInteractionLocked) { continue } - if (!player.settings.isAcceptAid) { + if (!otherPlayer.settings.isAcceptAid) { continue } - curePoison(player) - sendMessage(player, "You have been cured of poison.") - visualizeSpell(player, -1, Graphics.LUNAR_SPELLBOOK_CURE_GROUP_744, 130, Sounds.LUNAR_CURE_OTHER_INDIVIDUAL_2889) + curePoison(otherPlayer) + sendMessage(otherPlayer, "You have been cured of poison.") + visualizeSpell(otherPlayer, -1, Graphics.LUNAR_SPELLBOOK_CURE_GROUP_744, 130, Sounds.LUNAR_CURE_OTHER_INDIVIDUAL_2889) } addXP(player, 74.0) } diff --git a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java index b58529e77..b1af331fd 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java @@ -16,6 +16,7 @@ import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; import core.plugin.Plugin; +import org.rs09.consts.Items; import org.rs09.consts.Sounds; import java.util.List; @@ -63,7 +64,7 @@ public final class StatBoostSpell extends MagicSpell { int size = 0; for (Player o : pl) { if (size >= doses) break; - if (!o.isActive() || o.getLocks().isInteractionLocked() || o == player) { + if (!o.isActive() || o.getLocks().isInteractionLocked()) { continue; } if (!o.getSettings().isAcceptAid() && !(o instanceof AIPlayer)) { @@ -79,17 +80,18 @@ public final class StatBoostSpell extends MagicSpell { return false; } super.meetsRequirements(player, true, true); - potion.getEffect().activate(player); - playGlobalAudio(player.getLocation(), Sounds.LUNAR_STRENGTH_SHARE_2901); - player.animate(ANIMATION); - player.graphics(GRAPHICS); - player.getInventory().remove(item); - int newIndex = (potion.getIds().length - doses) + size; - if (newIndex > potion.getIds().length - 1) { - player.getInventory().add(new Item(229)); - return true; - } - player.getInventory().add(new Item(potion.getIds()[newIndex])); + if (player.getInventory().remove(item)) { + potion.getEffect().activate(player); + playGlobalAudio(player.getLocation(), Sounds.LUNAR_STRENGTH_SHARE_2901); + player.animate(ANIMATION); + player.graphics(GRAPHICS); + int newIndex = (potion.getIds().length - doses) + size; + if (newIndex > potion.getIds().length - 1) { + player.getInventory().add(new Item(Items.VIAL_229)); + return true; + } + player.getInventory().add(new Item(potion.getIds()[newIndex])); + } return true; } } diff --git a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java index b7aa4d15c..505d3921d 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java @@ -16,6 +16,7 @@ import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Plugin; +import org.rs09.consts.Items; import org.rs09.consts.Sounds; import java.util.List; @@ -45,22 +46,22 @@ public class StatRestoreSpell extends MagicSpell { Item item = ((Item) target); player.getInterfaceManager().setViewedTab(6); - if (Consumables.getConsumableById(item.getId()) == null) { + if (Consumables.getConsumableById(item.getId()) == null) { player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); - return false; - } + return false; + } final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable(); if (potion == null) { - player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); + player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); return false; } if (!item.getDefinition().isTradeable() || !isRestore(potion)) { player.getPacketDispatch().sendMessage("You can't cast this spell on that item."); return false; } - List pl = RegionManager.getLocalPlayers(player.getLocation(), 2); + List pl = RegionManager.getLocalPlayers(player.getLocation(), 1); int doses = potion.getDose(item); if (pl.isEmpty()) { return false; @@ -90,13 +91,14 @@ public class StatRestoreSpell extends MagicSpell { playGlobalAudio(player.getLocation(), Sounds.LUNAR_STAT_SHARE_2899); player.animate(ANIMATION); player.graphics(GRAPHICS); - player.getInventory().remove(item); - int newIndex = (potion.getIds().length - doses) + size; - if (newIndex > potion.getIds().length - 1) { - player.getInventory().add(new Item(229)); - return true; - } - player.getInventory().add(new Item(potion.getIds()[newIndex])); + if (player.getInventory().remove(item)) { + int newIndex = (potion.getIds().length - doses) + size; + if (newIndex > potion.getIds().length - 1) { + player.getInventory().add(new Item(Items.VIAL_229)); + return true; + } + player.getInventory().add(new Item(potion.getIds()[newIndex])); + } return true; } From 2297aa6b32b37d2ce899f7c09d715c2259ce0b0f Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 15 Jul 2026 08:03:02 +0200 Subject: [PATCH 60/94] make kq not enumerate local players twice --- .../content/region/desert/handlers/KalphiteQueenNPC.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java b/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java index 63d971e66..b9ec27143 100644 --- a/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java +++ b/Server/src/main/content/region/desert/handlers/KalphiteQueenNPC.java @@ -315,12 +315,10 @@ public final class KalphiteQueenNPC extends AbstractNPC { return; } if (style == CombatStyle.MAGIC) { - BattleState[] states = new BattleState[RegionManager.getLocalPlayers(entity.getLocation()).size() + 1]; + List localPlayers = RegionManager.getLocalPlayers(entity.getLocation()); + BattleState[] states = new BattleState[localPlayers.size() + 1]; int index = 1; - if (states.length == 0) { - return; - } - for (Player p : RegionManager.getLocalPlayers(entity.getLocation())) { + for (Player p : localPlayers) { if (p != victim) { states[index++] = new BattleState(entity, p); } From 12d7f526ac0f6ec1d147bb73d824c106a32b166d Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 15 Jul 2026 08:07:13 +0200 Subject: [PATCH 61/94] flag active/inactive consistency --- Server/src/main/core/game/world/map/RegionChunk.java | 2 ++ Server/src/main/core/game/world/map/RegionManager.kt | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 55b94e5c2..e86f2609e 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -251,6 +251,7 @@ public class RegionChunk { players.add(player); Region region = getCurrentBase().getRegion(); region.getTolerances().put(player.getName(), System.currentTimeMillis()); + region.flagActive(); } /** @@ -284,6 +285,7 @@ public class RegionChunk { players.remove(player); Region region = getCurrentBase().getRegion(); region.getTolerances().remove(player.getName()); + region.checkInactive(); } /** diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index e60c43296..7d5feb87a 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -386,7 +386,6 @@ object RegionManager { src.region.decrementViewAmount() dst.chunk.addPlayer(entity) dst.region.incrementViewAmount() - dst.region.flagActive() } is NPC -> { src.chunk.remove(entity) From 9b5ffa22554f9e32220e41910c6e03d145348693 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 21 Jul 2026 15:48:35 +0200 Subject: [PATCH 62/94] don't invent start position if you don't have one yet --- Server/src/main/core/game/node/entity/npc/NPC.java | 2 +- .../player/info/login/LoginConfiguration.java | 2 +- .../src/main/core/game/world/map/RegionManager.kt | 14 +++++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index 15877b6f8..07acec56f 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -214,7 +214,7 @@ public class NPC extends Entity { getProperties().setSpawnLocation(getLocation()); initConfig(); Repository.getNpcs().add(this); - RegionManager.move(this, ServerConstants.START_LOCATION, location); + RegionManager.move(this, null, location); if (getLocation().getRegion().isActive()) { Repository.addRenderableNPC(this); } diff --git a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java index 4a7c87c91..5133f4a58 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java +++ b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java @@ -130,7 +130,7 @@ public final class LoginConfiguration { Repository.getLobbyPlayers().remove(player); player.setPlaying(true); UpdateSequence.getRenderablePlayers().add(player); - RegionManager.move(player, ServerConstants.START_LOCATION, player.getLocation()); + RegionManager.move(player, null, player.getLocation()); player.getMusicPlayer().init(); player.updateAppearance(); player.getPlayerFlags().setUpdateSceneGraph(true); diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 7d5feb87a..16c0deccd 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -378,17 +378,21 @@ object RegionManager { * @param entity The entity. */ @JvmStatic - fun move(entity: Entity, src: Location, dst: Location) { - if (src.chunk != dst.chunk) { + fun move(entity: Entity, src: Location?, dst: Location) { + if (src?.chunk != dst.chunk) { when (entity) { is Player -> { - src.chunk.removePlayer(entity) - src.region.decrementViewAmount() + if (src != null) { + src.chunk.removePlayer(entity) + src.region.decrementViewAmount() + } dst.chunk.addPlayer(entity) dst.region.incrementViewAmount() } is NPC -> { - src.chunk.remove(entity) + if (src != null) { + src.chunk.remove(entity) + } dst.chunk.add(entity) } else -> { From 9ce45ddcc0f9214b091efdc5e7ab0630be69952c Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 21 Jul 2026 17:11:54 +0200 Subject: [PATCH 63/94] Fix clipping flag update ordering issue --- Server/src/main/core/game/world/map/RegionChunk.java | 6 +++--- .../src/main/core/game/world/map/build/DynamicRegion.java | 4 ++-- .../src/main/core/game/world/update/ChunkUpdateTracker.kt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index e86f2609e..385d7a705 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -635,7 +635,7 @@ public class RegionChunk { /** * Resets the flags. */ - public void resetFlags() { + public void resetUpdateFlags() { updateFlags.clear(); } @@ -658,7 +658,7 @@ public class RegionChunk { /** * Reinitializes the clipping flags; used when a region is copied into a new dynamic region. */ - public void syncFlagsToRegionManager() { + public void resetClippingFlags() { flags = new ChunkFlags(currentBase.getX(), currentBase.getY(), currentBase.getZ()); projectileFlags = new ChunkFlags(currentBase.getX(), currentBase.getY(), currentBase.getZ(), true); } @@ -667,7 +667,7 @@ public class RegionChunk { * Rebuilds the clipping flags based on those of a source chunk (used when a chunk is being replaced). * @param from The region plane to get the new clipping flags from. */ - public void rebuildFlags(RegionChunk from) { + public void rebuildClippingFlags(RegionChunk from) { for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { // Import the landscape flags from the template chunk to the new chunk diff --git a/Server/src/main/core/game/world/map/build/DynamicRegion.java b/Server/src/main/core/game/world/map/build/DynamicRegion.java index 7e5ce124a..c1a7ac7de 100644 --- a/Server/src/main/core/game/world/map/build/DynamicRegion.java +++ b/Server/src/main/core/game/world/map/build/DynamicRegion.java @@ -290,8 +290,8 @@ public final class DynamicRegion extends Region { Location currentBase = getBaseLocation().transform(x << 3, y << 3, z); replacement.setCurrentBase(currentBase); replacement.rebaseObjects(); - replacement.rebuildFlags(orig); - replacement.syncFlagsToRegionManager(); + replacement.resetClippingFlags(); + replacement.rebuildClippingFlags(orig); for (NPC npc : orig.getNpcs()) { Location newLoc = currentBase.transform(npc.getLocation().getChunkOffsetX(), npc.getLocation().getChunkOffsetY(), 0); NPC copy = NPC.create(npc.getId(), newLoc, npc.getDirection()); diff --git a/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt b/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt index 03a3d9d0d..3db33d592 100644 --- a/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt +++ b/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt @@ -13,7 +13,7 @@ object ChunkUpdateTracker : ChunkDirtyListener { /** Resets flags on exactly the chunks flagged this tick. Must run after all per-player flushes. */ fun resetAll() { - dirty.forEach { it.resetFlags() } + dirty.forEach { it.resetUpdateFlags() } dirty.clear() } } From c6fd45eb62449065638eb782b0aa47a46f818349 Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 22 Jul 2026 13:02:48 +0200 Subject: [PATCH 64/94] more fixes --- Server/src/main/content/global/bots/DoublingMoney.kt | 1 - .../main/content/global/skill/magic/lunar/StatBoostSpell.java | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Server/src/main/content/global/bots/DoublingMoney.kt b/Server/src/main/content/global/bots/DoublingMoney.kt index 8840191eb..36b8ccf30 100644 --- a/Server/src/main/content/global/bots/DoublingMoney.kt +++ b/Server/src/main/content/global/bots/DoublingMoney.kt @@ -22,7 +22,6 @@ import core.game.bots.Script import core.game.interaction.IntType import core.game.interaction.InteractionListeners import core.game.world.ImmerseWorld -import core.game.world.repository.Repository import java.io.File import java.io.FileReader import java.util.Random diff --git a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java index b1af331fd..5df9fc5ff 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java @@ -64,6 +64,9 @@ public final class StatBoostSpell extends MagicSpell { int size = 0; for (Player o : pl) { if (size >= doses) break; + if (o == player) { + continue; + } if (!o.isActive() || o.getLocks().isInteractionLocked()) { continue; } From f797ea1b370c559c7353c6d1b42e2b008271e1b0 Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 22 Jul 2026 13:27:43 +0200 Subject: [PATCH 65/94] aggro fixes --- .../command/sets/DevelopmentCommandSet.kt | 4 ++-- .../main/core/game/world/map/RegionChunk.java | 2 -- .../main/core/game/world/map/RegionManager.kt | 23 ++++++++++++------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt index 780319bc3..dc2fb3159 100644 --- a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt @@ -385,14 +385,14 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { sendMessage(player, "${player.location.chunk.players.size} players and ${player.location.chunk.npcs.size} npcs on this chunk.") sendMessage(player, "Entities on this tile:") for (p in RegionManager.getLocalPlayers(player.location, 0)) { - sendMessage(p, " player ${player.username}") + sendMessage(player, " player ${player.username}") } for (npc in RegionManager.getLocalNPCs(player.location, 0)) { sendMessage(player, " npc ${npc.name}") } sendMessage(player, "Entities within render distance:") for (p in RegionManager.getLocalPlayers(player.location)) { - sendMessage(p, " player ${player.username} at ${player.location}") + sendMessage(player, " player ${player.username} at ${player.location}") } for (npc in RegionManager.getLocalNPCs(player.location)) { sendMessage(player, " npc ${npc.name} at ${npc.location}}") diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 385d7a705..3a5986abe 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -250,7 +250,6 @@ public class RegionChunk { public void addPlayer(Player player) { players.add(player); Region region = getCurrentBase().getRegion(); - region.getTolerances().put(player.getName(), System.currentTimeMillis()); region.flagActive(); } @@ -284,7 +283,6 @@ public class RegionChunk { public void removePlayer(Player player) { players.remove(player); Region region = getCurrentBase().getRegion(); - region.getTolerances().remove(player.getName()); region.checkInactive(); } diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 16c0deccd..07f602ae5 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -382,12 +382,21 @@ object RegionManager { if (src?.chunk != dst.chunk) { when (entity) { is Player -> { - if (src != null) { - src.chunk.removePlayer(entity) - src.region.decrementViewAmount() + val player = entity.asPlayer() + val sameRegion = src?.region == dst.region + if (src != null && sameRegion) { + src.chunk.removePlayer(player) + dst.chunk.addPlayer(player) + } else { + if (src != null) { + src.chunk.removePlayer(player) + src.region.tolerances.remove(player.name) + src.region.decrementViewAmount() + } + dst.chunk.addPlayer(entity) + dst.region.tolerances[entity.asPlayer().name] = System.currentTimeMillis() + dst.region.incrementViewAmount() } - dst.chunk.addPlayer(entity) - dst.region.incrementViewAmount() } is NPC -> { if (src != null) { @@ -395,9 +404,7 @@ object RegionManager { } dst.chunk.add(entity) } - else -> { - throw (IllegalStateException("Tried to move an Entity that was neither Player nor NPC")) - } + else -> throw IllegalStateException("Tried to move an Entity that was neither Player nor NPC") } } entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint) From 642dc4b162dd5b1da06d916e3a93c08f34fab4a8 Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 22 Jul 2026 14:24:46 +0200 Subject: [PATCH 66/94] wider get local entities range, some things depend on it --- .../main/core/game/world/map/RegionManager.kt | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 07f602ae5..b75b5b774 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -415,13 +415,12 @@ object RegionManager { * @param location the location. * @param distance the distance. * @param maximum the maximum number of entities to return. - * @param ignore an entity to exclude (may be null). * @return the list. */ - inline fun getLocalEntities(location: Location, distance: Int, maximum: Int, ignore: Entity?): List { + inline fun getLocalEntities(location: Location, distance: Int, maximum: Int): List { val entities: MutableList = ArrayList(20) - for (cx in (location.absChunkX - 2)..(location.absChunkX + 2)) { - for (cy in (location.absChunkY - 2)..(location.absChunkY + 2)) { + for (cx in (location.absChunkX - 8)..(location.absChunkX + 8)) { + for (cy in (location.absChunkY - 8)..(location.absChunkY + 8)) { val chunk = Location(cx shl 3, cy shl 3, location.z).chunk if (T::class.java.isAssignableFrom(Player::class.java)) { entities.addAll(chunk.players as Collection) @@ -432,20 +431,20 @@ object RegionManager { } } val b = ZoneBorders(location.x - distance, location.y - distance, location.x + distance, location.y + distance) - var filtered = entities.filter { it != ignore && b.insideBorder(it.location.x, it.location.y) } + var filtered = entities.filter { b.insideBorder(it.location.x, it.location.y) } if (maximum > 0 && filtered.size > maximum) { filtered = filtered.slice(0 until maximum) } return filtered } - @JvmStatic fun getLocalEntities(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) - @JvmStatic fun getLocalPlayers(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) - @JvmStatic fun getLocalNPCs(location: Location, distance: Int): List = getLocalEntities(location, distance, 0, null) - @JvmStatic fun getLocalPlayers(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0, null) - @JvmStatic fun getLocalNPCs(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0, null) - @JvmStatic fun getSurroundingPlayers(player: Entity, maximum: Int): List = getLocalEntities(player.location, 1, maximum, null) - @JvmStatic fun getSurroundingNPCs(npc: Entity, maximum: Int): List = getLocalEntities(npc.location, 1, maximum, null) - @JvmStatic fun getLocalPlayersBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum, null) + @JvmStatic fun getLocalEntities(location: Location, distance: Int): List = getLocalEntities(location, distance, 0) + @JvmStatic fun getLocalPlayers(location: Location, distance: Int): List = getLocalEntities(location, distance, 0) + @JvmStatic fun getLocalNPCs(location: Location, distance: Int): List = getLocalEntities(location, distance, 0) + @JvmStatic fun getLocalPlayers(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0) + @JvmStatic fun getLocalNPCs(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0) + @JvmStatic fun getSurroundingPlayers(player: Entity, maximum: Int): List = getLocalEntities(player.location, 1, maximum) + @JvmStatic fun getSurroundingNPCs(npc: Entity, maximum: Int): List = getLocalEntities(npc.location, 1, maximum) + @JvmStatic fun getLocalPlayersBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum) /** * Gets a random teleport location in the radius around the given location. From c4fa99d6d34edca0de8464b95aa5a09583d3bac5 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 25 Jul 2026 08:32:24 +0200 Subject: [PATCH 67/94] lunar pot fixes --- .../global/skill/magic/lunar/HealSpell.java | 3 ++- .../skill/magic/lunar/StatBoostSpell.java | 11 ++++++----- .../skill/magic/lunar/StatRestoreSpell.java | 17 ++++++----------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java index 8485e6e06..7059385aa 100644 --- a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java @@ -1,5 +1,6 @@ package content.global.skill.magic.lunar; +import core.game.bots.AIPlayer; import core.game.node.entity.combat.spell.MagicSpell; import core.game.node.entity.combat.spell.Runes; import core.plugin.Initializable; @@ -92,7 +93,7 @@ public final class HealSpell extends MagicSpell { player.getPacketDispatch().sendMessage("This player is busy."); return false; } - if (!o.getSettings().isAcceptAid()) { + if (!o.getSettings().isAcceptAid() || (o instanceof AIPlayer)) { player.getPacketDispatch().sendMessage("The player is not accepting any aid."); return false; } diff --git a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java index 5df9fc5ff..bdaa387ea 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatBoostSpell.java @@ -41,15 +41,16 @@ public final class StatBoostSpell extends MagicSpell { @Override public boolean cast(Entity entity, Node target) { - final Player player = ((Player) entity); - Item item = ((Item) target); - final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable(); + final Player player = (Player) entity; + Item item = (Item) target; player.getInterfaceManager().setViewedTab(6); + + final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable(); if (potion == null) { player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); return false; } - if (!item.getDefinition().isTradeable() || item.getName().toLowerCase().contains("restore") || item.getName().toLowerCase().contains("zamorak") || item.getName().toLowerCase().contains("saradomin") || item.getName().toLowerCase().contains("combat")) { + if (!item.getDefinition().isTradeable() || item.getName().toLowerCase().contains("restore") || item.getName().toLowerCase().contains("zamorak") || item.getName().toLowerCase().contains("saradomin")) { player.getPacketDispatch().sendMessage("You can't cast this spell on that item."); return false; } @@ -70,7 +71,7 @@ public final class StatBoostSpell extends MagicSpell { if (!o.isActive() || o.getLocks().isInteractionLocked()) { continue; } - if (!o.getSettings().isAcceptAid() && !(o instanceof AIPlayer)) { + if (!o.getSettings().isAcceptAid() || o instanceof AIPlayer) { continue; } o.graphics(GRAPHICS); diff --git a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java index 505d3921d..dda2b5d6d 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java @@ -46,13 +46,7 @@ public class StatRestoreSpell extends MagicSpell { Item item = ((Item) target); player.getInterfaceManager().setViewedTab(6); - if (Consumables.getConsumableById(item.getId()) == null) { - player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); - return false; - } - final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable(); - if (potion == null) { player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); return false; @@ -63,22 +57,23 @@ public class StatRestoreSpell extends MagicSpell { } List pl = RegionManager.getLocalPlayers(player.getLocation(), 1); int doses = potion.getDose(item); - if (pl.isEmpty()) { - return false; - } if (!super.meetsRequirements(player, true, false)) { return false; } int size = 0; for (Player o : pl) { if (size >= doses) break; - if (!o.isActive() || o.getLocks().isInteractionLocked() || o == player) { + if (o == player) { continue; } - if (!o.getSettings().isAcceptAid() && !(o instanceof AIPlayer)) { + if (!o.isActive() || o.getLocks().isInteractionLocked()) { + continue; + } + if (!o.getSettings().isAcceptAid() || (o instanceof AIPlayer)) { continue; } o.graphics(GRAPHICS); + playGlobalAudio(o.getLocation(), Sounds.LUNAR_STAT_SHARE_INDIVIDUAL_2897); potion.getEffect().activate(o); size++; } From 6d7818951bea739d11f0cfa621891021122a8032 Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 25 Jul 2026 16:49:51 +0200 Subject: [PATCH 68/94] tears of guthix and fix of resulting edge cases --- .../skill/construction/BuildingUtils.java | 20 ++-- .../global/skill/construction/Room.java | 31 +++--- .../minigame/vinesweeper/Vinesweeper.kt | 16 +-- .../tearsofguthix/TearsOfGuthixMinigame.kt | 53 ++++------ Server/src/main/core/api/ContentAPI.kt | 5 +- .../system/command/sets/SpawnCommandSet.kt | 4 +- .../src/main/core/game/world/map/Region.java | 2 +- .../main/core/game/world/map/RegionChunk.java | 100 ++++++++---------- .../main/core/game/world/map/RegionManager.kt | 5 +- .../game/world/map/build/LandscapeParser.java | 6 +- 10 files changed, 111 insertions(+), 131 deletions(-) diff --git a/Server/src/main/content/global/skill/construction/BuildingUtils.java b/Server/src/main/content/global/skill/construction/BuildingUtils.java index 158d7abbb..ad8b71bcd 100644 --- a/Server/src/main/content/global/skill/construction/BuildingUtils.java +++ b/Server/src/main/content/global/skill/construction/BuildingUtils.java @@ -289,9 +289,11 @@ public final class BuildingUtils { h.setDecorationIndex(decIndex); int objectId = hotspot.getHotspot().getObjectId(style); int index = chunk.getIndex(x, y, objectId, -1); - Scenery o = chunk.getObjects()[index][x][y]; - if (o != null && objectId == o.getId()) { - SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getDecorations()[decIndex].getObjectId(style))); + if (index != -1) { + Scenery o = chunk.getObjects()[x][y][index]; + if (objectId == o.getId()) { + SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getDecorations()[decIndex].getObjectId(style))); + } } } } @@ -308,9 +310,11 @@ public final class BuildingUtils { h.setDecorationIndex(decIndex); int objectId = bh.getObjectId(style); int index = chunk.getIndex(x, y, objectId, -1); - Scenery o = chunk.getObjects()[index][x][y]; - if (o != null && objectId == o.getId()) { - SceneryBuilder.replace(o, o.transform(bh.getDecorations()[decIndex].getObjectId(style))); + if (index != -1) { + Scenery o = chunk.getObjects()[x][y][index]; + if (objectId == o.getId()) { + SceneryBuilder.replace(o, o.transform(bh.getDecorations()[decIndex].getObjectId(style))); + } } } } @@ -423,7 +427,7 @@ public final class BuildingUtils { if (h != null) { int objectId = hotspot.getHotspot().getDecorations()[h.getDecorationIndex()].getObjectId(style); int index = chunk.getIndex(x, y, objectId, -1); - Scenery o = chunk.getObjects()[index][x][y]; + Scenery o = chunk.getObjects()[x][y][index]; h.setDecorationIndex(-1); if (o != null && objectId == o.getId()) { SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getObjectId(style))); @@ -442,7 +446,7 @@ public final class BuildingUtils { if (h != null) { int objectId = bh.getDecorations()[h.getDecorationIndex()].getObjectId(style); int index = chunk.getIndex(x, y, objectId, -1); - Scenery o = chunk.getObjects()[index][x][y]; + Scenery o = chunk.getObjects()[x][y][index]; h.setDecorationIndex(-1); if (o != null && objectId == o.getId()) { SceneryBuilder.replace(o, o.transform(bh.getObjectId(style))); diff --git a/Server/src/main/content/global/skill/construction/Room.java b/Server/src/main/content/global/skill/construction/Room.java index 28f068ac4..508fa6370 100644 --- a/Server/src/main/content/global/skill/construction/Room.java +++ b/Server/src/main/content/global/skill/construction/Room.java @@ -131,21 +131,22 @@ public final class Room { int y = spot.getChunkY(); int id = spot.getHotspot().getObjectId(house.getStyle()); int index = chunk.getIndex(x, y, id, -1); - Scenery[][] objects = chunk.getObjects()[index]; - Scenery object = objects[x][y]; - if (object != null && object.getId() == spot.getHotspot().getObjectId(house.getStyle())) { - if (spot.getDecorationIndex() > -1 && spot.getDecorationIndex() < spot.getHotspot().getDecorations().length) { - id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getObjectId(house.getStyle()); - if (spot.getHotspot().getType() == BuildHotspotType.CREST) { - id += house.getCrest().ordinal(); + if (index != -1) { + Scenery object = chunk.getObjects()[x][y][index]; + if (object.getId() == spot.getHotspot().getObjectId(house.getStyle())) { + if (spot.getDecorationIndex() > -1 && spot.getDecorationIndex() < spot.getHotspot().getDecorations().length) { + id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getObjectId(house.getStyle()); + if (spot.getHotspot().getType() == BuildHotspotType.CREST) { + id += house.getCrest().ordinal(); + } + SceneryBuilder.replace(object, object.transform(id, object.getRotation(), chunk.getCurrentBase().transform(x, y, 0))); + } else if (object.getId() == BuildHotspot.WINDOW.getObjectId(house.getStyle()) || (!house.isBuildingMode() && object.getId() == BuildHotspot.CHAPEL_WINDOW.getObjectId(house.getStyle()))) { + SceneryBuilder.replace(object, object.transform(house.getStyle().getWindowStyle().getObjectId(house.getStyle()), object.getRotation(), object.getType())); } - SceneryBuilder.replace(object, object.transform(id, object.getRotation(), chunk.getCurrentBase().transform(x, y, 0))); - } else if (object.getId() == BuildHotspot.WINDOW.getObjectId(house.getStyle()) || (!house.isBuildingMode() && object.getId() == BuildHotspot.CHAPEL_WINDOW.getObjectId(house.getStyle()))) { - SceneryBuilder.replace(object, object.transform(house.getStyle().getWindowStyle().getObjectId(house.getStyle()), object.getRotation(), object.getType())); + int[] pos = RegionChunk.getRotatedPosition(x, y, object.getSizeX(), object.getSizeY(), 0, rotation.toInteger()); + spot.setCurrentX(pos[0]); + spot.setCurrentY(pos[1]); } - int[] pos = RegionChunk.getRotatedPosition(x, y, object.getSizeX(), object.getSizeY(), 0, rotation.toInteger()); - spot.setCurrentX(pos[0]); - spot.setCurrentY(pos[1]); } } if (rotation != Direction.NORTH && chunk.getRotation() == 0) { @@ -167,7 +168,7 @@ public final class Room { for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { for (int i = 0; i < RegionChunk.ARRAY_SIZE; i++) { - Scenery object = chunk.getObjects()[i][x][y]; + Scenery object = chunk.getObjects()[x][y][i]; if (object != null) { int id = object.getId(); boolean isBuilt = !object.getDefinition().hasAction("build"); @@ -197,7 +198,7 @@ public final class Room { for (int i = 0; i < RegionChunk.ARRAY_SIZE; i++) { for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { - Scenery object = chunk.getObjects()[i][x][y]; + Scenery object = chunk.getObjects()[x][y][i]; if (object != null && BuildingUtils.isDoorHotspot(object)) { boolean edge = false; Room otherRoom = null; diff --git a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt index 151a265da..0069671f4 100644 --- a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt +++ b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt @@ -374,10 +374,10 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { fun resetChunkIfBarren(chunk: RegionChunk) { val wipedHoles = ArrayList() - for (i in 0 until chunk.objects.size) { - for (x in 0 until 8) { - for (y in 0 until 8) { - val obj = chunk.objects[i][x][y] ?: continue + for (x in 0 until 8) { + for (y in 0 until 8) { + for (i in 0 until 4) { + val obj = chunk.objects[x][y][i] ?: continue if (obj.id in HOLES) { return //this chunk is not barren and hence should not be reset } @@ -393,10 +393,10 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { } fun countFieldState(chunk: RegionChunk, emptyHoleList: ArrayList, seedHoleList: ArrayList) { - for (i in 0 until chunk.objects.size) { - for (x in 0 until 8) { - for (y in 0 until 8) { - val obj = chunk.objects[i][x][y] ?: continue + for (x in 0 until 8) { + for (y in 0 until 8) { + for (i in 0 until 4) { + val obj = chunk.objects[x][y][i] ?: continue if (obj.id in HOLES) { if (obj.location in SEED_LOCS) { seedHoleList.add(obj) diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt index ab27cbd71..da71522ce 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt @@ -11,7 +11,9 @@ import core.game.node.entity.Entity import core.game.node.entity.player.Player import core.game.node.entity.skill.Skills import core.game.node.item.Item +import core.game.node.scenery.SceneryBuilder import core.game.world.map.Location +import core.game.world.map.RegionManager import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneRestriction import core.game.world.update.flag.context.Animation @@ -254,14 +256,12 @@ class TearsOfGuthixMinigame : InteractionListener, EventHook, MapArea } override fun defineListeners() { - on(Scenery.WEEPING_WALL_6660, SCENERY, "collect-from") { player, node -> animate(player, 2043) val index = TearsOfGuthixGlobalTick.allWalls.indexOf(node.location) setAttribute(player, attributeIsCollecting, index) return@on true } - } // Timer step per tick while you are in the minigame. @@ -330,7 +330,6 @@ class TearsOfGuthixMinigame : InteractionListener, EventHook, MapArea * Global Tick class to randomize the walls consistently for everyone. */ class TearsOfGuthixGlobalTick : TickListener { - companion object { var ticks = 0 var globalWallState = intArrayOf(0, 0, 2, 1, 2, 1, 0, 0, 2, 1) @@ -360,43 +359,29 @@ class TearsOfGuthixGlobalTick : TickListener { globalWallState = intArrayOf(0) + wallStates /* - * Explanation: The walls are layered sceneries, which makes it rabidly fucked to change them. - * What I did was to add the tears scenery first (essentially overriding the tears scenery), - * then add the WEEPING_WALL_6660 right after it so that the interactions are still there. - * this is how a layer is like: - * 1 - WEEPING_WALL_6660 - No model, but holds the option "collect-from" - * 2 - BLUE/GREEN/ABSENT - Model of the blue/green/absent waterfall. - * 3 - WEEPING_WALL_6664 - The actual model, but not interactive. - * 6661 - 6664 is left side, 6665 to 6668 is right side + * All walls have two objects: + * 1 - WEEPING_WALL_6660 (type 0) - No model, but holds the option "collect-from" + * 2 - BLUE/GREEN/ABSENT (type 4) - Model of the blue/green/absent waterfall. + * 6665, 6661, 6665 is blue on the north side + * 6662, 6666, 6662 is green on the south side */ wallStates.forEachIndexed { index, state -> - val scenery = getScenery(allWalls[index + 1])!! - val newSceneryId = if (state == 2) { - if (index + 1 <= 5) { - Scenery.GREEN_TEARS_6662 - } else { - Scenery.GREEN_TEARS_6666 + val wallLocation = allWalls[index + 1] + val currentWaterfall = RegionManager.getObject(wallLocation, 4)!! + val newWaterfallId = when (state) { + 2 -> { + if (index + 1 <= 5) Scenery.GREEN_TEARS_6662 else Scenery.GREEN_TEARS_6666 } - } else if (state == 1) { - if (index + 1 <= 5) { - Scenery.BLUE_TEARS_6661 - } else { - Scenery.BLUE_TEARS_6665 + 1 -> { + if (index + 1 <= 5) Scenery.BLUE_TEARS_6661 else Scenery.BLUE_TEARS_6665 } - } else { - if (index + 1 <= 5) { - Scenery.ABSENCE_OF_TEARS_6663 - } else { - Scenery.ABSENCE_OF_TEARS_6667 + else -> { + if (index + 1 <= 5) Scenery.ABSENCE_OF_TEARS_6663 else Scenery.ABSENCE_OF_TEARS_6667 } } - addScenery(core.game.node.scenery.Scenery( - newSceneryId, - scenery.location, - 4, - scenery.rotation - )) - addScenery(core.game.node.scenery.Scenery(Scenery.WEEPING_WALL_6660, scenery.location, 0, scenery.rotation)) + if (currentWaterfall.id != newWaterfallId) { + SceneryBuilder.replace(currentWaterfall, currentWaterfall.transform(newWaterfallId)) + } } } } \ No newline at end of file diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 7e1d6f813..749324d36 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -1078,9 +1078,10 @@ fun findNPC(id: Int): NPC? { * @param x the X coordinate to use * @param y the Y coordinate to use * @param z the Z coordinate to use + * @param type the scenery type, -1 if any */ -fun getScenery(x: Int, y: Int, z: Int): Scenery? { - return RegionManager.getObject(z, x, y) +fun getScenery(x: Int, y: Int, z: Int, type: Int = -1): Scenery? { + return RegionManager.getObject(z, x, y, type) } /** diff --git a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt index 0e2151425..f197553bb 100644 --- a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt @@ -185,8 +185,8 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ } } val stat = ArrayList(10) - for (i in 0 until chunk.statObjects.size) { - val obj = chunk.statObjects[i][player.location.chunkOffsetX][player.location.chunkOffsetY] + for (i in 0 until 4) { + val obj = chunk.statObjects[player.location.chunkOffsetX][player.location.chunkOffsetY][i] if (obj != null) { stat.add(obj) } diff --git a/Server/src/main/core/game/world/map/Region.java b/Server/src/main/core/game/world/map/Region.java index 40e455aea..6524772aa 100644 --- a/Server/src/main/core/game/world/map/Region.java +++ b/Server/src/main/core/game/world/map/Region.java @@ -558,7 +558,7 @@ public class Region { for (int offsetX = 0; offsetX < 8; offsetX++) { for (int offsetY = 0; offsetY < 8; offsetY++) { for (int i = 0; i < 4; i++) { - Scenery object = chunk.getObjects()[i][offsetX][offsetY]; + Scenery object = chunk.getObjects()[offsetX][offsetY][i]; if (object != null) { list.add(object); } diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 3a5986abe..216d1556a 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -118,8 +118,8 @@ public class RegionChunk { this.base = base; this.currentBase = base; this.rotation = rotation; - this.statObjects = new Scenery[ARRAY_SIZE][SIZE][SIZE]; - this.objects = new Scenery[ARRAY_SIZE][SIZE][SIZE]; + this.statObjects = new Scenery[SIZE][SIZE][ARRAY_SIZE]; + this.objects = new Scenery[SIZE][SIZE][ARRAY_SIZE]; this.flags = new ChunkFlags(base.getX(), base.getY(), base.getZ()); this.projectileFlags = new ChunkFlags(base.getX(), base.getY(), base.getZ(), true); } @@ -136,10 +136,10 @@ public class RegionChunk { * Corrects objects' Locations when copying them from a template region into an instance - private version. */ private void rebaseObjects(Scenery[][][] objects) { - for (int i = 0; i < objects.length; i++) { + for (int i = 0; i < ARRAY_SIZE; i++) { for (int x = 0; x < SIZE; x++) { for (int y = 0; y < SIZE; y++) { - Scenery o = objects[i][x][y]; + Scenery o = objects[x][y][i]; if (o == null) { continue; } @@ -153,21 +153,21 @@ public class RegionChunk { * Makes a deep copy of an object list - private version. */ private void copyObjects(Scenery[][][] src, Scenery[][][] dest) { - for (int i = 0; i < src.length; i++) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - Scenery o = src[i][x][y]; + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery o = src[x][y][i]; if (o == null) { continue; } Scenery copy = o.transform(o.getId()); if (o instanceof Constructed) { - dest[i][x][y] = copy.asConstructed(); + dest[x][y][i] = copy.asConstructed(); } else { - dest[i][x][y] = copy; + dest[x][y][i] = copy; } - dest[i][x][y].setActive(o.isActive()); - dest[i][x][y].setRenderable(o.isRenderable()); + dest[x][y][i].setActive(o.isActive()); + dest[x][y][i].setRenderable(o.isRenderable()); } } } @@ -191,11 +191,11 @@ public class RegionChunk { * @return The slot it was added into. */ public int addStatDyn(Scenery object, int chunkOffsetX, int chunkOffsetY) { - for (int i = 0; i < statObjects.length; i++) { - Scenery current = statObjects[i][chunkOffsetX][chunkOffsetY]; + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery current = statObjects[chunkOffsetX][chunkOffsetY][i]; if (current == null) { - statObjects[i][chunkOffsetX][chunkOffsetY] = object; - objects[i][chunkOffsetX][chunkOffsetY] = object.transform(object.getId()); //deep copy so that active/renderable flags don't synchronize across multiple copies of e.g. a POH + statObjects[chunkOffsetX][chunkOffsetY][i] = object; + objects[chunkOffsetX][chunkOffsetY][i] = object.transform(object.getId()); //deep copy so that active/renderable flags don't synchronize across multiple copies of e.g. a POH return i; } if (current.getId() == object.getId()) { @@ -217,10 +217,10 @@ public class RegionChunk { public int add(Scenery object) { int chunkOffsetX = object.getLocation().getChunkOffsetX(); int chunkOffsetY = object.getLocation().getChunkOffsetY(); - for (int i = 0; i < objects.length; i++) { - Scenery current = objects[i][chunkOffsetX][chunkOffsetY]; + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery current = objects[chunkOffsetX][chunkOffsetY][i]; if (current == null) { - objects[i][chunkOffsetX][chunkOffsetY] = object.asConstructed(); + objects[chunkOffsetX][chunkOffsetY][i] = object.asConstructed(); object.setRenderable(true); object.setActive(true); return i; @@ -321,7 +321,7 @@ public class RegionChunk { for (int offsetX = 0; offsetX < 8; offsetX++) { for (int offsetY = 0; offsetY < 8; offsetY++) { for (int i = 0; i < ARRAY_SIZE; i++) { - Scenery object = objects[i][offsetX][offsetY]; + Scenery object = objects[offsetX][offsetY][i]; if (object != null) { list.add(object); } @@ -364,10 +364,10 @@ public class RegionChunk { items.clear(); items = null; } - for (int i = 0; i < objects.length; i++) { - for (int x = 0; x < objects[i].length; x++) { - for (int y = 0; y < objects[i][x].length; y++) { - statObjects[i][x][y] = objects[i][x][y] = null; + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + for (int i = 0; i < ARRAY_SIZE; i++) { + statObjects[x][y][i] = objects[x][y][i] = null; } } } @@ -392,11 +392,11 @@ public class RegionChunk { */ protected boolean appendUpdate(Player player, IoBuffer buffer) { boolean updated = false; - for (int i = 0; i < objects.length; i++) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { - Scenery dyn = objects[i][x][y]; - Scenery stat = statObjects[i][x][y]; + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery dyn = objects[x][y][i]; + Scenery stat = statObjects[x][y][i]; if (dyn == stat) { continue; } @@ -522,11 +522,7 @@ public class RegionChunk { * @return The objects. */ public Scenery[] getObjects(int chunkOffsetX, int chunkOffsetY) { - Scenery[] result = new Scenery[ARRAY_SIZE]; - for (int i = 0; i < objects.length; i++) { - result[i] = objects[i][chunkOffsetX][chunkOffsetY]; - } - return result; + return objects[chunkOffsetX][chunkOffsetY]; } /** @@ -536,11 +532,7 @@ public class RegionChunk { * @return The objects. */ public Scenery[] getStatObjects(int chunkOffsetX, int chunkOffsetY) { - Scenery[] result = new Scenery[ARRAY_SIZE]; - for (int i = 0; i < statObjects.length; i++) { - result[i] = statObjects[i][chunkOffsetX][chunkOffsetY]; - } - return result; + return statObjects[chunkOffsetX][chunkOffsetY]; } /** @@ -567,18 +559,14 @@ public class RegionChunk { * @param type The scenery type. */ public int getIndex(int x, int y, int objectId, int type) { - for (int i = 0; i < objects.length; i++) { - Scenery o = objects[i][x][y]; + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery o = objects[x][y][i]; if (o != null) { if (objectId < 0) { if (type >= 0 && o.getType() != type) { continue; } - // Caller didn't ask for anything specific, so we assume they want whatever *interactable-excluding-examine* object is in here - // We should probably discourage this and instead make functions calling this function more specific - if (o.getDefinition().hasOptions(false)) { - return i; - } + return i; } else { if (o.getId() == objectId) { // TODO: what if there are multiple instances of the same object? Hopefully this is only a theoretical possibility in this game @@ -587,7 +575,7 @@ public class RegionChunk { } } } - return 0; + return -1; } /** @@ -672,8 +660,8 @@ public class RegionChunk { flags.getLandscape()[x][y] = from.getFlags().getLandscape()[x][y]; projectileFlags.getLandscape()[x][y] = from.getProjectileFlags().getLandscape()[x][y]; // Reflag any objects - for (int i = 0; i < objects.length; i++) { - Scenery obj = objects[i][x][y]; + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery obj = objects[x][y][i]; if (obj != null) { LandscapeParser.flagScenery(this, x, y, obj, false, true); } @@ -691,16 +679,14 @@ public class RegionChunk { log(this.getClass(), Log.ERR, "Region chunk was already rotated!"); return; } - Scenery[][][] copy = new Scenery[ARRAY_SIZE][SIZE][SIZE]; - int baseX = currentBase.getLocalX(); - int baseY = currentBase.getLocalY(); + Scenery[][][] copy = new Scenery[SIZE][SIZE][ARRAY_SIZE]; for (int x = 0; x < SIZE; x++) { for (int y = 0; y < SIZE; y++) { - for (int i = 0; i < objects.length; i++) { - Scenery object = copy[i][x][y] = objects[i][x][y]; + for (int i = 0; i < ARRAY_SIZE; i++) { + Scenery object = copy[x][y][i] = objects[x][y][i]; if (object != null) { SceneryBuilder.remove(object); - objects[i][x][y] = null; + objects[x][y][i] = null; } } } @@ -715,10 +701,10 @@ public class RegionChunk { log(this.getClass(), Log.ERR, "Attempted to rotate a chunk in a non-cardinal direction - using fallback rotation code. This should be investigated!"); break; }; - for (int i = 0; i < objects.length; i++) { + for (int i = 0; i < ARRAY_SIZE; i++) { for (int x = 0; x < SIZE; x++) { for (int y = 0; y < SIZE; y++) { - Scenery object = copy[i][x][y]; + Scenery object = copy[x][y][i]; if (object != null) { int[] pos = getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation); Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index b75b5b774..8a78e0a99 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -355,7 +355,10 @@ object RegionManager { Region.load(region) val chunk = region.chunks[loc.chunkX][loc.chunkY][loc.z] val index = chunk.getIndex(loc.chunkOffsetX, loc.chunkOffsetY, objectId, type) - val obj = chunk.objects[index][loc.chunkOffsetX][loc.chunkOffsetY] + if (index == -1) { + return null + } + val obj = chunk.objects[loc.chunkOffsetX][loc.chunkOffsetY][index] if (obj != null && !obj.isRenderable) { return null } diff --git a/Server/src/main/core/game/world/map/build/LandscapeParser.java b/Server/src/main/core/game/world/map/build/LandscapeParser.java index 3c6f44cec..618e3637a 100644 --- a/Server/src/main/core/game/world/map/build/LandscapeParser.java +++ b/Server/src/main/core/game/world/map/build/LandscapeParser.java @@ -158,13 +158,13 @@ public final class LandscapeParser { Region.load(region); RegionChunk chunk = region.getChunks()[loc.getChunkX()][loc.getChunkY()][loc.getZ()]; int index = chunk.getIndex(loc.getChunkOffsetX(), loc.getChunkOffsetY(), object.getId(), object.getType()); - Scenery current = chunk.getObjects()[index][loc.getChunkOffsetX()][loc.getChunkOffsetY()]; - if (current == null || current.getId() != object.getId()) { + if (index == -1) { return null; } + Scenery current = chunk.getObjects()[loc.getChunkOffsetX()][loc.getChunkOffsetY()][index]; current.setActive(false); object.setActive(false); - chunk.getObjects()[index][loc.getChunkOffsetX()][loc.getChunkOffsetY()] = null; + chunk.getObjects()[loc.getChunkOffsetX()][loc.getChunkOffsetY()][index] = null; SceneryDefinition def = object.getDefinition(); // Remove its clipping flags From 74d563837c04518aa797428194bc0826beef17db Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 05:38:30 +0000 Subject: [PATCH 69/94] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: GregF --- Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java b/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java index bf41dc764..0cd9dff53 100644 --- a/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java +++ b/Server/src/main/content/minigame/pestcontrol/PCPortalNPC.java @@ -144,7 +144,8 @@ public final class PCPortalNPC extends AbstractNPC { super.tick(); if (session != null) { Region region = RegionManager.forId(location.getRegionId()); - if (session.getTicks() % 35 - region.assemblePlayerList(0).size() == 0 && region.assembleNpcList(0).size() < 100) { + if ((session.getTicks() % 35 - region.assemblePlayerList(0).size()) == 0 && + region.assembleNpcList(0).size() < 100) { spawnNPCs(); } if (updateLifepoints && session.getTicks() % 10 == 0) { From d65eee6e8c86a71e53dbd61aa0c9dc26b0c912a3 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 06:12:05 +0000 Subject: [PATCH 70/94] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: GregF --- .../main/core/api/regionspec/contracts/FillChunkContract.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt b/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt index 3218207bb..0e9545b84 100644 --- a/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt +++ b/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt @@ -18,8 +18,7 @@ open class FillChunkContract(var chunk: RegionChunk? = null) : ChunkSpecContract for(x in 0 until 8) for(y in 0 until 8) if(replaceCondition.invoke(x,y,plane)) { - val chunk = getChunk(x,y,plane,dyn) - if (chunk==null) continue + val chunk = getChunk(x,y,plane,dyn) ?: continue dyn.replaceChunk( plane, x, From 0161a000b590970bd2e47b7d0fa6f2ac92c58964 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 06:46:43 +0000 Subject: [PATCH 71/94] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: GregF --- Server/src/main/core/game/world/map/RegionManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 8a78e0a99..425aab878 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -349,7 +349,7 @@ object RegionManager { * @return The scenery, or `null` if no object was found. */ @JvmStatic - fun getObject(z: Int, x: Int, y: Int, objectId: Int, type: Int): Scenery? { + fun getObject(z: Int, x: Int, y: Int, objectId: Int, type: Int = -1): Scenery? { val loc = Location(x, y, z) val region = forId(loc.regionId) Region.load(region) From a356fef354a79d52ebd5b7521279766def5ff640 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 08:51:03 +0200 Subject: [PATCH 72/94] greg review comments --- .../skill/construction/HouseManager.java | 1 - .../skill/construction/HousingStyle.java | 37 ++- .../skill/magic/lunar/LunarListeners.kt | 2 +- .../skill/magic/lunar/StatRestoreSpell.java | 12 +- .../pestcontrol/PestControlSession.java | 3 +- .../minigame/pestcontrol/SquireDialogue.java | 2 +- .../minigame/vinesweeper/Vinesweeper.kt | 14 +- .../draynor/dialogue/DraynorBankGuard.java | 6 +- .../draynor/handlers/DBRCutscenePlugin.kt | 49 ++-- .../tearsofguthix/TearsOfGuthixMinigame.kt | 2 +- .../regionspec/contracts/FillChunkContract.kt | 16 +- Server/src/main/core/game/bots/ScriptAPI.kt | 4 +- .../core/game/interaction/MovementPulse.java | 232 +++++++++--------- .../node/entity/combat/spell/CombatSpell.java | 6 +- .../game/node/entity/impl/WalkingQueue.java | 45 ++-- .../main/core/game/node/entity/npc/NPC.java | 1 - .../node/entity/npc/drop/NPCDropTables.java | 1 - .../player/info/login/LoginConfiguration.java | 2 - .../entity/player/link/PacketDispatch.java | 14 +- .../core/game/node/entity/skill/Skills.java | 52 +--- .../game/node/scenery/SceneryBuilder.java | 38 +-- .../command/sets/DevelopmentCommandSet.kt | 51 ---- 22 files changed, 242 insertions(+), 348 deletions(-) diff --git a/Server/src/main/content/global/skill/construction/HouseManager.java b/Server/src/main/content/global/skill/construction/HouseManager.java index 884ce5a7f..555ad027a 100644 --- a/Server/src/main/content/global/skill/construction/HouseManager.java +++ b/Server/src/main/content/global/skill/construction/HouseManager.java @@ -10,7 +10,6 @@ import core.game.world.map.*; import core.game.world.map.build.DynamicRegion; import core.game.world.map.zone.ZoneBorders; import core.game.world.map.zone.ZoneBuilder; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.tools.Log; import org.jetbrains.annotations.NotNull; diff --git a/Server/src/main/content/global/skill/construction/HousingStyle.java b/Server/src/main/content/global/skill/construction/HousingStyle.java index b9df17417..e2213e405 100644 --- a/Server/src/main/content/global/skill/construction/HousingStyle.java +++ b/Server/src/main/content/global/skill/construction/HousingStyle.java @@ -11,14 +11,13 @@ import java.util.Arrays; * */ public enum HousingStyle { - // open door ids are doorId + 1 - BASIC_WOOD (1, 5000, 7503, 0, 13100, 13101, 13098, 13098, Decoration.BASIC_WOOD_WINDOW), - BASIC_STONE (10, 5000, 7503, 1, 13094, 13096, 1902, 13090, Decoration.BASIC_STONE_WINDOW), - WHITEWASHED_STONE (20, 7500, 7503, 2, 13006, 13007, 1415, 1415, Decoration.WHITEWASHED_STONE_WINDOW), - FREMENNIK_STYLE_WOOD(30, 10000, 7503, 3, 13109, 13107, 13111, 13111, Decoration.FREMENNIK_WINDOW), - TROPICAL_WOOD (40, 15000, 7759, 0, 13016, 13015, 13011, 13011, Decoration.TROPICAL_WOOD_WINDOW), - FANCY_STONE (50, 25000, 7759, 1, 13119, 13118, 13116, 13116, Decoration.FANCY_STONE_WINDOW); + BASIC_WOOD (1, 5000, 7503, 0, 13100, 13101, 13098, Decoration.BASIC_WOOD_WINDOW), + BASIC_STONE (10, 5000, 7503, 1, 13094, 13096, 1902, 13090, Decoration.BASIC_STONE_WINDOW), + WHITEWASHED_STONE (20, 7500, 7503, 2, 13006, 13007, 1415, Decoration.WHITEWASHED_STONE_WINDOW), + FREMENNIK_STYLE_WOOD(30, 10000, 7503, 3, 13109, 13107, 13111, Decoration.FREMENNIK_WINDOW), + TROPICAL_WOOD (40, 15000, 7759, 0, 13016, 13015, 13011, Decoration.TROPICAL_WOOD_WINDOW), + FANCY_STONE (50, 25000, 7759, 1, 13119, 13118, 13116, Decoration.FANCY_STONE_WINDOW); /** * Array of all Dungeon Wall IDs. @@ -107,6 +106,7 @@ public enum HousingStyle { * @param secondDoorId The second-door object id used in this style. * @param wallId The wall object id used in this style. * @param secondWallId The second-wall object id used in this style. + * @param window The window decoration used in this style. */ HousingStyle(int level, int cost, int regionId, int plane, int doorId, int secondDoorId, int wallId, int secondWallId, Decoration window) { this.levelRequirement = level; @@ -120,6 +120,29 @@ public enum HousingStyle { this.window = window; } + /** + * Constructs a new {@code HousingStyle} {@code Object} for housing styles that do not have a second wall id + * @param level The level required. + * @param cost The cost of the style. + * @param regionId The region id for this style. + * @param plane The plane for this style. + * @param doorId The door object id used in this style. + * @param secondDoorId The second-door object id used in this style. + * @param wallId The wall object id used in this style. + * @param window The window decoration used in this style. + */ + HousingStyle(int level, int cost, int regionId, int plane, int doorId, int secondDoorId, int wallId, Decoration window) { + this.levelRequirement = level; + this.cost = cost; + this.regionId = regionId; + this.plane = plane; + this.doorId = doorId; + this.secondDoorId = secondDoorId; + this.wallId = wallId; + this.secondWallId = wallId; + this.window = window; + } + /** * Gets the level. * @return the level diff --git a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt index 3bbfa2881..8695b07e4 100644 --- a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt +++ b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt @@ -819,7 +819,7 @@ class LunarListeners : SpellListener("lunar"), Commands { private fun sendGroupTeleport(player: Player, xp: Double, destName: String, loc: Location){ RegionManager.getLocalPlayers(player.location, 1).forEach { - if (it.name == player.name) return@forEach + if (it == player) return@forEach if (it.isTeleBlocked) return@forEach if (!it.isActive) return@forEach if (!it.settings.isAcceptAid) return@forEach diff --git a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java index dda2b5d6d..7915590ba 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java @@ -28,7 +28,7 @@ public class StatRestoreSpell extends MagicSpell { private static final Animation ANIMATION = new Animation(4413); private static final Graphics GRAPHICS = new Graphics(733, 130); - private static final Consumables[] acceptedPotions = new Consumables[] { Consumables.RESTORE, Consumables.SUPER_RESTO, Consumables.PRAYER, Consumables.ENERGY, Consumables.SUPER_ENERGY }; + private static final Consumables[] acceptedPotions = new Consumables[] { Consumables.RESTORE, Consumables.SUPER_RESTO, Consumables.PRAYER, Consumables.ENERGY, Consumables.SUPER_ENERGY }; public StatRestoreSpell() { super(SpellBook.LUNAR, 81, 84, null, null, null, new Item[] { new Item(Runes.ASTRAL_RUNE.getId(), 2), new Item(Runes.EARTH_RUNE.getId(), 10), new Item(Runes.WATER_RUNE.getId(), 10) }); @@ -69,7 +69,7 @@ public class StatRestoreSpell extends MagicSpell { if (!o.isActive() || o.getLocks().isInteractionLocked()) { continue; } - if (!o.getSettings().isAcceptAid() || (o instanceof AIPlayer)) { + if (!o.getSettings().isAcceptAid() && !(o instanceof AIPlayer)) { continue; } o.graphics(GRAPHICS); @@ -98,10 +98,10 @@ public class StatRestoreSpell extends MagicSpell { } private boolean isRestore(Potion p) { - for (int i = 0; i < acceptedPotions.length; i++) { - if (p == acceptedPotions[i].getConsumable()) - return true; - } + for (int i = 0; i < acceptedPotions.length; i++) { + if (p == acceptedPotions[i].getConsumable()) + return true; + } return false; } diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java index f29a8c314..4899d15c8 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java @@ -20,6 +20,7 @@ import static core.api.ContentAPIKt.*; * @author Emperor */ public final class PestControlSession { + private static STRANGE_PHANTOM_OBJECT_THAT_SHARES_A_TILE_WITH_A_BARRICADE = 25636; /** * The barricade object offsets. @@ -274,7 +275,7 @@ public final class PestControlSession { for (Scenery object : objectList) { for (Point point : OBJECT_OFFSETS) { if (object.getLocation().getLocalX() == point.getX() && object.getLocation().getLocalY() == point.getY()) { - if (object.getId() != 25636) { //strange phantom object that shares a tile with a barricade + if (object.getId() != STRANGE_PHANTOM_OBJECT_THAT_SHARES_A_TILE_WITH_A_BARRICADE) { barricades.add(object); } } diff --git a/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java b/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java index c1c2a11c7..c0e7ca1de 100644 --- a/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java +++ b/Server/src/main/content/minigame/pestcontrol/SquireDialogue.java @@ -46,7 +46,7 @@ public class SquireDialogue extends DialoguePlugin { interpreter.sendDialogues(3781, FacialExpression.HALF_GUILTY, "Congratulations! You managed to destroy all the portals!", "We've awarded you " + points + " Void Knight Commendation", "points. Please also accept these coins as a reward."); stage = 100; } else {// won and not awarded. - interpreter.sendDialogues(3781, FacialExpression.HALF_GUILTY, "Congratulations! You managed to destroy all the portals!", "However, you did not succeed in reaching the required", "amount of damage dealt we cannot grant you a reward."); + interpreter.sendDialogues(3781, FacialExpression.HALF_GUILTY, "Congratulations! You managed to destroy all the portals!", "However, you did not succeed in reaching the required", "amount of damage delt we cannot grant you a reward."); stage = 101; } return true; diff --git a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt index 0069671f4..94ed9dceb 100644 --- a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt +++ b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt @@ -372,7 +372,7 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { return scenery != null && SEED_LOCS.contains(scenery.location) } - fun resetChunkIfBarren(chunk: RegionChunk) { + private fun resetChunkIfBarren(chunk: RegionChunk) { val wipedHoles = ArrayList() for (x in 0 until 8) { for (y in 0 until 8) { @@ -392,10 +392,10 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { } } - fun countFieldState(chunk: RegionChunk, emptyHoleList: ArrayList, seedHoleList: ArrayList) { - for (x in 0 until 8) { - for (y in 0 until 8) { - for (i in 0 until 4) { + private fun countFieldState(chunk: RegionChunk, emptyHoleList: ArrayList, seedHoleList: ArrayList) { + for (x in 0 until RegionChunk.SIZE) { + for (y in 0 until RegionChunk.SIZE) { + for (i in 0 until RegionChunk.ARRAY_SIZE) { val obj = chunk.objects[x][y][i] ?: continue if (obj.id in HOLES) { if (obj.location in SEED_LOCS) { @@ -412,8 +412,8 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { fun populateSeeds() { // First, see if there are any chunks that have been completely wiped out. These need to be restored first (GL #2400). Region.load(VINESWEEPER_REGION) - for (cx in 0 until 8) { - for (cy in 0 until 8) { + for (cx in 0 until RegionChunk.SIZE) { + for (cy in 0 until RegionChunk.SIZE) { val chunk = VINESWEEPER_REGION.chunks[cx][cy][0] resetChunkIfBarren(chunk) } diff --git a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java index 4c485d7af..501f0f0dd 100644 --- a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java +++ b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java @@ -1,7 +1,6 @@ package content.region.misthalin.draynor.dialogue; import content.region.misthalin.draynor.handlers.DBRCutscene; -import core.game.activity.ActivityManager; import core.game.dialogue.DialoguePlugin; import core.game.dialogue.FacialExpression; import core.game.node.entity.npc.NPC; @@ -9,6 +8,8 @@ import core.game.node.entity.player.Player; import core.plugin.Initializable; import core.game.node.item.Item; +import static core.api.ContentAPIKt.getAttribute; + /** * Represents the dialogue plugin used for the draynor bank guard npc. * @author 'Vexia @@ -16,6 +17,7 @@ import core.game.node.item.Item; */ @Initializable public final class DraynorBankGuard extends DialoguePlugin { + private final static String HAS_SEEN_RECORDING = "draynor-recording"; /** * Represents the coins item needed to re-watch the recording. @@ -56,7 +58,7 @@ public final class DraynorBankGuard extends DialoguePlugin { public boolean handle(int interfaceId, int buttonId) { switch (stage) { case 0: - if (!player.getAttribute("draynor-recording", false)) { + if (!getAttribute(player, HAS_SEEN_RECORDING, false)) { interpreter.sendOptions("Select an option", "Can I deposit my stuff here?", "That wall doesn't look very good.", "Sorry, I don't want anything."); stage = 1; } else { diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt b/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt index ace7b3646..50a13f033 100644 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt @@ -1,5 +1,6 @@ package content.region.misthalin.draynor.handlers +import content.region.misthalin.draynor.dialogue.DraynorBankGuard import core.api.* import core.game.activity.Cutscene import core.game.component.Component @@ -29,6 +30,8 @@ import org.rs09.consts.NPCs class DBRCutscene(player: Player) : Cutscene(player) { companion object { + const val HAS_SEEN_RECORDING = "draynor-recording" + // Animations private val STEAL_ANIMATION = Animation(832) private val CAST_ANIMATION = Animation(1167) @@ -46,11 +49,15 @@ class DBRCutscene(player: Player) : Cutscene(player) { // Graphics private val TELEKINETIC_GRAPHIC = Graphics(142, 96) private val SHOCK_GRAPHIC = Graphics(432, 0, 0) + private val SHOCK_CAST = Graphics(433) private val TELE_OTHER_CAST = Graphics(343) private val TELE_OTHER_TARGET = Graphics(342) private val PURPLE_GRAPHIC = Graphics(301, 100) private val THUNDER_GRAPHIC = Graphics(76) + // Projectile ids + private const val SHOCK_PROJECTILE_ID = 434 + // Components private val CRACKED = Component(385) } @@ -93,19 +100,17 @@ class DBRCutscene(player: Player) : Cutscene(player) { ) } - private fun castShock(target: Entity) { - val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + private fun castShock(target: Entity, wiseOldMan: Entity) { wiseOldMan.animate(CAST_ANIMATION) - wiseOldMan.graphics(Graphics(433)) - val projectile = Projectile.create(wiseOldMan, target, 434) + wiseOldMan.graphics(SHOCK_CAST) + val projectile = Projectile.create(wiseOldMan, target, SHOCK_PROJECTILE_ID) projectile.send() } - private fun castShock(loc: Location) { - val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + private fun castShock(loc: Location, wiseOldMan: Entity) { wiseOldMan.animate(CAST_ANIMATION) - wiseOldMan.graphics(Graphics(433)) - val projectile = Projectile.create(wiseOldMan, null, 434, 30, 30, 41, 140, 0, 0) + wiseOldMan.graphics(SHOCK_CAST) + val projectile = Projectile.create(wiseOldMan, null, SHOCK_PROJECTILE_ID, 30, 30, 41, 140, 0, 0) projectile.endLocation = loc projectile.send() } @@ -119,12 +124,6 @@ class DBRCutscene(player: Player) : Cutscene(player) { SpellBookManager.SpellBook.MODERN.getSpell(19).cast(wiseOldMan, GroundItemManager.get(Item(Items.BLUE_PARTYHAT_2422).id, base.transform(20, 44, 0), player)) } - private fun castThunderShock() { - val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! - wiseOldMan.animate(THUNDER_ANIMATION) - wiseOldMan.graphics(PURPLE_GRAPHIC) - } - private fun die(npc: NPC) { npc.animator.reset() npc.animate(DEATH_ANIMATION) @@ -135,8 +134,7 @@ class DBRCutscene(player: Player) : Cutscene(player) { override fun runStage(stage: Int) { when (stage) { 0 -> { - player.lock() - player.locks.lockMovement(10000000) + lock(player, 1000) sendDialogue(player, "You close your eyes and watch the recording...") fadeToBlack() timedUpdate(3) @@ -220,7 +218,7 @@ class DBRCutscene(player: Player) : Cutscene(player) { sendChat(qutieDoll, "Huh?") qutieDoll.faceTemporary(wiseOldMan, 2) sendChat(wiseOldMan, "Please don't block my line of fire!") - castShock(purePker) + castShock(purePker, wiseOldMan) timedUpdate(1) } 16 -> { @@ -270,7 +268,8 @@ class DBRCutscene(player: Player) : Cutscene(player) { timedUpdate(3) } 24 -> { - castShock(base.transform(16, 46, 0)) + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + castShock(base.transform(16, 46, 0), wiseOldMan) timedUpdate(2) } 25 -> { @@ -381,7 +380,7 @@ class DBRCutscene(player: Player) : Cutscene(player) { 38 -> { val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! wiseOldMan.faceTemporary(getNPC(NPCs.ELFINLOCKS_2578)!!, 1) - castShock(getNPC(NPCs.ELFINLOCKS_2578)!!) + castShock(getNPC(NPCs.ELFINLOCKS_2578)!!, wiseOldMan) timedUpdate(2) } 39 -> { @@ -400,7 +399,8 @@ class DBRCutscene(player: Player) : Cutscene(player) { timedUpdate(2) } 42 -> { - castShock(getNPC(NPCs.SP34KR_1337_2577)!!) + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + castShock(getNPC(NPCs.SP34KR_1337_2577)!!, wiseOldMan) move(getNPC(NPCs.QUTIEDOLL_2576)!!, 21, 44) timedUpdate(2) } @@ -430,7 +430,8 @@ class DBRCutscene(player: Player) : Cutscene(player) { timedUpdate(1) } 48 -> { - castShock(getNPC(NPCs.QUTIEDOLL_2576)!!) + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + castShock(getNPC(NPCs.QUTIEDOLL_2576)!!, wiseOldMan) timedUpdate(3) } 49 -> { @@ -501,7 +502,9 @@ class DBRCutscene(player: Player) : Cutscene(player) { timedUpdate(2) } 61 -> { - castThunderShock() + val wiseOldMan = getNPC(NPCs.WISE_OLD_MAN_2566)!! + wiseOldMan.animate(THUNDER_ANIMATION) + wiseOldMan.graphics(PURPLE_GRAPHIC) timedUpdate(3) } 62 -> { @@ -547,7 +550,7 @@ class DBRCutscene(player: Player) : Cutscene(player) { } 69 -> end { player.isInvisible = false - setAttribute(player, "/save:draynor-recording", true) + setAttribute(player, "/save:$HAS_SEEN_RECORDING", true) sendDialogue(player, "End of recording.") } } diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt index da71522ce..b097ee20a 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt @@ -384,4 +384,4 @@ class TearsOfGuthixGlobalTick : TickListener { } } } -} \ No newline at end of file +} diff --git a/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt b/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt index 0e9545b84..aefe80795 100644 --- a/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt +++ b/Server/src/main/core/api/regionspec/contracts/FillChunkContract.kt @@ -14,18 +14,12 @@ open class FillChunkContract(var chunk: RegionChunk? = null) : ChunkSpecContract var chunkDelegate: (Int, Int, Int, Region) -> RegionChunk? = {_,_,_,_ -> chunk} override fun populateChunks(dyn: DynamicRegion) { - for(plane in planes) { - for(x in 0 until 8) - for(y in 0 until 8) - if(replaceCondition.invoke(x,y,plane)) { + for (plane in planes) { + for (x in 0 until 8) + for (y in 0 until 8) + if (replaceCondition.invoke(x,y,plane)) { val chunk = getChunk(x,y,plane,dyn) ?: continue - dyn.replaceChunk( - plane, - x, - y, - chunk, - sourceRegion - ) + dyn.replaceChunk(plane, x, y, chunk, sourceRegion) afterSetting(chunk, x, y, plane, dyn) } } diff --git a/Server/src/main/core/game/bots/ScriptAPI.kt b/Server/src/main/core/game/bots/ScriptAPI.kt index 14ed085ac..b2e94e8a7 100644 --- a/Server/src/main/core/game/bots/ScriptAPI.kt +++ b/Server/src/main/core/game/bots/ScriptAPI.kt @@ -141,7 +141,7 @@ class ScriptAPI(private val bot: Player) { /** * Gets the nearest node with matching id. * @param id the id to look for - * @param object whether the node we are looking for is an object. + * @param isObject whether the node we are looking for is an object. * @return the closest node with matching id or null. * @author Ceikry */ @@ -166,7 +166,7 @@ class ScriptAPI(private val bot: Player) { /** * Gets the nearest node with a matching name. * @param name the name to look for. - * @param object whether the node we are looking for is an object. + * @param isObject whether the node we are looking for is an object. * @return the nearest matching node or null. * @author Ceikry */ diff --git a/Server/src/main/core/game/interaction/MovementPulse.java b/Server/src/main/core/game/interaction/MovementPulse.java index 9d7688306..372ed3b12 100644 --- a/Server/src/main/core/game/interaction/MovementPulse.java +++ b/Server/src/main/core/game/interaction/MovementPulse.java @@ -7,6 +7,7 @@ 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.task.Pulse; +import core.game.world.GameWorld; import core.game.world.map.Direction; import core.game.world.map.Location; import core.game.world.map.Point; @@ -18,8 +19,11 @@ import core.net.packet.context.PlayerContext; import core.net.packet.out.ClearMinimapFlag; import kotlin.jvm.functions.Function2; import kotlin.Pair; +import core.tools.SystemLogger; import core.api.utils.Vector; +import content.region.wilderness.handlers.revenants.RevenantNPC; + import static core.api.ContentAPIKt.*; import java.util.Deque; @@ -217,12 +221,12 @@ public abstract class MovementPulse extends Pulse { clearInferiorScripts(); mover.face(null); - if (canInteractWithoutMoving()) { - if (interactImmediately()) { - stop(); - return true; - } - } + if (canInteractWithoutMoving()) { + if (interactImmediately()) { + stop(); + return true; + } + } updatePath(); if (tryInteract()) { @@ -235,33 +239,28 @@ public abstract class MovementPulse extends Pulse { private boolean tryInteract() { Location ml = mover.getLocation(); - if (ml == null) { - return false; - } // Allow being within 1 square of moving entities to interact with them. - int radius = destination instanceof Entity && ((Entity) destination).getWalkingQueue().hasPath() ? 1 : 0; + int radius = destination instanceof Entity && ((Entity)destination).getWalkingQueue().hasPath() ? 1 : 0; if (interactLocation == null) return false; - boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; - // Check if already in a valid interaction position for entity destinations - boolean canInteractFromCurrentPosition = false; - if (!atInteractLocation && destination instanceof Entity) { - Entity target = (Entity) destination; - Location dl = target.getLocation(); - if (dl == null) { - return false; - } - boolean onSameTile = ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ(); - if (!onSameTile) { - canInteractFromCurrentPosition = Pathfinder.canInteract( - ml.getX(), ml.getY(), mover.size(), - dl.getX(), dl.getY(), target.size(), target.size(), - 0, // walkFlag - "can interact from any unblocked direction" - ml.getZ(), - RegionManager::getClippingFlag); - } - } - if (atInteractLocation || canInteractFromCurrentPosition) { + boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; + // Check if already in a valid interaction position for entity destinations + boolean canInteractFromCurrentPosition = false; + if (!atInteractLocation && destination instanceof Entity) { + Entity target = (Entity) destination; + Location dl = target.getLocation(); + boolean onSameTile = ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ(); + if (!onSameTile) { + canInteractFromCurrentPosition = Pathfinder.canInteract( + ml.getX(), ml.getY(), mover.size(), + dl.getX(), dl.getY(), target.size(), target.size(), + 0, // walkFlag - "can interact from any unblocked direction" + ml.getZ(), + RegionManager::getClippingFlag + ); + } + } + if (atInteractLocation || canInteractFromCurrentPosition) { try { if (near || pulse()) { if (mover instanceof Player) { @@ -273,7 +272,7 @@ public abstract class MovementPulse extends Pulse { stop(); return true; } - } catch (Exception e) { + } catch (Exception e){ e.printStackTrace(); stop(); } @@ -288,35 +287,34 @@ public abstract class MovementPulse extends Pulse { * @return true if the mover can interact without moving */ private boolean canInteractWithoutMoving() { - if (!(destination instanceof Entity)) { - return false; - } - Entity target = (Entity) destination; - Location ml = mover.getLocation(); - Location dl = target.getLocation(); - if (ml == null || dl == null) { - return false; - } - if (ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ()) { - return false; - } - if (isInsideEntity(ml)) { - return false; - } - if (target.getWalkingQueue().hasPath()) { // For moving entities, allow interaction from 1 tile away - int distance = Math.max( - Math.abs(ml.getX() - dl.getX()), - Math.abs(ml.getY() - dl.getY())); - if (distance <= target.size()) { - return true; - } - } - return Pathfinder.canInteract( - ml.getX(), ml.getY(), mover.size(), - dl.getX(), dl.getY(), target.size(), target.size(), - 0, // walkFlag - "can interact from any unblocked direction" - ml.getZ(), - RegionManager::getClippingFlag); + if (!(destination instanceof Entity)) { + return false; + } + Entity target = (Entity) destination; + Location ml = mover.getLocation(); + Location dl = target.getLocation(); + if (ml.getX() == dl.getX() && ml.getY() == dl.getY() && ml.getZ() == dl.getZ()) { + return false; + } + if (isInsideEntity(mover.getLocation())) { + return false; + } + if (target.getWalkingQueue().hasPath()) { // For moving entities, allow interaction from 1 tile away + int distance = Math.max( + Math.abs(ml.getX() - dl.getX()), + Math.abs(ml.getY() - dl.getY()) + ); + if (distance <= target.size()) { + return true; + } + } + return Pathfinder.canInteract( + ml.getX(), ml.getY(), mover.size(), + dl.getX(), dl.getY(), target.size(), target.size(), + 0, // walkFlag - "can interact from any unblocked direction" + ml.getZ(), + RegionManager::getClippingFlag + ); } /** @@ -326,20 +324,20 @@ public abstract class MovementPulse extends Pulse { * @return true if interaction was successful and pulse should stop */ private boolean interactImmediately() { - if (destination instanceof Entity) { - mover.face((Entity) destination); - } - try { - if (pulse()) { - if (mover instanceof Player) { - PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); - } - return true; - } - } catch (Exception e) { - e.printStackTrace(); - } - return false; + if (destination instanceof Entity) { + mover.face((Entity) destination); + } + try { + if (pulse()) { + if (mover instanceof Player) { + PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); + } + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; } private boolean validate() { @@ -466,49 +464,49 @@ public abstract class MovementPulse extends Pulse { return canMove; } - private Location checkForEntityPathInterrupt(Location loc) { - Location ml = mover.getLocation(); - Location dl = destination.getLocation(); - // Lead the target if they're walking/running, unless they're already within interaction range - if (loc != null && destination instanceof Entity) { - WalkingQueue wq = ((Entity) destination).getWalkingQueue(); - if (wq.hasPath()) { - Point[] points = wq.getQueue().toArray(new Point[0]); - if (points.length > 0) { - Point p = points[0]; - Point predictiveIntersection = null; - for (int i = 0; i < points.length; i++) { - Location closestBorder = getClosestBorderToPoint(points[i], loc.getZ()); + private Location checkForEntityPathInterrupt(Location loc) { + Location ml = mover.getLocation(); + Location dl = destination.getLocation(); + // Lead the target if they're walking/running, unless they're already within interaction range + if (loc != null && destination instanceof Entity) { + WalkingQueue wq = ((Entity) destination).getWalkingQueue(); + if (wq.hasPath()) { + Point[] points = wq.getQueue().toArray(new Point[0]); + if (points.length > 0) { + Point p = points[0]; + Point predictiveIntersection = null; + for (int i = 0; i < points.length; i++) { + Location closestBorder = getClosestBorderToPoint(points[i], loc.getZ()); - if (!RegionManager.isTeleportPermitted(closestBorder)) { // A nasty hack to discard invalid intersection points - continue; - } - int moverDist = Math.max(Math.abs(ml.getX() - closestBorder.getX()), Math.abs(ml.getY() - closestBorder.getY())); - float movementRatio = moverDist / (float) ((i + 1) / (mover.getWalkingQueue().isRunning() ? 2 : 1)); - if (predictiveIntersection == null && movementRatio <= 1.0) { //try to predict an intersection point on the path if possible - predictiveIntersection = points[i]; - break; - } - // Otherwise, we target the farthest point along target's planned movement that's within 1 tick's running, - // this ensures the player will run to catch up to the target if able. - if (moverDist <= 2) { - p = points[i]; - } - } - if (predictiveIntersection != null) - p = predictiveIntersection; + if (!RegionManager.isTeleportPermitted(closestBorder)) { // A nasty hack to discard invalid intersection points + continue; + } + int moverDist = Math.max(Math.abs(ml.getX() - closestBorder.getX()), Math.abs(ml.getY() - closestBorder.getY())); + float movementRatio = moverDist / (float) ((i + 1) / (mover.getWalkingQueue().isRunning() ? 2 : 1)); + if (predictiveIntersection == null && movementRatio <= 1.0) { //try to predict an intersection point on the path if possible + predictiveIntersection = points[i]; + break; + } + // Otherwise, we target the farthest point along target's planned movement that's within 1 tick's running, + // this ensures the player will run to catch up to the target if able. + if (moverDist <= 2) { + p = points[i]; + } + } + if (predictiveIntersection != null) + p = predictiveIntersection; - Location endLoc = getClosestBorderToPoint(p, loc.getZ()); + Location endLoc = getClosestBorderToPoint(p, loc.getZ()); - if (!RegionManager.isTeleportPermitted(endLoc)) { // Basically a prayer - return loc; - } - return endLoc; - } - } - } - return loc; - } + if (!RegionManager.isTeleportPermitted(endLoc)) { // Basically a prayer + return loc; + } + return endLoc; + } + } + } + return loc; + } private Location getClosestBorderToPoint (Point p, int plane) { Vector pathDiff = Vector.betweenLocs (destination.getLocation(), Location.create(p.getX(), p.getY(), plane)); @@ -597,9 +595,6 @@ public abstract class MovementPulse extends Pulse { * @return {@code True} if so. */ private boolean isInsideEntity(Location l) { - if (l == null) { - return false; - } if (!(destination instanceof Entity)) { return false; } @@ -607,9 +602,6 @@ public abstract class MovementPulse extends Pulse { return false; } Location loc = destination.getLocation(); - if (loc == null) { - return false; - } int size = destination.size(); return Pathfinder.isStandingIn(l.getX(), l.getY(), mover.size(), mover.size(), loc.getX(), loc.getY(), size, size); } diff --git a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java index 09009b142..519621763 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java @@ -112,11 +112,11 @@ public abstract class CombatSpell extends MagicSpell { * Gets a list of valid targets for a multihitting spell. * @param entity The caster of the spell. * @param target The primary victim. - * @param max The maximum number of extra victims that may be hit. + * @param max The maximum number of extra victims that may be hit. * @return The list of targets (the primary target is always at index 0). */ public List getMultihitTargets(Entity entity, Entity target, int max) { - List victims = new ArrayList<>(20); + List victims = new ArrayList<>(max+1); victims.add(target); List surrounding = RegionManager.getLocalEntities(target.getLocation(), 1); @@ -249,4 +249,4 @@ public abstract class CombatSpell extends MagicSpell { return SPLASH_GRAPHIC; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java index 5a68c1f6c..ba0c2ded4 100644 --- a/Server/src/main/core/game/node/entity/impl/WalkingQueue.java +++ b/Server/src/main/core/game/node/entity/impl/WalkingQueue.java @@ -20,7 +20,6 @@ import static core.api.ContentAPIKt.*; * @author Emperor */ public final class WalkingQueue { - /** * The walking queue. */ @@ -57,7 +56,7 @@ public final class WalkingQueue { */ private Location footPrint; - public ArrayList routeItems = new ArrayList(); + public ArrayList routeItems = new ArrayList(); /** * Constructs a new {@code WalkingQueue} {@code Object}. @@ -85,20 +84,21 @@ public final class WalkingQueue { if (isPlayer && updateRegion(prevLocation, entity.getLocation(), true)) { return; } - if (hasTimerActive(entity, "frozen")) - return; + if (hasTimerActive(entity, "frozen")) { + return; + } Point point = walkingQueue.poll(); - boolean drawPath = entity.getAttribute("routedraw", false); + boolean drawPath = entity.getAttribute("routedraw", false); if (point == null) { updateRunEnergy(false); - if (isPlayer && drawPath) { - for (GroundItem item : routeItems) { - if (item != null) { - RegionManager.getRegionChunk(item.getLocation()).remove(item); - } - } - routeItems.clear(); - } + if (isPlayer && drawPath) { + for (GroundItem item : routeItems) { + if (item != null) { + RegionManager.getRegionChunk(item.getLocation()).remove(item); + } + } + routeItems.clear(); + } return; } if (isPlayer && ((Player) entity).getSettings().getRunEnergy() < 1.0) { @@ -308,13 +308,13 @@ public final class WalkingQueue { if (point == null) { return; } - boolean drawRoute = entity.getAttribute("routedraw", false); - if (drawRoute && entity instanceof Player) { - Player p = (Player) entity; - GroundItem item = new GroundItem(new Item(13444), Location.create(x, y, p.getLocation().getZ()), p); - routeItems.add (item); - RegionManager.getRegionChunk(item.getLocation()).add(item); - } + boolean drawRoute = entity.getAttribute("routedraw", false); + if (drawRoute && entity instanceof Player) { + Player p = (Player) entity; + GroundItem item = new GroundItem(new Item(13444), Location.create(x, y, p.getLocation().getZ()), p); + routeItems.add (item); + RegionManager.getRegionChunk(item.getLocation()).add(item); + } int diffX = x - point.getX(), diffY = y - point.getY(); int max = Math.max(Math.abs(diffX), Math.abs(diffY)); for (int i = 0; i < max; i++) { @@ -351,9 +351,7 @@ public final class WalkingQueue { /** * Checks if the entity is running. - * @return {@code True} if a ctrl + click reward was performed,
the - * player has the run option enabled or the NPC is a familiar,

- * {@code false} if not. + * @return {@code True} if a ctrl + click reward was performed, the player has the run option enabled or the NPC is a familiar, {@code False} if not. */ public boolean isRunningBoth() { if (isRunDisabled()) return false; @@ -392,7 +390,6 @@ public final class WalkingQueue { */ public void reset(boolean running) { Location loc = entity.getLocation(); - if (loc == null) { log(this.getClass(), Log.ERR, "The entity location provided was null." diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index 07acec56f..97c1fef8b 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -1,6 +1,5 @@ package core.game.node.entity.npc; -import core.ServerConstants; import core.game.event.NPCKillEvent; import core.cache.def.impl.NPCDefinition; import core.game.dialogue.DialoguePlugin; diff --git a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java index ebd086000..951f1d503 100644 --- a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java +++ b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java @@ -25,7 +25,6 @@ import core.game.world.repository.Repository; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * Holds and handles the NPC drop tables. diff --git a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java index 5133f4a58..5e6a193ee 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java +++ b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java @@ -1,11 +1,9 @@ package core.game.node.entity.player.info.login; -import core.Server; import core.game.component.Component; import core.game.node.entity.player.Player; import core.game.node.entity.player.link.emote.Emotes; import core.game.node.item.Item; -import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.net.packet.PacketRepository; import core.net.packet.context.InterfaceContext; diff --git a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java index 16e12e682..de6bb8233 100644 --- a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java +++ b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java @@ -50,9 +50,9 @@ public final class PacketDispatch { PacketRepository.send(Config.class, new ConfigContext(player, index, value)); } - public void sendVarcUpdate(short index, int value) { - PacketRepository.send(VarcUpdate.class, new VarcUpdateContext(player, index, value)); - } + public void sendVarcUpdate(short index, int value) { + PacketRepository.send(VarcUpdate.class, new VarcUpdateContext(player, index, value)); + } /** * Send a game message. @@ -312,7 +312,7 @@ public final class PacketDispatch { * @param id The animation id. */ public void sendAnimation(int id) { - player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id)); + player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id)); } /** @@ -321,7 +321,7 @@ public final class PacketDispatch { * @param delay The animation delay. */ public void sendAnimation(int id, int delay) { - player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id, delay)); + player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id, delay)); } /** @@ -329,7 +329,7 @@ public final class PacketDispatch { * @param id The graphic id. */ public void sendGraphic(int id) { - player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id)); + player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id)); } /** @@ -395,7 +395,7 @@ public final class PacketDispatch { * @param height The graphic height. */ public void sendGraphic(int id, int height) { - player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id, height)); + player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id, height)); } public void sendVarClient(int id, int value, boolean cs2) { PacketRepository.send(Config.class, new ConfigContext(player, id, value, cs2)); diff --git a/Server/src/main/core/game/node/entity/skill/Skills.java b/Server/src/main/core/game/node/entity/skill/Skills.java index 5b8b30b5c..0985d1671 100644 --- a/Server/src/main/core/game/node/entity/skill/Skills.java +++ b/Server/src/main/core/game/node/entity/skill/Skills.java @@ -41,11 +41,6 @@ public final class Skills { */ public double experienceMultiplier = 1.0; - /** - * The maximum experience multiplier. - */ - public static final double MAX_EXPERIENCE_MOD = 60.0; - /** * Represents an array of skill names. */ @@ -252,9 +247,9 @@ public final class Skills { staticLevels[slot] = newLevel; if (entity instanceof Player) { - player.updateAppearance(); + player.updateAppearance(); LevelUp.levelup(player, slot, amount); - updateCombatLevel(); + updateCombatLevel(); } } if (entity instanceof Player) { @@ -288,46 +283,6 @@ public final class Skills { //Keywords for people ctrl + Fing the project //xprate xp rate xp multiplier skilling rate return experienceMultiplier; - /*if (!(entity instanceof Player)) { - return 1.0; - } - double mod = multiplyer ? (EXPERIENCE_MULTIPLIER) : 1; - Player p = (Player) entity; - if (p.getIronmanManager().getMode() == IronmanMode.ULTIMATE) { - mod /= 4; - } else if (p.getIronmanManager().getMode() == IronmanMode.STANDARD) { - mod /= 2; - } - //A boost for combat skills that are under level 65. - if(entity instanceof Player && !this.hasLevel(slot, 65) && isCombat(slot)){ - mod *= 1.5; - } - //Grand Exchange region XP boost. - if(entity.getLocation().getRegion().getRegionId() == 12598){ - mod += 1.5; - } - // Pest control, XP halved during the game - if (entity.getLocation().getRegion().getRegionId() == 10536) { - mod *= .5; - } - if (SystemManager.getSystemConfig().isDoubleExp()) { - mod *= 2; - } - if (HolidayEvent.getCurrent() != null) { - HolidayEvent.getCurrent().addExperience(p, slot, experience); - } - p.getAntiMacroHandler().registerExperience(slot, experience); - if (TutorialSession.getExtension(p).getStage() < TutorialSession.MAX_STAGE) { - mod = 1.0; - } else { - if (playerMod && p.getExperienceMod() != 0.0) { - mod *= p.getExperienceMod(); - } - } - if (mod > MAX_EXPERIENCE_MOD ) { - return MAX_EXPERIENCE_MOD; - } - return mod;*/ } /** @@ -721,9 +676,6 @@ public final class Skills { if (prayerPoints < 0) { prayerPoints = 0; } - // if (prayerPoints > staticLevels[PRAYER]) { - // prayerPoints = staticLevels[PRAYER]; - // } if (entity instanceof Player) { PacketRepository.send(SkillLevel.class, new SkillContext((Player) entity, PRAYER)); } diff --git a/Server/src/main/core/game/node/scenery/SceneryBuilder.java b/Server/src/main/core/game/node/scenery/SceneryBuilder.java index 304403930..db45f8942 100644 --- a/Server/src/main/core/game/node/scenery/SceneryBuilder.java +++ b/Server/src/main/core/game/node/scenery/SceneryBuilder.java @@ -15,15 +15,12 @@ import static core.api.ContentAPIKt.log; /** * An aiding class for object constructing/removing. - * * @author Emperor */ public final class SceneryBuilder { - /** * Replaces a scenery. - * - * @param remove The object to remove. + * @param remove The object to remove. * @param construct The object to add. * @return {@code True} if successful. */ @@ -34,9 +31,9 @@ public final class SceneryBuilder { /** * Replaces a scenery. * - * @param remove The object to remove. + * @param remove The object to remove. * @param construct The object to add. - * @param clip If clipping should be adjusted. + * @param clip If clipping should be adjusted. * @return {@code True} if successful. */ public static boolean replace(Scenery remove, Scenery construct, boolean clip, boolean permanent) { @@ -71,9 +68,8 @@ public final class SceneryBuilder { /** * Replaces the object client sided alone. - * - * @param remove The object to remove. - * @param construct The object to replace with. + * @param remove The object to remove. + * @param construct The object to replace with. * @param restoreTicks The restoration ticks. * @return {@code True} if successful. */ @@ -93,9 +89,8 @@ public final class SceneryBuilder { /** * Replaces a scenery temporarily. - * - * @param remove The object to remove. - * @param construct The object to add. + * @param remove The object to remove. + * @param construct The object to add. * @param restoreTicks The amount of ticks before the object gets restored. * @return {@code True} if successful. */ @@ -105,9 +100,8 @@ public final class SceneryBuilder { /** * Replaces a scenery temporarily. - * - * @param remove The object to remove. - * @param construct The object to add. + * @param remove The object to remove. + * @param construct The object to add. * @param restoreTicks The amount of ticks before the object gets restored. * @return {@code True} if successful. */ @@ -151,7 +145,6 @@ public final class SceneryBuilder { /** * Adds a scenery. - * * @param object The object to add. * @return {@code True} if successful. */ @@ -161,10 +154,8 @@ public final class SceneryBuilder { /** * Adds a scenery. - * * @param object The object to add. - * @param ticks The amount of ticks this object should last for (-1 for - * permanent). + * @param ticks The amount of ticks this object should last for (-1 for permanent). * @return {@code True} if successful. */ public static Constructed add(Scenery object, int ticks, final GroundItem... items) { @@ -191,7 +182,6 @@ public final class SceneryBuilder { /** * Removes a scenery. - * * @param object The object to remove. * @return {@code True} if successful. */ @@ -210,21 +200,18 @@ public final class SceneryBuilder { /** * Removes a scenery. - * - * @param object the object. + * @param object the object. * @param respawnTicks the respawn ticks. * @return {@code True}if removed. */ public static boolean remove(final Scenery object, int respawnTicks) { if (remove(object)) { GameWorld.getPulser().submit(new Pulse(respawnTicks) { - @Override public boolean pulse() { add(object); return true; } - }); return true; } @@ -233,8 +220,7 @@ public final class SceneryBuilder { /** * Updates the scenery on all the player's screen. - * - * @param objects The scenerys. + * @param objects The sceneries. */ public static void update(Scenery... objects) { for (Scenery o : objects) { diff --git a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt index dc2fb3159..43a092aab 100644 --- a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt @@ -156,10 +156,6 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { sendMessage(player, "Job cleared successfully.") } - define("region", Privilege.STANDARD, "", "Prints your current Region ID.") {player, args -> - sendMessage(player, "Region ID: ${player.location.regionId}") - } - define("spellbook", Privilege.ADMIN, "::spellbook book ID (0 = MODERN, 1 = ANCIENTS, 2 = LUNARS)", "Swaps your spellbook to the given book ID."){player, args -> if(args.size < 2){ reject(player,"Usage: ::spellbook [int]. 0 = MODERN, 1 = ANCIENTS, 2 = LUNARS") @@ -377,28 +373,6 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { player.dialogueInterpreter.sendDialogues(player, id, "Expression ID: $id") } - define("tileinfo", Privilege.ADMIN, "::tileinfo", "Prints out your current tile's clipping flags and entities on it.") { player, args -> - if (args.size != 1) reject(player, "::tileinfo doesn't take arguments.") - sendMessage(player, "Location: ${player.location}") - sendMessage(player, "Clipping: ${RegionManager.getClippingFlag(player.location, false)}") - sendMessage(player, "Projectile: ${RegionManager.getClippingFlag(player.location, true)}") - sendMessage(player, "${player.location.chunk.players.size} players and ${player.location.chunk.npcs.size} npcs on this chunk.") - sendMessage(player, "Entities on this tile:") - for (p in RegionManager.getLocalPlayers(player.location, 0)) { - sendMessage(player, " player ${player.username}") - } - for (npc in RegionManager.getLocalNPCs(player.location, 0)) { - sendMessage(player, " npc ${npc.name}") - } - sendMessage(player, "Entities within render distance:") - for (p in RegionManager.getLocalPlayers(player.location)) { - sendMessage(player, " player ${player.username} at ${player.location}") - } - for (npc in RegionManager.getLocalNPCs(player.location)) { - sendMessage(player, " npc ${npc.name} at ${npc.location}}") - } - } - define("timers", Privilege.ADMIN, "::timers", "Print out timers") { player, args -> player.sendMessage("Active timers:") for(timer in player.timers.activeTimers) { @@ -483,31 +457,6 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { target.skills.addExperience(skill, xp!!) } - define("renewpenguins", Privilege.ADMIN, "", "Generates a fresh set of weekly penguins") { player, _ -> - val spawnedOrdinals = (PenguinHNSEvent.getStoreFile()["spawned-penguins"] as JSONArray).map { it.toString().toInt() } - val penguinNPCs = arrayListOf(NPCs.BARREL_8104, NPCs.BUSH_8105,NPCs.CACTUS_8107,NPCs.CRATE_8108,NPCs.ROCK_8109,NPCs.TOADSTOOL_8110) - - spawnedOrdinals.forEach { - val peng = Penguin.values()[it] - val nearNPCs = getLocalEntities(peng.location,1) - nearNPCs.forEach { npc -> - if (npc.id in penguinNPCs) { - poofClear(npc as NPC) - } - } - } - penguins = spawner.spawnPenguins(10) - PenguinHNSEvent.getStoreFile()["spawned-penguins"] = penguins.toJSONArray() - tagMapping.clear() - for (p in penguins) { - tagMapping.put(p, JSONArray()) - val pengCoord = Penguin.values()[p].location - player.debug("Penguin spawned at:$pengCoord") - } - updateStoreFile() - player.debug("Penguin positions have been renewed") - } - define("spawnpenguin",Privilege.ADMIN,"::spawnPenguin Ordinal","Adds a new Penguin spawn to this weeks list based on the ordinal provided 0-64"){player,args-> if (args.size!=2) reject (player,"Usage: ::spawnpenguin Ordinal") val ordinal = args[1].toIntOrNull() From 917827ce8ded1769c1ba9f245a37b9423be06dd0 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 08:54:09 +0200 Subject: [PATCH 73/94] remove default argument for jvmstatic method --- Server/src/main/core/game/world/map/RegionManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 425aab878..8a78e0a99 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -349,7 +349,7 @@ object RegionManager { * @return The scenery, or `null` if no object was found. */ @JvmStatic - fun getObject(z: Int, x: Int, y: Int, objectId: Int, type: Int = -1): Scenery? { + fun getObject(z: Int, x: Int, y: Int, objectId: Int, type: Int): Scenery? { val loc = Location(x, y, z) val region = forId(loc.regionId) Region.load(region) From eb3c64d61a21111687393ba9885c934dfc7d72c8 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 09:04:19 +0200 Subject: [PATCH 74/94] multihit wip --- .../skill/magic/ancient/BloodSpells.java | 2 +- .../global/skill/magic/ancient/IceSpells.java | 2 +- .../skill/magic/ancient/MiasmicSpells.java | 2 +- .../skill/magic/ancient/ShadowSpells.java | 2 +- .../skill/magic/ancient/SmokeSpells.java | 2 +- .../pestcontrol/PestControlSession.java | 4 +-- .../node/entity/combat/spell/CombatSpell.java | 29 +++++++++---------- 7 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java index 2cd31111c..453ccabb4 100644 --- a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java @@ -118,7 +118,7 @@ public final class BloodSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target, 9); + List list = getMultihitTargets(entity, target); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java index 4b0e29ff4..30941fec7 100644 --- a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java @@ -143,7 +143,7 @@ public final class IceSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target, 9); + List list = getMultihitTargets(entity, target); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java index 5ead4131e..927c59e29 100644 --- a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java @@ -157,7 +157,7 @@ public final class MiasmicSpells extends CombatSpell { || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target, 9); + List list = getMultihitTargets(entity, target); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java index 22ca33fa3..c5f247ab7 100644 --- a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java @@ -115,7 +115,7 @@ public final class ShadowSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target, 9); + List list = getMultihitTargets(entity, target); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java index 23ddf938f..610d9611e 100644 --- a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java @@ -123,7 +123,7 @@ public final class SmokeSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target, 9); + List list = getMultihitTargets(entity, target); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java index 4899d15c8..73b84e202 100644 --- a/Server/src/main/content/minigame/pestcontrol/PestControlSession.java +++ b/Server/src/main/content/minigame/pestcontrol/PestControlSession.java @@ -20,7 +20,7 @@ import static core.api.ContentAPIKt.*; * @author Emperor */ public final class PestControlSession { - private static STRANGE_PHANTOM_OBJECT_THAT_SHARES_A_TILE_WITH_A_BARRICADE = 25636; + private static int STRANGE_PHANTOM_OBJECT_THAT_SHARES_A_TILE_WITH_A_BARRICADE = 25636; /** * The barricade object offsets. @@ -31,7 +31,7 @@ public final class PestControlSession { * The object ids of non-attackable barricades/gates. */ public static final int[] INVALID_OBJECT_IDS = {14230, 14231, 14232, // Barricades - 14245, 14246, 14247, 14248, // Gates + 14245, 14246, 14247, 14248 // Gates }; /** diff --git a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java index 519621763..33c564c12 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java @@ -111,17 +111,19 @@ public abstract class CombatSpell extends MagicSpell { /** * Gets a list of valid targets for a multihitting spell. * @param entity The caster of the spell. - * @param target The primary victim. - * @param max The maximum number of extra victims that may be hit. + * @param victim The primary victim. * @return The list of targets (the primary target is always at index 0). */ - public List getMultihitTargets(Entity entity, Entity target, int max) { - List victims = new ArrayList<>(max+1); - victims.add(target); - - List surrounding = RegionManager.getLocalEntities(target.getLocation(), 1); - for (Entity e : surrounding) { - if (e == target || e == entity) { + public List getMultihitTargets(Entity entity, Entity victim) { + // https://oldschool.runescape.wiki/w/Chinchompa - shit source but it's better than what was here before + List targetCandidates; + if (victim instanceof Player) { + targetCandidates = RegionManager.getSurroundingPlayers(victim, 9); + } else { + targetCandidates = RegionManager.getSurroundingNPCs(victim, 11); + } + for (Entity e : targetCandidates) { + if (e == victim || e == entity) { continue; } if (CombatStyle.MAGIC.getSwingHandler().canSwing(entity, e) == InteractionType.NO_INTERACT || !e.isAttackable(entity, CombatStyle.MAGIC, false)) { @@ -130,16 +132,13 @@ public abstract class CombatSpell extends MagicSpell { if (e instanceof Familiar) { Player owner = ((Familiar) e).getOwner(); if (owner != entity && WildernessZone.getInstance().continueAttack(entity, owner, CombatStyle.MAGIC, true)) { - victims.add(e); + targetCandidates.add(e); } } else { - victims.add(e); - } - if (--max < 1) { - break; + targetCandidates.add(e); } } - return victims; + return targetCandidates; } /** From 4716a0b74dab627f917ce6e461b0ba5106c80630 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 10:15:20 +0200 Subject: [PATCH 75/94] multihit wip2 --- .../special/ChinchompaSwingHandler.java | 26 ++++-------- .../special/PowerstabSpecialHandler.java | 17 ++++---- .../special/SpearWallSpecialHandler.java | 14 +++---- .../special/SweepSpecialHandler.java | 12 ++---- .../magic/ancient/AncientTeleportPlugin.java | 2 +- .../skill/magic/ancient/BloodSpells.java | 5 ++- .../global/skill/magic/ancient/IceSpells.java | 13 +++--- .../skill/magic/ancient/MiasmicSpells.java | 11 +++-- .../skill/magic/ancient/ShadowSpells.java | 6 ++- .../skill/magic/ancient/SmokeSpells.java | 8 ++-- .../handlers/WildernessObeliskPlugin.java | 2 +- .../node/entity/combat/MultihitTargets.kt | 39 ++++++++++++++++++ .../node/entity/combat/spell/CombatSpell.java | 41 ------------------- .../main/core/game/world/map/RegionManager.kt | 21 ++++------ 14 files changed, 103 insertions(+), 114 deletions(-) create mode 100644 Server/src/main/core/game/node/entity/combat/MultihitTargets.kt diff --git a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java index 953b9db04..de9344617 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java @@ -6,15 +6,15 @@ import core.game.node.entity.combat.equipment.Ammunition; import core.game.node.entity.combat.equipment.RangeWeapon; import core.game.node.entity.combat.equipment.Weapon; import core.game.node.entity.combat.equipment.WeaponInterface; -import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.node.entity.skill.Skills; -import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; import java.util.List; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; + /** * Handles a combat swing using red chinchompas. * @author Emperor @@ -55,25 +55,17 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { return -1; } - // https://oldschool.runescape.wiki/w/Chinchompa - shit source but it's better than what was here before - List targetCandidates; - if (victim instanceof Player) { - targetCandidates = RegionManager.getSurroundingPlayers(victim, 9); - } else { - targetCandidates = RegionManager.getSurroundingNPCs(victim, 11); - } + List targetCandidates = findMultihitTargets(victim.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.RANGE); BattleState[] targets = new BattleState[targetCandidates.size()]; int count = 0; for (Entity e : targetCandidates) { - if (e != entity && canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { - BattleState s = targets[count++] = new BattleState(entity, e); - s.setStyle(CombatStyle.RANGE); - int hit = 0; - if (isAccurateImpact(entity, e, CombatStyle.RANGE)) { - hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); - } - s.setEstimatedHit(hit); + BattleState s = targets[count++] = new BattleState(entity, e); + s.setStyle(CombatStyle.RANGE); + int hit = 0; + if (isAccurateImpact(entity, e, CombatStyle.RANGE)) { + hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); } + s.setEstimatedHit(hit); } state.setTargets(targets); Companion.useAmmo(entity, state, null); diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index 7820d94d6..bcfb11e96 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -19,6 +19,7 @@ import core.tools.RandomFunction; import org.rs09.consts.Sounds; import static core.api.ContentAPIKt.playGlobalAudio; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; /** * Handles the Powerstab special attack. @@ -75,19 +76,17 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); + List list = findMultihitTargets(entity.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { - if (e != entity && CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { - BattleState s = targets[count++] = new BattleState(entity, e); - int hit = 0; - if (isAccurateImpact(entity, e)) { - hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); - } - s.setStyle(CombatStyle.MELEE); - s.setEstimatedHit(hit); + BattleState s = targets[count++] = new BattleState(entity, e); + int hit = 0; + if (isAccurateImpact(entity, e)) { + hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); } + s.setStyle(CombatStyle.MELEE); + s.setEstimatedHit(hit); } state.setTargets(targets); return 1; diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java index 27cd436ff..b66af1707 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java @@ -19,6 +19,7 @@ import core.tools.RandomFunction; import org.rs09.consts.Sounds; import static core.api.ContentAPIKt.playGlobalAudio; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; /** * Handles Vesta's Spear special attack - Spear Wall. @@ -76,17 +77,14 @@ public final class SpearWallSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = victim instanceof NPC ? RegionManager.getSurroundingNPCs(entity, 9) : RegionManager.getSurroundingPlayers(entity, 9); + List list = findMultihitTargets(entity.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { - if (e != entity && CombatStyle.RANGE.getSwingHandler().canSwing(entity, e) != InteractionType.NO_INTERACT && e.isAttackable(entity, CombatStyle.RANGE, false)) { - BattleState s = targets[count++] = new BattleState(entity, e); - int hit = 0; - hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); - s.setStyle(CombatStyle.MELEE); - s.setEstimatedHit(hit); - } + BattleState s = targets[count++] = new BattleState(entity, e); + int hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); + s.setStyle(CombatStyle.MELEE); + s.setEstimatedHit(hit); } state.setTargets(targets); return 1; diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index f01773bd1..cdeed3461 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -24,6 +24,7 @@ import core.tools.RandomFunction; import org.rs09.consts.Sounds; import static core.api.ContentAPIKt.playGlobalAudio; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; /** * Handles the Dragon halberd special attack. @@ -100,14 +101,9 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); - for (Entity n : victim instanceof NPC ? RegionManager.getSurroundingNPCs(victim, 9) : RegionManager.getSurroundingPlayers(victim, 9)) { - if (n == entity || n == victim) { - continue; - } - if (n instanceof Familiar) { - continue; - } - if (!n.isAttackable(entity, CombatStyle.MELEE, false)) { + List list = findMultihitTargets(entity.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.MELEE); + for (Entity n : list) { + if (n == victim) { continue; } if (n.getLocation().equals(vl.transform(dir.getStepY(), dir.getStepX(), 0)) || n.getLocation().equals(vl.transform(-dir.getStepY(), -dir.getStepX(), 0))) { diff --git a/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java b/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java index a9c95ab5e..0d7b1cfa1 100644 --- a/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java +++ b/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java @@ -68,7 +68,7 @@ public final class AncientTeleportPlugin extends MagicSpell { return false; } homeTeleport((Player) entity, Location.create(3087, 3495, 0)); - entity.dispatch(new SpellCastEvent(SpellBook.ANCIENT, getSpellId(), target)); + entity.dispatch(new SpellCastEvent(SpellBook.ANCIENT, getSpellId(), target)); } else if (entity.getTeleporter().send(location.transform(0, RandomFunction.random(3), 0), TeleportType.ANCIENT)) { if (!super.meetsRequirements(entity, true, true)) { entity.getTeleporter().getCurrentTeleport().stop(); diff --git a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java index 453ccabb4..700c21ecc 100644 --- a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java @@ -2,6 +2,8 @@ package content.global.skill.magic.ancient; import java.util.List; +import core.game.node.entity.combat.CombatStyle; +import core.game.node.entity.combat.MultihitTargetsKt; import core.game.node.entity.combat.spell.Runes; import core.game.node.Node; import core.game.node.entity.Entity; @@ -118,7 +120,8 @@ public final class BloodSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target); + + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java index 30941fec7..664971e2f 100644 --- a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java @@ -2,6 +2,8 @@ package content.global.skill.magic.ancient; import java.util.List; +import core.game.node.entity.combat.CombatStyle; +import core.game.node.entity.combat.MultihitTargetsKt; import core.game.node.entity.combat.spell.Runes; import core.game.node.Node; import core.game.node.entity.Entity; @@ -131,10 +133,10 @@ public final class IceSpells extends CombatSpell { return; } int ticks = (type.ordinal() - 4) * 8; - if (hasTimerActive(victim, "frozen") || hasTimerActive(victim, "frozen:immunity")) { - if (type == SpellType.BARRAGE) { state.setFrozen(true); } - return; - } + if (hasTimerActive(victim, "frozen") || hasTimerActive(victim, "frozen:immunity")) { + if (type == SpellType.BARRAGE) { state.setFrozen(true); } + return; + } registerTimer(victim, spawnTimer("frozen", ticks, true)); } @@ -143,7 +145,8 @@ public final class IceSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target); + + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java index 927c59e29..075e1e725 100644 --- a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java @@ -3,6 +3,8 @@ import java.util.List; import core.game.container.impl.EquipmentContainer; +import core.game.node.entity.combat.CombatStyle; +import core.game.node.entity.combat.MultihitTargetsKt; import core.plugin.Initializable; import core.game.node.entity.combat.spell.Runes; import core.game.node.Node; @@ -121,7 +123,7 @@ public final class MiasmicSpells extends CombatSpell { @Override public void fireEffect(Entity entity, Entity victim, BattleState state) { if (!hasTimerActive(victim, "miasmic:immunity")) { - registerTimer(victim, spawnTimer("miasmic", (getSpellId() - 15) * 20)); + registerTimer(victim, spawnTimer("miasmic", (getSpellId() - 15) * 20)); } } @@ -142,8 +144,8 @@ public final class MiasmicSpells extends CombatSpell { @Override public boolean cast(Entity entity, Node target) { if (!validStaffEquipped(entity) && !GameWorld.getSettings().isDevMode()) { - ((Player) entity).getPacketDispatch().sendMessage("You need to be wielding Zuriel's staff in order to cast this spell."); - return false; + ((Player) entity).getPacketDispatch().sendMessage("You need to be wielding Zuriel's staff in order to cast this spell."); + return false; } if (!meetsRequirements(entity, true, false)) { return false; @@ -157,7 +159,8 @@ public final class MiasmicSpells extends CombatSpell { || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target); + + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java index c5f247ab7..29ec2eb5a 100644 --- a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java @@ -2,7 +2,8 @@ package content.global.skill.magic.ancient; import java.util.List; -import core.game.node.entity.player.Player; +import core.game.node.entity.combat.CombatStyle; +import core.game.node.entity.combat.MultihitTargetsKt; import core.game.node.entity.skill.Skills; import core.game.node.entity.combat.spell.Runes; import core.game.node.Node; @@ -115,7 +116,8 @@ public final class ShadowSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target); + + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java index 610d9611e..1245dbd01 100644 --- a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java @@ -2,6 +2,8 @@ package content.global.skill.magic.ancient; import java.util.List; +import core.game.node.entity.combat.CombatStyle; +import core.game.node.entity.combat.MultihitTargetsKt; import core.game.node.entity.combat.spell.Runes; import core.game.node.Node; import core.game.node.entity.Entity; @@ -10,7 +12,6 @@ import core.game.node.entity.combat.spell.CombatSpell; import core.game.node.entity.combat.spell.SpellType; import core.game.node.entity.impl.Projectile; import core.game.node.entity.impl.Animator.Priority; -import core.game.node.entity.player.Player; import core.game.node.entity.player.link.SpellBookManager.SpellBook; import core.game.node.item.Item; import core.game.world.update.flag.context.Animation; @@ -114,7 +115,7 @@ public final class SmokeSpells extends CombatSpell { @Override public void fireEffect(Entity entity, Entity victim, BattleState state) { if (state.getEstimatedHit() > -1) { - applyPoison(victim, entity, type.ordinal() >= SpellType.BLITZ.ordinal() ? 4 : 2); + applyPoison(victim, entity, type.ordinal() >= SpellType.BLITZ.ordinal() ? 4 : 2); } } @@ -123,7 +124,8 @@ public final class SmokeSpells extends CombatSpell { if (animation.getId() == 1978 || !entity.getProperties().isMultiZone() || !target.getProperties().isMultiZone()) { return super.getTargets(entity, target); } - List list = getMultihitTargets(entity, target); + + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java b/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java index 6e70c538d..e7e5bbcd1 100644 --- a/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java +++ b/Server/src/main/content/region/wilderness/handlers/WildernessObeliskPlugin.java @@ -106,7 +106,7 @@ public final class WildernessObeliskPlugin extends OptionHandler { int index = RandomFunction.random(0, newObelisks.length - 1); //cutting out the last one that is now duplicated Obelisk newObelisk = newObelisks[index]; // Teleport players standing within a 3-by-3 bounding box - for (Player player : RegionManager.getLocalPlayersBoundingBox(center, 0)) { + for (Player player : RegionManager.getLocalPlayers(center, 1)) { if (player.timers.getTimer("teleblock") == null) { player.getPacketDispatch().sendMessage("Ancient magic teleports you somewhere in the wilderness."); int xOffset = player.getLocation().getX() - center.getX(); diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt new file mode 100644 index 000000000..244358bd5 --- /dev/null +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -0,0 +1,39 @@ +package core.game.node.entity.combat + +import content.global.skill.summoning.familiar.Familiar +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.RegionManager.getLocalEntities +import core.game.world.map.zone.impl.WildernessZone + +fun findMultihitTargets(center: Location, entity: Entity, victim: Entity, swingHandler: CombatSwingHandler, combatStyle: CombatStyle): List { + val targetCandidates = getLocalEntities(center, 1).filter { it != entity && swingHandler.canSwing(entity, it) != InteractionType.NO_INTERACT && it.isAttackable(entity, combatStyle, false) } + val targets: List? + if (victim is Player) { + val players = targetCandidates.filterIsInstance() + fun isFamiliarOf(entity: Entity, players: List): Boolean { + if (entity !is Familiar) { + return false + } + return entity.owner in players + } + targets = targetCandidates.filter { it is Player || isFamiliarOf(it, players) } + } else { + val npcs = targetCandidates.filterIsInstance() + fun isOwnerOf(entity: Entity, npcs: List): Boolean { + if (entity !is Player) { + return false + } + for (npc in npcs) { + if (npc is Familiar && npc.owner == entity) { + return WildernessZone.getInstance().continueAttack(entity, entity, combatStyle, false) + } + } + return false + } + targets = targetCandidates.filter { it is NPC || isOwnerOf(it, npcs) } + } + return targets.take(9) +} \ No newline at end of file diff --git a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java index 33c564c12..ca5e550c9 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/CombatSpell.java @@ -1,9 +1,6 @@ package core.game.node.entity.combat.spell; -import content.global.skill.summoning.familiar.Familiar; import core.game.node.entity.combat.BattleState; -import core.game.node.entity.combat.CombatStyle; -import core.game.node.entity.combat.InteractionType; import core.game.node.Node; import core.game.node.entity.Entity; import core.game.node.entity.impl.Animator.Priority; @@ -13,15 +10,10 @@ import core.game.node.entity.player.Player; import core.game.node.entity.player.link.SpellBookManager; import core.game.node.entity.player.link.audio.Audio; import core.game.node.item.Item; -import core.game.world.map.RegionManager; -import core.game.world.map.zone.impl.WildernessZone; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import org.rs09.consts.Sounds; -import java.util.ArrayList; -import java.util.List; - import static core.api.ContentAPIKt.playGlobalAudio; /** @@ -108,39 +100,6 @@ public abstract class CombatSpell extends MagicSpell { } - /** - * Gets a list of valid targets for a multihitting spell. - * @param entity The caster of the spell. - * @param victim The primary victim. - * @return The list of targets (the primary target is always at index 0). - */ - public List getMultihitTargets(Entity entity, Entity victim) { - // https://oldschool.runescape.wiki/w/Chinchompa - shit source but it's better than what was here before - List targetCandidates; - if (victim instanceof Player) { - targetCandidates = RegionManager.getSurroundingPlayers(victim, 9); - } else { - targetCandidates = RegionManager.getSurroundingNPCs(victim, 11); - } - for (Entity e : targetCandidates) { - if (e == victim || e == entity) { - continue; - } - if (CombatStyle.MAGIC.getSwingHandler().canSwing(entity, e) == InteractionType.NO_INTERACT || !e.isAttackable(entity, CombatStyle.MAGIC, false)) { - continue; - } - if (e instanceof Familiar) { - Player owner = ((Familiar) e).getOwner(); - if (owner != entity && WildernessZone.getInstance().continueAttack(entity, owner, CombatStyle.MAGIC, true)) { - targetCandidates.add(e); - } - } else { - targetCandidates.add(e); - } - } - return targetCandidates; - } - /** * Visualizes the impact. * @param entity The entity. diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index 8a78e0a99..f35789082 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -420,7 +420,7 @@ object RegionManager { * @param maximum the maximum number of entities to return. * @return the list. */ - inline fun getLocalEntities(location: Location, distance: Int, maximum: Int): List { + private inline fun getLocalEntitiesOfType(location: Location, distance: Int): List { val entities: MutableList = ArrayList(20) for (cx in (location.absChunkX - 8)..(location.absChunkX + 8)) { for (cy in (location.absChunkY - 8)..(location.absChunkY + 8)) { @@ -434,20 +434,13 @@ object RegionManager { } } val b = ZoneBorders(location.x - distance, location.y - distance, location.x + distance, location.y + distance) - var filtered = entities.filter { b.insideBorder(it.location.x, it.location.y) } - if (maximum > 0 && filtered.size > maximum) { - filtered = filtered.slice(0 until maximum) - } - return filtered + return entities.filter { b.insideBorder(it.location.x, it.location.y) } } - @JvmStatic fun getLocalEntities(location: Location, distance: Int): List = getLocalEntities(location, distance, 0) - @JvmStatic fun getLocalPlayers(location: Location, distance: Int): List = getLocalEntities(location, distance, 0) - @JvmStatic fun getLocalNPCs(location: Location, distance: Int): List = getLocalEntities(location, distance, 0) - @JvmStatic fun getLocalPlayers(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0) - @JvmStatic fun getLocalNPCs(location: Location): List = getLocalEntities(location, MapDistance.RENDERING.distance, 0) - @JvmStatic fun getSurroundingPlayers(player: Entity, maximum: Int): List = getLocalEntities(player.location, 1, maximum) - @JvmStatic fun getSurroundingNPCs(npc: Entity, maximum: Int): List = getLocalEntities(npc.location, 1, maximum) - @JvmStatic fun getLocalPlayersBoundingBox(location: Location, maximum: Int): List = getLocalEntities(location, 1, maximum) + @JvmStatic fun getLocalEntities(location: Location, distance: Int) = getLocalEntitiesOfType(location, distance) + @JvmStatic fun getLocalPlayers(location: Location, distance: Int) = getLocalEntitiesOfType(location, distance) + @JvmStatic fun getLocalNPCs(location: Location, distance: Int) = getLocalEntitiesOfType(location, distance) + @JvmStatic fun getLocalPlayers(location: Location): List = getLocalPlayers(location, MapDistance.RENDERING.distance) + @JvmStatic fun getLocalNPCs(location: Location): List = getLocalNPCs(location, MapDistance.RENDERING.distance) /** * Gets a random teleport location in the radius around the given location. From e91bf716a42230c7772a9b15e0f9f0af6d4d4b4d Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 11:13:04 +0200 Subject: [PATCH 76/94] Fix bugs in multihit --- .../item/equipment/special/ChinchompaSwingHandler.java | 5 +++-- .../item/equipment/special/PowerstabSpecialHandler.java | 2 +- .../item/equipment/special/SpearWallSpecialHandler.java | 2 +- .../item/equipment/special/SweepSpecialHandler.java | 2 +- .../content/global/skill/magic/ancient/BloodSpells.java | 2 +- .../content/global/skill/magic/ancient/IceSpells.java | 2 +- .../content/global/skill/magic/ancient/MiasmicSpells.java | 2 +- .../content/global/skill/magic/ancient/ShadowSpells.java | 2 +- .../content/global/skill/magic/ancient/SmokeSpells.java | 2 +- .../main/core/game/node/entity/combat/MultihitTargets.kt | 8 ++++---- 10 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java index de9344617..246fb6297 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java @@ -55,14 +55,15 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { return -1; } - List targetCandidates = findMultihitTargets(victim.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.RANGE); + boolean accurate = isAccurateImpact(entity, victim, CombatStyle.RANGE); + List targetCandidates = findMultihitTargets(victim.getLocation(), entity, victim, CombatStyle.RANGE); BattleState[] targets = new BattleState[targetCandidates.size()]; int count = 0; for (Entity e : targetCandidates) { BattleState s = targets[count++] = new BattleState(entity, e); s.setStyle(CombatStyle.RANGE); int hit = 0; - if (isAccurateImpact(entity, e, CombatStyle.RANGE)) { + if (accurate) { hit = RandomFunction.random(calculateHit(entity, e, 1.0) + 1); } s.setEstimatedHit(hit); diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index bcfb11e96..678bc6ef6 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -76,7 +76,7 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargets(entity.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.MELEE); + List list = findMultihitTargets(entity.getLocation(), entity, victim, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java index b66af1707..9e5b4227c 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java @@ -77,7 +77,7 @@ public final class SpearWallSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargets(entity.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.MELEE); + List list = findMultihitTargets(entity.getLocation(), entity, victim, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index cdeed3461..04ca935d9 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -101,7 +101,7 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); - List list = findMultihitTargets(entity.getLocation(), entity, victim, entity.getSwingHandler(false), CombatStyle.MELEE); + List list = findMultihitTargets(entity.getLocation(), entity, victim, CombatStyle.MELEE); for (Entity n : list) { if (n == victim) { continue; diff --git a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java index 700c21ecc..c9ebbff9e 100644 --- a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java @@ -121,7 +121,7 @@ public final class BloodSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java index 664971e2f..e2afb1488 100644 --- a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java @@ -146,7 +146,7 @@ public final class IceSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java index 075e1e725..101c21943 100644 --- a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java @@ -160,7 +160,7 @@ public final class MiasmicSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java index 29ec2eb5a..f50d3206a 100644 --- a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java @@ -117,7 +117,7 @@ public final class ShadowSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java index 1245dbd01..4c238df56 100644 --- a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java @@ -125,7 +125,7 @@ public final class SmokeSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, entity.getSwingHandler(false), CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt index 244358bd5..71666b7da 100644 --- a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -8,8 +8,8 @@ import core.game.world.map.Location import core.game.world.map.RegionManager.getLocalEntities import core.game.world.map.zone.impl.WildernessZone -fun findMultihitTargets(center: Location, entity: Entity, victim: Entity, swingHandler: CombatSwingHandler, combatStyle: CombatStyle): List { - val targetCandidates = getLocalEntities(center, 1).filter { it != entity && swingHandler.canSwing(entity, it) != InteractionType.NO_INTERACT && it.isAttackable(entity, combatStyle, false) } +fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, combatStyle: CombatStyle): List { + val targetCandidates = getLocalEntities(center, 1).filter { it != attacker && it.isAttackable(attacker, combatStyle, false) } val targets: List? if (victim is Player) { val players = targetCandidates.filterIsInstance() @@ -17,7 +17,7 @@ fun findMultihitTargets(center: Location, entity: Entity, victim: Entity, swingH if (entity !is Familiar) { return false } - return entity.owner in players + return entity.owner in players && WildernessZone.getInstance().continueAttack(attacker, entity.owner, combatStyle, false) } targets = targetCandidates.filter { it is Player || isFamiliarOf(it, players) } } else { @@ -28,7 +28,7 @@ fun findMultihitTargets(center: Location, entity: Entity, victim: Entity, swingH } for (npc in npcs) { if (npc is Familiar && npc.owner == entity) { - return WildernessZone.getInstance().continueAttack(entity, entity, combatStyle, false) + return WildernessZone.getInstance().continueAttack(attacker, entity, combatStyle, false) } } return false From e998239635bdad1db04a4097e87a95db966961f7 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 11:30:37 +0200 Subject: [PATCH 77/94] Fix bugs in multihit --- .../special/SweepSpecialHandler.java | 2 +- .../node/entity/combat/MultihitTargets.kt | 20 ++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index 04ca935d9..94c11cca6 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -101,7 +101,7 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); - List list = findMultihitTargets(entity.getLocation(), entity, victim, CombatStyle.MELEE); + List list = findMultihitTargets(vl, entity, victim, null); for (Entity n : list) { if (n == victim) { continue; diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt index 71666b7da..478d58026 100644 --- a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -8,8 +8,18 @@ import core.game.world.map.Location import core.game.world.map.RegionManager.getLocalEntities import core.game.world.map.zone.impl.WildernessZone -fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, combatStyle: CombatStyle): List { - val targetCandidates = getLocalEntities(center, 1).filter { it != attacker && it.isAttackable(attacker, combatStyle, false) } +fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatStyle?, wilderness: Boolean): Boolean { + if (combatStyle == null) { + return true + } + if (wilderness) { + return WildernessZone.getInstance().continueAttack(attacker, victim, combatStyle, false) + } + return victim.isAttackable(attacker, combatStyle, false) +} + +fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, combatStyle: CombatStyle?): List { + val targetCandidates = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } val targets: List? if (victim is Player) { val players = targetCandidates.filterIsInstance() @@ -17,9 +27,9 @@ fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, comb if (entity !is Familiar) { return false } - return entity.owner in players && WildernessZone.getInstance().continueAttack(attacker, entity.owner, combatStyle, false) + return entity.owner in players && isAttackable(entity.owner, attacker, combatStyle, true) } - targets = targetCandidates.filter { it is Player || isFamiliarOf(it, players) } + targets = targetCandidates.filter { (it is Player && isAttackable(attacker, it, combatStyle, true)) || isFamiliarOf(it, players) } } else { val npcs = targetCandidates.filterIsInstance() fun isOwnerOf(entity: Entity, npcs: List): Boolean { @@ -28,7 +38,7 @@ fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, comb } for (npc in npcs) { if (npc is Familiar && npc.owner == entity) { - return WildernessZone.getInstance().continueAttack(attacker, entity, combatStyle, false) + return isAttackable(entity, attacker, combatStyle, true) } } return false From eca859714714d2da48b9e7c51277a7a35b8a3fc3 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 11:43:59 +0200 Subject: [PATCH 78/94] ssshhh you did not see this --- .../region/misthalin/draynor/handlers/DBRCutscenePlugin.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt b/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt index 50a13f033..467943a5d 100644 --- a/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt +++ b/Server/src/main/content/region/misthalin/draynor/handlers/DBRCutscenePlugin.kt @@ -1,6 +1,5 @@ package content.region.misthalin.draynor.handlers -import content.region.misthalin.draynor.dialogue.DraynorBankGuard import core.api.* import core.game.activity.Cutscene import core.game.component.Component From 8316d934e95ffbf389a512241e7ace45e5bb4e25 Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 16:23:37 +0200 Subject: [PATCH 79/94] Multihit fix only chinchompas discriminate players and npcs --- .../special/ChinchompaSwingHandler.java | 4 ++-- .../special/PowerstabSpecialHandler.java | 5 +---- .../special/SpearWallSpecialHandler.java | 5 +---- .../equipment/special/SweepSpecialHandler.java | 7 +------ .../global/skill/magic/ancient/BloodSpells.java | 2 +- .../global/skill/magic/ancient/IceSpells.java | 2 +- .../skill/magic/ancient/MiasmicSpells.java | 2 +- .../skill/magic/ancient/ShadowSpells.java | 2 +- .../global/skill/magic/ancient/SmokeSpells.java | 2 +- .../game/node/entity/combat/MultihitTargets.kt | 17 +++++++++++------ 10 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java index 246fb6297..73b034e06 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java @@ -13,7 +13,7 @@ import core.tools.RandomFunction; import java.util.List; -import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargetsForChinchompa; /** * Handles a combat swing using red chinchompas. @@ -56,7 +56,7 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { } boolean accurate = isAccurateImpact(entity, victim, CombatStyle.RANGE); - List targetCandidates = findMultihitTargets(victim.getLocation(), entity, victim, CombatStyle.RANGE); + List targetCandidates = findMultihitTargetsForChinchompa(victim.getLocation(), entity, victim); BattleState[] targets = new BattleState[targetCandidates.size()]; int count = 0; for (Entity e : targetCandidates) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index 678bc6ef6..74f18dca1 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -5,12 +5,9 @@ import java.util.List; 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.combat.InteractionType; import core.game.node.entity.combat.MeleeSwingHandler; import core.game.node.entity.impl.Animator.Priority; -import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; -import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Plugin; @@ -76,7 +73,7 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargets(entity.getLocation(), entity, victim, CombatStyle.MELEE); + List list = findMultihitTargets(entity.getLocation(), entity, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java index 9e5b4227c..3abb1e50f 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java @@ -5,12 +5,9 @@ import java.util.List; 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.combat.InteractionType; import core.game.node.entity.combat.MeleeSwingHandler; import core.game.node.entity.impl.Animator.Priority; -import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; -import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Plugin; @@ -77,7 +74,7 @@ public final class SpearWallSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargets(entity.getLocation(), entity, victim, CombatStyle.MELEE); + List list = findMultihitTargets(entity.getLocation(), entity, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index 94c11cca6..3c9217d8f 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -2,21 +2,16 @@ package content.global.handlers.item.equipment.special; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; -import core.game.world.repository.Repository; import core.plugin.Initializable; -import content.global.skill.summoning.familiar.Familiar; 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.combat.MeleeSwingHandler; import core.game.node.entity.impl.Animator.Priority; -import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.world.map.Direction; import core.game.world.map.Location; -import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Plugin; @@ -101,7 +96,7 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); - List list = findMultihitTargets(vl, entity, victim, null); + List list = findMultihitTargets(vl, entity, null); for (Entity n : list) { if (n == victim) { continue; diff --git a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java index c9ebbff9e..44280fe75 100644 --- a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java @@ -121,7 +121,7 @@ public final class BloodSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java index e2afb1488..d854979e4 100644 --- a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java @@ -146,7 +146,7 @@ public final class IceSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java index 101c21943..6cdfe11c7 100644 --- a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java @@ -160,7 +160,7 @@ public final class MiasmicSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java index f50d3206a..c8d390dba 100644 --- a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java @@ -117,7 +117,7 @@ public final class ShadowSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java index 4c238df56..187f7249c 100644 --- a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java @@ -125,7 +125,7 @@ public final class SmokeSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, target, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt index 478d58026..1150743a4 100644 --- a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -8,7 +8,7 @@ import core.game.world.map.Location import core.game.world.map.RegionManager.getLocalEntities import core.game.world.map.zone.impl.WildernessZone -fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatStyle?, wilderness: Boolean): Boolean { +private fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatStyle?, wilderness: Boolean): Boolean { if (combatStyle == null) { return true } @@ -18,8 +18,13 @@ fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatStyle?, wi return victim.isAttackable(attacker, combatStyle, false) } -fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, combatStyle: CombatStyle?): List { - val targetCandidates = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } +fun findMultihitTargets(center: Location, attacker: Entity, combatStyle: CombatStyle?): List { + val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } + return targets.take(9) +} + +fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: Entity): List { + val targetCandidates = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, CombatStyle.RANGE, false) } val targets: List? if (victim is Player) { val players = targetCandidates.filterIsInstance() @@ -27,9 +32,9 @@ fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, comb if (entity !is Familiar) { return false } - return entity.owner in players && isAttackable(entity.owner, attacker, combatStyle, true) + return entity.owner in players && isAttackable(entity.owner, attacker, CombatStyle.RANGE, true) } - targets = targetCandidates.filter { (it is Player && isAttackable(attacker, it, combatStyle, true)) || isFamiliarOf(it, players) } + targets = targetCandidates.filter { (it is Player && isAttackable(attacker, it, CombatStyle.RANGE, true)) || isFamiliarOf(it, players) } } else { val npcs = targetCandidates.filterIsInstance() fun isOwnerOf(entity: Entity, npcs: List): Boolean { @@ -38,7 +43,7 @@ fun findMultihitTargets(center: Location, attacker: Entity, victim: Entity, comb } for (npc in npcs) { if (npc is Familiar && npc.owner == entity) { - return isAttackable(entity, attacker, combatStyle, true) + return isAttackable(entity, attacker, CombatStyle.RANGE, true) } } return false From e85d81157f92892aa95b7679ccc588e692c7318a Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 16:35:54 +0200 Subject: [PATCH 80/94] inline a few getObjects for greg --- .../tearsofguthix/TearsOfGuthixMinigame.kt | 2 +- Server/src/main/core/api/ContentAPI.kt | 2 +- .../game/global/action/DoorActionHandler.java | 13 ++++++---- .../main/core/game/world/map/RegionManager.kt | 26 +------------------ .../main/core/net/packet/PacketProcessor.kt | 4 +-- .../src/test/kotlin/core/PathfinderTests.kt | 6 +---- 6 files changed, 14 insertions(+), 39 deletions(-) diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt index b097ee20a..c6594cb64 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt @@ -367,7 +367,7 @@ class TearsOfGuthixGlobalTick : TickListener { */ wallStates.forEachIndexed { index, state -> val wallLocation = allWalls[index + 1] - val currentWaterfall = RegionManager.getObject(wallLocation, 4)!! + val currentWaterfall = RegionManager.getObject(wallLocation.z, wallLocation.x, wallLocation.y, -1, 4)!! val newWaterfallId = when (state) { 2 -> { if (index + 1 <= 5) Scenery.GREEN_TEARS_6662 else Scenery.GREEN_TEARS_6666 diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 749324d36..904f5cb6c 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -1081,7 +1081,7 @@ fun findNPC(id: Int): NPC? { * @param type the scenery type, -1 if any */ fun getScenery(x: Int, y: Int, z: Int, type: Int = -1): Scenery? { - return RegionManager.getObject(z, x, y, type) + return RegionManager.getObject(z, x, y, type, -1) } /** diff --git a/Server/src/main/core/game/global/action/DoorActionHandler.java b/Server/src/main/core/game/global/action/DoorActionHandler.java index 26df139c5..fcf0bdab6 100644 --- a/Server/src/main/core/game/global/action/DoorActionHandler.java +++ b/Server/src/main/core/game/global/action/DoorActionHandler.java @@ -1,6 +1,5 @@ package core.game.global.action; -import content.data.Quests; import core.game.node.entity.Entity; import core.game.node.entity.player.Player; import core.game.node.entity.player.link.diary.DiaryType; @@ -491,6 +490,10 @@ public final class DoorActionHandler { return null; } + private static Scenery getAdjacentDoor(Location location, int type) { + return RegionManager.getObject(location.getZ(), location.getX(), location.getY(), -1, type); + } + /** * Gets the door next to this door. * @@ -500,16 +503,16 @@ public final class DoorActionHandler { public static Scenery getSecondDoor(Scenery object, Entity entity) { Location l = object.getLocation(); Scenery o = null; - if ((o = RegionManager.getObject(l.transform(-1, 0, 0), object.getType())) != null && o.getName().equals(object.getName())) { + if ((o = getAdjacentDoor(l.transform(-1, 0, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } - if ((o = RegionManager.getObject(l.transform(1, 0, 0), object.getType())) != null && o.getName().equals(object.getName())) { + if ((o = getAdjacentDoor(l.transform(1, 0, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } - if ((o = RegionManager.getObject(l.transform(0, -1, 0), object.getType())) != null && o.getName().equals(object.getName())) { + if ((o = getAdjacentDoor(l.transform(0, -1, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } - if ((o = RegionManager.getObject(l.transform(0, 1, 0), object.getType())) != null && o.getName().equals(object.getName())) { + if ((o = getAdjacentDoor(l.transform(0, 1, 0), object.getType())) != null && o.getName().equals(object.getName())) { return o; } return null; diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index f35789082..d123088dd 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -303,17 +303,6 @@ object RegionManager { return getObject(l.z, l.x, l.y) } - /** - * Gets the scenery on the current location of the same type as a different piece of scenery. - * @param l The location. - * @param type The scenery type. - * @return The scenery, or `null` if no object was found. - */ - @JvmStatic - fun getObject(l: Location, type: Int): Scenery? { - return getObject(l.z, l.x, l.y, -1, type) - } - /** * Gets the scenery on the current absolute coordinates. * @param z The height. @@ -323,20 +312,7 @@ object RegionManager { */ @JvmStatic fun getObject(z: Int, x: Int, y: Int): Scenery? { - return getObject(z, x, y, -1) - } - - /** - * Gets the object on the given absolute coordinates. - * @param z The height. - * @param x The x-coordinate. - * @param y The y-coordinate. - * @param objectId The object id. - * @return The scenery, or `null` if no object was found. - */ - @JvmStatic - fun getObject(z: Int, x: Int, y: Int, objectId: Int): Scenery? { - return getObject(z, x, y, objectId, -1) + return getObject(z, x, y, -1, -1) } /** diff --git a/Server/src/main/core/net/packet/PacketProcessor.kt b/Server/src/main/core/net/packet/PacketProcessor.kt index 7a05cc549..b7c10c50f 100644 --- a/Server/src/main/core/net/packet/PacketProcessor.kt +++ b/Server/src/main/core/net/packet/PacketProcessor.kt @@ -579,7 +579,7 @@ object PacketProcessor { } else if (pkt is Packet.UseWithScenery) { item = pkt.player.inventory[pkt.slot] ?: return sendClearMinimap(pkt.player) - node = RegionManager.getObject(pkt.player.location.z, pkt.x, pkt.y, pkt.sceneryId) ?: return sendClearMinimap(pkt.player) + node = RegionManager.getObject(pkt.player.location.z, pkt.x, pkt.y, pkt.sceneryId, -1) ?: return sendClearMinimap(pkt.player) childNode = node.asScenery().getChild(pkt.player) itemId = pkt.itemId nodeId = node.id @@ -680,7 +680,7 @@ object PacketProcessor { private fun processSceneryAction(pkt: Packet.SceneryAction) { val player = pkt.player - var scenery = RegionManager.getObject(player.location.z, pkt.x, pkt.y, pkt.id) + var scenery = RegionManager.getObject(player.location.z, pkt.x, pkt.y, pkt.id, -1) var objId = pkt.id //what follows is a series of hardcoded crimes against humanity diff --git a/Server/src/test/kotlin/core/PathfinderTests.kt b/Server/src/test/kotlin/core/PathfinderTests.kt index eebeb5219..a5bed11fb 100644 --- a/Server/src/test/kotlin/core/PathfinderTests.kt +++ b/Server/src/test/kotlin/core/PathfinderTests.kt @@ -16,12 +16,8 @@ import core.game.node.entity.impl.PulseType import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player import core.game.world.GameWorld -import core.game.world.map.Region -import core.net.packet.PacketProcessor -import core.plugin.ClassScanner import core.plugin.Plugin import core.tools.Log -import org.rs09.consts.NPCs class PathfinderTests { companion object {init {TestUtils.preTestSetup(); GatheringSkillOptionListeners().defineListeners(); WoodcuttingListener().defineListeners() }; val NPC_TEST_LOC = ServerConstants.HOME_LOCATION!!.transform(2, 10, 0)} @@ -49,7 +45,7 @@ class PathfinderTests { @Test fun movementPulseShouldStopEarlyIfNextToATileOccupiedByTargetObject() { val start = Location.create(2731, 3481) - val dest = RegionManager.getObject(0, 2720, 3475, 1307) + val dest = RegionManager.getObject(0, 2720, 3475, 1307, -1) val p = TestUtils.getMockPlayer("treefindtest") p.location = start p.init() From f2456b676f118f938ea747ce9c2f5215d4f8ee7f Mon Sep 17 00:00:00 2001 From: Player Name Date: Mon, 27 Jul 2026 17:52:26 +0200 Subject: [PATCH 81/94] Remove ailing test that I inherited from an earlier version of dam's movement MR --- Server/src/test/kotlin/core/PathfinderTests.kt | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Server/src/test/kotlin/core/PathfinderTests.kt b/Server/src/test/kotlin/core/PathfinderTests.kt index a5bed11fb..621bbebc0 100644 --- a/Server/src/test/kotlin/core/PathfinderTests.kt +++ b/Server/src/test/kotlin/core/PathfinderTests.kt @@ -112,22 +112,6 @@ class PathfinderTests { } } - @Test fun entityTargetMovementPulseShouldTolerateMissingTargetLocation() { - TestUtils.getMockPlayer("missingtargetloc").use { p -> - p.location = ServerConstants.HOME_LOCATION - val npc = NPC.create(0, NPC_TEST_LOC) - npc.setLocation(null) - - val pulse = object : MovementPulse(p, npc) { - override fun pulse(): Boolean { - return true - } - } - - Assertions.assertDoesNotThrow { pulse.update() } - } - } - @Test fun entityTargetMovementPulseShouldNotStopOnSameTileAsEntity() { TestUtils.getMockPlayer("entitystoptest").use {p -> p.location = ServerConstants.HOME_LOCATION From 33f1ea94d19572edc71b791223499621413fcb16 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 28 Jul 2026 20:07:12 +0200 Subject: [PATCH 82/94] Hopefully last review comments for greg --- .../special/PowerstabSpecialHandler.java | 4 +- .../skill/construction/HouseManager.java | 28 ++--- .../global/skill/construction/Room.java | 2 +- .../gather/woodcutting/WoodcuttingListener.kt | 6 +- .../magic/ancient/AncientTeleportPlugin.java | 2 +- .../draynor/dialogue/DraynorBankGuard.java | 4 +- Server/src/main/core/game/bots/ScriptAPI.kt | 8 +- .../core/game/interaction/MovementPulse.java | 2 +- .../node/entity/combat/MultihitTargets.kt | 11 +- .../core/game/node/entity/player/Player.java | 2 +- .../system/command/sets/SpawnCommandSet.kt | 8 +- .../core/game/system/config/ConfigParser.kt | 4 +- .../system/config/ObjectOverrideParser.kt | 4 +- .../src/main/core/game/world/map/Region.java | 110 ++++++++++-------- .../main/core/game/world/map/RegionChunk.java | 74 ++++++------ .../main/core/game/world/map/RegionManager.kt | 13 +-- .../game/world/map/build/DynamicRegion.java | 34 +++--- .../game/world/map/build/MapscapeParser.java | 20 ++-- .../world/map/zone/impl/ModeratorZone.java | 5 - .../game/world/update/ChunkDirtyListener.kt | 17 ++- .../game/world/update/ChunkUpdateTracker.kt | 19 --- .../game/world/update/MapChunkRenderer.kt | 12 +- .../core/game/world/update/NPCRenderer.kt | 5 +- .../game/world/update/flag/PlayerFlags.java | 3 +- .../randoms/SnowStormHolidayRandomNPC.kt | 2 +- .../net/packet/out/BuildDynamicScene.java | 11 +- .../core/net/packet/out/ClearRegionChunk.java | 2 +- .../blastfurnace/BlastFurnaceAreaTests.kt | 2 +- 28 files changed, 206 insertions(+), 208 deletions(-) delete mode 100644 Server/src/main/core/game/world/update/ChunkUpdateTracker.kt diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index 74f18dca1..ca7efb145 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -16,7 +16,7 @@ import core.tools.RandomFunction; import org.rs09.consts.Sounds; import static core.api.ContentAPIKt.playGlobalAudio; -import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargetsForD2h; /** * Handles the Powerstab special attack. @@ -73,7 +73,7 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargets(entity.getLocation(), entity, CombatStyle.MELEE); + List list = findMultihitTargetsForD2h(entity.getLocation(), entity, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/construction/HouseManager.java b/Server/src/main/content/global/skill/construction/HouseManager.java index 555ad027a..773d252b5 100644 --- a/Server/src/main/content/global/skill/construction/HouseManager.java +++ b/Server/src/main/content/global/skill/construction/HouseManager.java @@ -26,14 +26,12 @@ import static core.api.ContentAPIKt.*; import static core.api.regionspec.RegionSpecificationKt.fillWith; import static core.api.regionspec.RegionSpecificationKt.using; - /** * Manages the player's house. * @author Emperor * */ public final class HouseManager { - /** * The current region. */ @@ -98,7 +96,6 @@ public final class HouseManager { */ } - public void parse(JSONObject data){ location = HouseLocation.values()[Integer.parseInt( data.get("location").toString())]; style = HousingStyle.values()[Integer.parseInt( data.get("style").toString())]; @@ -261,7 +258,7 @@ public final class HouseManager { */ public void expelGuests(Player player) { if (isLoaded()) { - for (int z = 0; z < 4; z++) { + for (int z = 0; z < Region.PLANES; z++) { ArrayList players = new ArrayList<>(houseRegion.assemblePlayerList(z)); if (dungeonRegion != null) { players.addAll(dungeonRegion.assemblePlayerList(z)); @@ -292,7 +289,7 @@ public final class HouseManager { if (h.getDecorationIndex() > -1) { Decoration d = h.getHotspot().getDecorations()[h.getDecorationIndex()]; if (d == Decoration.PORTAL) { - return houseRegion.getBaseLocation().transform(x * 8 + h.getChunkX(), y * 8 + h.getChunkY() + 2, 0); + return houseRegion.getBaseLocation().transform(x*RegionChunk.SIZE + h.getChunkX(), y*RegionChunk.SIZE + h.getChunkY() + 2, 0); } } } @@ -308,9 +305,9 @@ public final class HouseManager { */ public void redecorate(HousingStyle style) { this.style = style; - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int z = 0; z < Region.PLANES; z++) { + for (int x = 0; x < RegionChunk.SIZE; x++) { + for (int y = 0; y < RegionChunk.SIZE; y++) { Room room = rooms[z][x][y]; if (room != null) { room.decorate(style); @@ -325,9 +322,9 @@ public final class HouseManager { */ @Deprecated public void clearRooms() { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int z = 0; z < Region.PLANES; z++) { + for (int x = 0; x < RegionChunk.SIZE; x++) { + for (int y = 0; y < RegionChunk.SIZE; y++) { rooms[z][x][y] = null; } } @@ -368,7 +365,7 @@ public final class HouseManager { } private DynamicRegion getPreparedRegion() { - ZoneBorders borders = DynamicRegion.reserveArea(8,8); + ZoneBorders borders = DynamicRegion.reserveArea(Region.CHUNKS_SIZE,Region.CHUNKS_SIZE); DynamicRegion region = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6); region.setBorders(borders); region.setBuild(true); @@ -604,8 +601,8 @@ public final class HouseManager { int startY = 99; int endX = 0; int endY = 0; - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < Region.CHUNKS_SIZE; x++) { + for (int y = 0; y < Region.CHUNKS_SIZE; y++) { if (rooms[0][x][y] != null) { if (x < startX) startX = x; if (y < startY) startY = y; @@ -699,9 +696,6 @@ public final class HouseManager { * Checks if the house region was constructed and active. * @return {@code True} if an active region for the house exists. */ - //public boolean isLoaded() { - // return (houseRegion != null) || (dungeonRegion != null); - //} public boolean isLoaded() { return (houseRegion != null && houseRegion.isActive()) || (dungeonRegion != null && dungeonRegion.isActive()); } diff --git a/Server/src/main/content/global/skill/construction/Room.java b/Server/src/main/content/global/skill/construction/Room.java index 508fa6370..1dbbaecb7 100644 --- a/Server/src/main/content/global/skill/construction/Room.java +++ b/Server/src/main/content/global/skill/construction/Room.java @@ -149,7 +149,7 @@ public final class Room { } } } - if (rotation != Direction.NORTH && chunk.getRotation() == 0) { + if (rotation != Direction.NORTH && chunk.getRotation() == 0) { //TODO: it is absolutely insane that this is using Direction.NORTH and such rather than RegionChunk.NORTH_ROTATION and such. chunk.rotate(rotation); } if (!house.isBuildingMode()) { diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt index 301fc6799..e9c3edcad 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt @@ -214,11 +214,11 @@ class WoodcuttingListener : InteractionListener { player.animate(SkillingTool.getHatchet(player).animation) val playersAroundMe: List = RegionManager.getLocalPlayers(player.location, 2) .stream() - .filter { p -> p.name != player.name } + .filter { p -> p != player } .toList() val soundIndex = RandomFunction.random(0, woodcuttingSounds.size) - for (player in playersAroundMe) { - playAudio(player, woodcuttingSounds[soundIndex]) + for (p in playersAroundMe) { + playAudio(p, woodcuttingSounds[soundIndex]) } } } diff --git a/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java b/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java index 0d7b1cfa1..a9c95ab5e 100644 --- a/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java +++ b/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java @@ -68,7 +68,7 @@ public final class AncientTeleportPlugin extends MagicSpell { return false; } homeTeleport((Player) entity, Location.create(3087, 3495, 0)); - entity.dispatch(new SpellCastEvent(SpellBook.ANCIENT, getSpellId(), target)); + entity.dispatch(new SpellCastEvent(SpellBook.ANCIENT, getSpellId(), target)); } else if (entity.getTeleporter().send(location.transform(0, RandomFunction.random(3), 0), TeleportType.ANCIENT)) { if (!super.meetsRequirements(entity, true, true)) { entity.getTeleporter().getCurrentTeleport().stop(); diff --git a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java index 501f0f0dd..611737fd1 100644 --- a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java +++ b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java @@ -17,8 +17,6 @@ import static core.api.ContentAPIKt.getAttribute; */ @Initializable public final class DraynorBankGuard extends DialoguePlugin { - private final static String HAS_SEEN_RECORDING = "draynor-recording"; - /** * Represents the coins item needed to re-watch the recording. */ @@ -58,7 +56,7 @@ public final class DraynorBankGuard extends DialoguePlugin { public boolean handle(int interfaceId, int buttonId) { switch (stage) { case 0: - if (!getAttribute(player, HAS_SEEN_RECORDING, false)) { + if (!getAttribute(player, DBRCutscene.HAS_SEEN_RECORDING, false)) { interpreter.sendOptions("Select an option", "Can I deposit my stuff here?", "That wall doesn't look very good.", "Sorry, I don't want anything."); stage = 1; } else { diff --git a/Server/src/main/core/game/bots/ScriptAPI.kt b/Server/src/main/core/game/bots/ScriptAPI.kt index b2e94e8a7..9b96aec77 100644 --- a/Server/src/main/core/game/bots/ScriptAPI.kt +++ b/Server/src/main/core/game/bots/ScriptAPI.kt @@ -134,7 +134,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNodeFromList(acceptedNames: List, isObject: Boolean): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleEntityList(bot.location.z) + val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedName = acceptedNames) } @@ -147,7 +147,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNode(id: Int, isObject: Boolean): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleEntityList(bot.location.z) + val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedId = id) } @@ -159,7 +159,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNode(entityName: String): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = region.assembleEntityList(bot.location.z) + val list = region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedName = listOf(entityName)) } @@ -172,7 +172,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNode(name: String, isObject: Boolean): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = region.assembleEntityList(bot.location.z) + val list = region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedName = listOf(name)) } diff --git a/Server/src/main/core/game/interaction/MovementPulse.java b/Server/src/main/core/game/interaction/MovementPulse.java index 372ed3b12..de51f1d13 100644 --- a/Server/src/main/core/game/interaction/MovementPulse.java +++ b/Server/src/main/core/game/interaction/MovementPulse.java @@ -240,7 +240,7 @@ public abstract class MovementPulse extends Pulse { private boolean tryInteract() { Location ml = mover.getLocation(); // Allow being within 1 square of moving entities to interact with them. - int radius = destination instanceof Entity && ((Entity)destination).getWalkingQueue().hasPath() ? 1 : 0; + int radius = destination instanceof Entity && ((Entity) destination).getWalkingQueue().hasPath() ? 1 : 0; if (interactLocation == null) return false; boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt index 1150743a4..26f1c9168 100644 --- a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -20,7 +20,12 @@ private fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatSt fun findMultihitTargets(center: Location, attacker: Entity, combatStyle: CombatStyle?): List { val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } - return targets.take(9) + return targets.take(9) //https://runescape.wiki/w/Vesta%27s_spear "the opponent and up to 9 additional targets in a 3x3 area around the player"; https://oldschool.runescape.wiki/w/Ice_Barrage "up to nine targets" +} + +fun findMultihitTargetsForD2h(center: Location, attacker: Entity, combatStyle: CombatStyle?): List { + val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } + return targets.filter { it.location.withinDistance(center, 1) } .take(14) //runescape.wiki/w/Dragon_2h_sword?oldid=859949 "up to 14 enemies in the squares around the player (Only directly in front of and to the sides, it does not attack those diagonal of the player)" } fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: Entity): List { @@ -50,5 +55,5 @@ fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: } targets = targetCandidates.filter { it is NPC || isOwnerOf(it, npcs) } } - return targets.take(9) -} \ No newline at end of file + return targets.take(9) //https://runescape.wiki/w/Chinchompa "up to 9 enemies" +} diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index 301ad724f..19233647d 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -856,7 +856,7 @@ public class Player extends Entity { getZoneMonitor().getZones().clear(); playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); - playerFlags.setLastViewport(new RegionChunk[13][13]); + playerFlags.setLastViewport(new RegionChunk[MapChunkRenderer.BUILD_AREA_SIZE][MapChunkRenderer.BUILD_AREA_SIZE]); renderInfo.getLocalNPCs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); diff --git a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt index f197553bb..7649bb414 100644 --- a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt @@ -151,7 +151,7 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ if (args.size != 1) reject(player, "::removeobject doesn't support arguments") val obj = getObject(player.location) if (obj == null) { - sendMessage(player, "All ten objects on the tile were null.") + sendMessage(player, "All four objects on the tile were null.") return@define } sendMessage(player, "The first object found on the tile was ${obj.id}; it will now be removed.") @@ -161,12 +161,10 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ define("objects", Privilege.STANDARD, "::objects", "Prints a list of all ten sceneries at your current coordinates") { player, args -> if (args.size != 1) reject(player, "::objects doesn't support arguments") val chunk = getRegionChunk(player.location) - val region = RegionManager.forId(player.location.regionId) fun dump(label: String, objects: List) { sendMessage(player, "--- $label ---") val nulls = ArrayList(10) - for (i in 0 until objects.size) { - val o = objects[i] + for ((i, o) in objects.withIndex()) { if (o == null) { nulls.add(i) } else { @@ -174,7 +172,7 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ val r = if (o.isRenderable) "R" else "" val a = if (o.isActive) "A" else "" var props = c + r + a - if (props.length > 0) { + if (props.isNotEmpty()) { props = " *$props" } sendMessage(player, " $i: $o$props") diff --git a/Server/src/main/core/game/system/config/ConfigParser.kt b/Server/src/main/core/game/system/config/ConfigParser.kt index 00c8e72e7..fd88dfdfa 100644 --- a/Server/src/main/core/game/system/config/ConfigParser.kt +++ b/Server/src/main/core/game/system/config/ConfigParser.kt @@ -34,8 +34,8 @@ class ConfigParser : Commands { fun reloadConfigs(callback: () -> Unit) { GlobalScope.launch { RegionManager.apply { r -> - r.addScenery.clear() - r.removeScenery.clear() + r.addSceneries.clear() + r.removeSceneries.clear() } Repository.npcs.toTypedArray().forEach { npc -> diff --git a/Server/src/main/core/game/system/config/ObjectOverrideParser.kt b/Server/src/main/core/game/system/config/ObjectOverrideParser.kt index 68705d7ca..c75840039 100644 --- a/Server/src/main/core/game/system/config/ObjectOverrideParser.kt +++ b/Server/src/main/core/game/system/config/ObjectOverrideParser.kt @@ -45,8 +45,8 @@ class ObjectOverrideParser { val obj = Scenery(id, loc, type, rotation) val region = RegionManager.forId(loc.regionId) when (mode) { - "remove" -> region.removeScenery.add(obj) //type and rotation are currently ignored, but this can be changed in Region.java if needed - "add" -> region.addScenery.add(obj) + "remove" -> region.removeSceneries.add(obj) //type and rotation are currently ignored, but this can be changed in Region.java if needed + "add" -> region.addSceneries.add(obj) else -> log(this::class.java, Log.ERR, "Ignored unknown ObjectOverride mode $mode!") } count++ diff --git a/Server/src/main/core/game/world/map/Region.java b/Server/src/main/core/game/world/map/Region.java index 6524772aa..0a0ca85e4 100644 --- a/Server/src/main/core/game/world/map/Region.java +++ b/Server/src/main/core/game/world/map/Region.java @@ -32,6 +32,21 @@ import static core.api.ContentAPIKt.log; * @author Emperor */ public class Region { + /** + * The number of tiles per region. + */ + public static final int SIZE = 64; + + /** + * The number of chunks per region. + */ + public static final int CHUNKS_SIZE = 8; + + /** + * The number of z levels per x,y coordinate. + */ + public static final int PLANES = 4; + /** * The region x-coordinate. */ @@ -45,7 +60,7 @@ public class Region { /** * The chunks in this region. */ - protected RegionChunk[][][] chunks = new RegionChunk[8][8][4]; + protected RegionChunk[][][] chunks = new RegionChunk[CHUNKS_SIZE][CHUNKS_SIZE][PLANES]; /** * The activity pulse. @@ -105,8 +120,8 @@ public class Region { /** * Any scenery overrides for this region */ - private ArrayList addScenery = new ArrayList<>(); - private ArrayList removeScenery = new ArrayList<>(); + private final ArrayList addSceneries = new ArrayList<>(); + private final ArrayList removeSceneries = new ArrayList<>(); /** * Constructs a new {@code Region} {@code Object}. @@ -117,10 +132,10 @@ public class Region { this.x = x; this.y = y; Location swCorner = getBaseLocation(); - for (x = 0; x < 8; x++) { - for (y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { - Location loc = swCorner.transform(x*8, y*8, z); + for (x = 0; x < CHUNKS_SIZE; x++) { + for (y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { + Location loc = swCorner.transform(x*RegionChunk.SIZE, y*RegionChunk.SIZE, z); chunks[x][y][z] = new RegionChunk(loc, 0); } } @@ -157,9 +172,9 @@ public class Region { */ public void add(RegionZone zone) { regionZones.add(zone); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { for (NPC npc : chunks[x][y][z].getNpcs()) { npc.getZoneMonitor().updateLocation(npc.getLocation()); } @@ -175,9 +190,9 @@ public class Region { public void remove(RegionZone zone) { regionZones.remove(zone); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { for (NPC npc : chunks[x][y][z].getNpcs()) { npc.getZoneMonitor().updateLocation(npc.getLocation()); } @@ -213,9 +228,9 @@ public class Region { if (isViewed()) { return false; } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { if (!chunks[x][y][z].getPlayers().isEmpty()) { return false; } @@ -240,9 +255,9 @@ public class Region { if (!active) { active = true; load(this); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { for (NPC npc : chunks[x][y][z].getNpcs()) { if (npc.isActive()) { Repository.addRenderableNPC(npc); @@ -300,11 +315,11 @@ public class Region { return; } - byte[][][] mapscapeData = new byte[4][64][64]; - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { - r.chunks[x][y][z].getFlags().setLandscape(new boolean[8][8]); + byte[][][] mapscapeData = new byte[PLANES][SIZE][SIZE]; + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { + r.chunks[x][y][z].getFlags().setLandscape(new boolean[RegionChunk.SIZE][RegionChunk.SIZE]); } } } @@ -328,14 +343,14 @@ public class Region { } } MapscapeParser.clipMapscape(r, r.chunks, mapscapeData); - for (Scenery object : r.removeScenery) { + for (Scenery object : r.removeSceneries) { // Get the actual object, not the instance that's kept in the removeScenery array Scenery realObject = RegionManager.getObject(object.getLocation()); //can be extended to take into account type and rotation if needed if (realObject != null) { SceneryBuilder.remove(realObject); } } - for (Scenery object : r.addScenery) { + for (Scenery object : r.addSceneries) { SceneryBuilder.add(object); } } catch (Throwable e) { @@ -353,20 +368,20 @@ public class Region { r.flagActive(); return false; } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { if (!force && !chunks[x][y][z].getPlayers().isEmpty()) { - log(CommunicationInfo.class, Log.ERR, "Players still in region!"); + log(CommunicationInfo.class, Log.ERR, "Players still in region! (region id " + getId() + "; " + chunks[x][y][z].getPlayers().size() + " players on a chunk)"); r.flagActive(); return false; } } } } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { if (!(r instanceof DynamicRegion)) { for (NPC npc : chunks[x][y][z].getNpcs()) { npc.onRegionInactivity(); @@ -552,12 +567,12 @@ public class Region { public List assembleObjectList(int z) { ArrayList list = new ArrayList<>(); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { RegionChunk chunk = chunks[x][y][z]; - for (int offsetX = 0; offsetX < 8; offsetX++) { - for (int offsetY = 0; offsetY < 8; offsetY++) { - for (int i = 0; i < 4; i++) { + for (int offsetX = 0; offsetX < RegionChunk.SIZE; offsetX++) { + for (int offsetY = 0; offsetY < RegionChunk.SIZE; offsetY++) { + for (int i = 0; i < RegionChunk.ARRAY_SIZE; i++) { Scenery object = chunk.getObjects()[offsetX][offsetY][i]; if (object != null) { list.add(object); @@ -572,8 +587,8 @@ public class Region { public List assembleNpcList(int z) { ArrayList list = new ArrayList<>(); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { RegionChunk chunk = chunks[x][y][z]; list.addAll(chunk.getNpcs()); } @@ -583,8 +598,8 @@ public class Region { public List assemblePlayerList(int z) { ArrayList list = new ArrayList<>(); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { RegionChunk chunk = chunks[x][y][z]; list.addAll(chunk.getPlayers()); } @@ -592,7 +607,7 @@ public class Region { return list; } - public List assembleEntityList(int z) { + public List assembleNodeList(int z) { ArrayList list = new ArrayList<>(assembleObjectList(z)); list.addAll(assemblePlayerList(z)); list.addAll(assembleNpcList(z)); @@ -601,7 +616,6 @@ public class Region { /** * Getter for region aggro tolerances. - * @return */ public HashMap getTolerances() { return tolerances; @@ -610,10 +624,10 @@ public class Region { /** * Getters for addScenery and removeScenery. */ - public ArrayList getAddScenery() { - return addScenery; + public ArrayList getAddSceneries() { + return addSceneries; } - public ArrayList getRemoveScenery() { - return removeScenery; + public ArrayList getRemoveSceneries() { + return removeSceneries; } } diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 216d1556a..17f4e7f08 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -19,6 +19,7 @@ import core.game.world.map.build.DynamicRegion; import core.game.world.map.build.LandscapeParser; import core.game.world.update.flag.UpdateFlag; import core.net.packet.IoBuffer; +import org.rs09.consts.Items; import java.util.ArrayList; import java.util.List; @@ -188,22 +189,21 @@ public class RegionChunk { * Adds the scenery to the static and dynamic object lists. You never want this unless you are the landscape-parsing * code. * @param object The object to add. - * @return The slot it was added into. */ - public int addStatDyn(Scenery object, int chunkOffsetX, int chunkOffsetY) { + public void addStatDyn(Scenery object, int chunkOffsetX, int chunkOffsetY) { for (int i = 0; i < ARRAY_SIZE; i++) { Scenery current = statObjects[chunkOffsetX][chunkOffsetY][i]; if (current == null) { statObjects[chunkOffsetX][chunkOffsetY][i] = object; objects[chunkOffsetX][chunkOffsetY][i] = object.transform(object.getId()); //deep copy so that active/renderable flags don't synchronize across multiple copies of e.g. a POH - return i; + return; } if (current.getId() == object.getId()) { // It's possible that we already have this object. One instance of this was found at 1906, 5082, 0, // where our cache has more than one copy of the same [Scenery 15349, [1906, 5082, 0], type=22, rot=1] // object. Since authentically, the engine can only support one of the same type of object per tile, // if the ID matches we can be confident that this is a duplicate. - return i; + return; } } throw new IllegalStateException("RC addStatDyn insufficient array length for storing object " + object); @@ -249,8 +249,7 @@ public class RegionChunk { */ public void addPlayer(Player player) { players.add(player); - Region region = getCurrentBase().getRegion(); - region.flagActive(); + currentBase.getRegion().flagActive(); } /** @@ -282,8 +281,7 @@ public class RegionChunk { */ public void removePlayer(Player player) { players.remove(player); - Region region = getCurrentBase().getRegion(); - region.checkInactive(); + currentBase.getRegion().checkInactive(); } /** @@ -318,8 +316,8 @@ public class RegionChunk { */ public List assembleObjectList() { ArrayList list = new ArrayList<>(ARRAY_SIZE); - for (int offsetX = 0; offsetX < 8; offsetX++) { - for (int offsetY = 0; offsetY < 8; offsetY++) { + for (int offsetX = 0; offsetX < SIZE; offsetX++) { + for (int offsetY = 0; offsetY < SIZE; offsetY++) { for (int i = 0; i < ARRAY_SIZE; i++) { Scenery object = objects[offsetX][offsetY][i]; if (object != null) { @@ -331,12 +329,6 @@ public class RegionChunk { return list; } - public List getEntities() { - List entities = new ArrayList<>(assembleObjectList()); - entities.addAll(npcs); - return entities; - } - /** * Gets the players. * @return The players. @@ -424,7 +416,7 @@ public class RegionChunk { } public ArrayList drawItems(List items, Player player) { - ArrayList totalItems = items != null ? new ArrayList(items) : new ArrayList(); + ArrayList totalItems = items != null ? new ArrayList<>(items) : new ArrayList(); if (player.getAttribute("chunkdraw", false)) { Location l = currentBase; @@ -436,7 +428,7 @@ public class RegionChunk { else if (x == 0 || x == SIZE - 1) add = true; if (add) - totalItems.add(new GroundItem(new Item(13444), l.transform(x, y, 0), player)); + totalItems.add(new GroundItem(new Item(Items.ABYSSAL_WHIP_13444), l.transform(x, y, 0), player)); } } } @@ -461,7 +453,7 @@ public class RegionChunk { add = true; if (add) - totalItems.add(new GroundItem(new Item(13444), l.transform(x,y,0), player)); + totalItems.add(new GroundItem(new Item(Items.ABYSSAL_WHIP_13444), l.transform(x,y,0), player)); } } @@ -502,7 +494,7 @@ public class RegionChunk { */ public List getItems() { if (items == null) { - items = new ArrayList(); + items = new ArrayList<>(); } return items; } @@ -555,7 +547,7 @@ public class RegionChunk { * Gets the objects index for the given object id and/or scenery type. * @param x The x-coordinate on the region chunk. * @param y The y-coordinate on the region chunk. - * @param objectId The object id. + * @param objectId The object id. -1 if any. * @param type The scenery type. */ public int getIndex(int x, int y, int objectId, int type) { @@ -569,7 +561,6 @@ public class RegionChunk { return i; } else { if (o.getId() == objectId) { - // TODO: what if there are multiple instances of the same object? Hopefully this is only a theoretical possibility in this game return i; } } @@ -654,8 +645,8 @@ public class RegionChunk { * @param from The region plane to get the new clipping flags from. */ public void rebuildClippingFlags(RegionChunk from) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { // Import the landscape flags from the template chunk to the new chunk flags.getLandscape()[x][y] = from.getFlags().getLandscape()[x][y]; projectileFlags.getLandscape()[x][y] = from.getProjectileFlags().getLandscape()[x][y]; @@ -670,6 +661,15 @@ public class RegionChunk { } } + /** + * Rotation consts. Greg loves these :) + */ + private static int NORTH_ROTATION = 0; + private static int EAST_ROTATION = 1; + private static int SOUTH_ROTATION = 2; + private static int WEST_ROTATION = 2; + private static int NUMBER_OF_CARDINAL_ROTATIONS = 4; + /** * Rotates the chunk. * @param direction The direction. @@ -692,22 +692,22 @@ public class RegionChunk { } } clear(); - switch(direction) { - case NORTH: rotation = 0; break; - case EAST: rotation = 1; break; - case SOUTH: rotation = 2; break; - case WEST: rotation = 3; break; - default: rotation = (direction.toInteger() + (direction.toInteger() % 2 == 0 ? 2 : 0)) % 4; + switch (direction) { + case NORTH: rotation = NORTH_ROTATION; break; + case EAST: rotation = EAST_ROTATION; break; + case SOUTH: rotation = SOUTH_ROTATION; break; + case WEST: rotation = WEST_ROTATION; break; + default: rotation = (direction.toInteger() + (direction.toInteger() % 2 == 0 ? 2 : 0)) % NUMBER_OF_CARDINAL_ROTATIONS; log(this.getClass(), Log.ERR, "Attempted to rotate a chunk in a non-cardinal direction - using fallback rotation code. This should be investigated!"); break; }; - for (int i = 0; i < ARRAY_SIZE; i++) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + for (int i = 0; i < ARRAY_SIZE; i++) { Scenery object = copy[x][y][i]; if (object != null) { int[] pos = getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation); - Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); + Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % NUMBER_OF_CARDINAL_ROTATIONS, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); if (object instanceof Constructed) { obj = obj.asConstructed(); } @@ -740,12 +740,12 @@ public class RegionChunk { return new int[] { x, y }; } if (chunkRotation == 1) { - return new int[] { y, 7 - x - (sizeX - 1) }; + return new int[] { y, (SIZE-1) - x - (sizeX - 1) }; } if (chunkRotation == 2) { - return new int[] { 7 - x - (sizeX - 1), 7 - y - (sizeY - 1) }; + return new int[] { (SIZE-1) - x - (sizeX - 1), 7 - y - (sizeY - 1) }; } - return new int[] { 7 - y - (sizeY - 1), x }; + return new int[] { (SIZE-1) - y - (sizeY - 1), x }; } public ChunkFlags getFlags() { diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index d123088dd..aca27af9f 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -25,7 +25,7 @@ object RegionManager { @JvmStatic val CLIPPING_FLAGS = HashMap>() @JvmStatic val PROJECTILE_FLAGS = HashMap>() - val LOCK = ReentrantLock() + private val LOCK = ReentrantLock() /** * Gets the region for the given region id. @@ -378,12 +378,10 @@ object RegionManager { } } is NPC -> { - if (src != null) { - src.chunk.remove(entity) - } + src?.chunk?.remove(entity) dst.chunk.add(entity) } - else -> throw IllegalStateException("Tried to move an Entity that was neither Player nor NPC") + else -> log(this::class.java, Log.ERR, "Tried to move an Entity that was neither Player nor NPC, but $entity of class ${entity.javaClass}! It tried to move from $src to $dst.") } } entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint) @@ -393,7 +391,6 @@ object RegionManager { * Gets local entities. You never call the below function directly (it's inlined); instead, you use one of the typed helpers defined directly below this function. * @param location the location. * @param distance the distance. - * @param maximum the maximum number of entities to return. * @return the list. */ private inline fun getLocalEntitiesOfType(location: Location, distance: Int): List { @@ -402,10 +399,10 @@ object RegionManager { for (cy in (location.absChunkY - 8)..(location.absChunkY + 8)) { val chunk = Location(cx shl 3, cy shl 3, location.z).chunk if (T::class.java.isAssignableFrom(Player::class.java)) { - entities.addAll(chunk.players as Collection) + entities.addAll(chunk.players.filterIsInstance()) } if (T::class.java.isAssignableFrom(NPC::class.java)) { - entities.addAll(chunk.npcs as Collection) + entities.addAll(chunk.npcs.filterIsInstance()) } } } diff --git a/Server/src/main/core/game/world/map/build/DynamicRegion.java b/Server/src/main/core/game/world/map/build/DynamicRegion.java index c1a7ac7de..96671133a 100644 --- a/Server/src/main/core/game/world/map/build/DynamicRegion.java +++ b/Server/src/main/core/game/world/map/build/DynamicRegion.java @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; - /** * Represents a dynamically constructed region. * @@ -69,9 +68,9 @@ public final class DynamicRegion extends Region { super(x, y); this.regionId = regionId; // Reset any stale flags at this region's chunk coordinates - for (int chunkX = 0; chunkX < 8; chunkX++) { - for (int chunkY = 0; chunkY < 8; chunkY++) { - for (int cz = 0; cz < 4; cz++) { + for (int chunkX = 0; chunkX < CHUNKS_SIZE; chunkX++) { + for (int chunkY = 0; chunkY < CHUNKS_SIZE; chunkY++) { + for (int cz = 0; cz < Region.PLANES; cz++) { RegionChunk chunk = chunks[chunkX][chunkY][cz]; for (int chunkOffsetX = 0; chunkOffsetX < 8; chunkOffsetX++) { for (int chunkOffsetY = 0; chunkOffsetY < 8; chunkOffsetY++) { @@ -98,7 +97,7 @@ public final class DynamicRegion extends Region { public static DynamicRegion create(int regionId) { int x = (regionId >> 8) << 6; int y = (regionId & 0xFF) << 6; - return create(new ZoneBorders(x, y, x + 64, y + 64))[0]; + return create(new ZoneBorders(x, y, x + SIZE, y + SIZE))[0]; } /** @@ -112,7 +111,7 @@ public final class DynamicRegion extends Region { int y = (regionOne & 0xFF) << 6; int x1 = (regionTwo >> 8) << 6; int y1 = (regionTwo & 0xFF) << 6; - return create(new ZoneBorders(x, y, x1 + 64, y1 + 64))[0]; + return create(new ZoneBorders(x, y, x1 + SIZE, y1 + SIZE))[0]; } /** @@ -123,7 +122,6 @@ public final class DynamicRegion extends Region { public static DynamicRegion[] create(ZoneBorders copy) { int baseX = copy.getSouthWestX() >> 6; int baseY = copy.getSouthWestY() >> 6; - ZoneBorders border = findZoneBorders((copy.getNorthEastX() - copy.getSouthWestX()) >> 3, (copy.getNorthEastY() - copy.getSouthWestY()) >> 3); RESERVED_AREAS.add(border); Location l = Location.create(border.getSouthWestX(), border.getSouthWestY(), 0); @@ -139,7 +137,7 @@ public final class DynamicRegion extends Region { } } for (Region r : regions) { - for (int z = 0; z < 4; z++) { + for (int z = 0; z < PLANES; z++) { for (Player player : r.assemblePlayerList(z)) { if (player != null) { player.updateSceneGraph(false); @@ -174,11 +172,11 @@ public final class DynamicRegion extends Region { int count = 0; int width = (sizeX >> 3) << 6; int height = (sizeY >> 3) << 6; - if (width < 64) { - width = 64; + if (width < SIZE) { + width = SIZE; } - if (height < 64) { - height = 64; + if (height < SIZE) { + height = SIZE; } while (true) { int endX = x + width; @@ -195,10 +193,10 @@ public final class DynamicRegion extends Region { return new ZoneBorders(x, y, endX, endY); } if (++count % 15 == 0) { - y += 64; + y += SIZE; x = 0; } else { - x += 64; + x += SIZE; } } } @@ -219,7 +217,7 @@ public final class DynamicRegion extends Region { for (int offsetY = 0; offsetY < 8; offsetY++) { int x = regionX + (offsetX << 3); int y = regionY + (offsetY << 3); - for (int plane = 0; plane < 4; plane++) { + for (int plane = 0; plane < PLANES; plane++) { RegionChunk c = base.getChunks()[offsetX][offsetY][plane]; if (c == null) { c = new RegionChunk(Location.create(0, 0, 0), 0); @@ -319,9 +317,9 @@ public final class DynamicRegion extends Region { if (!super.flagInactive(force)) { return false; } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { RegionChunk chunk = chunks[x][y][z]; for (NPC npc : chunk.getNpcs()) { npc.clear(); diff --git a/Server/src/main/core/game/world/map/build/MapscapeParser.java b/Server/src/main/core/game/world/map/build/MapscapeParser.java index 567b308cb..16866d653 100644 --- a/Server/src/main/core/game/world/map/build/MapscapeParser.java +++ b/Server/src/main/core/game/world/map/build/MapscapeParser.java @@ -23,8 +23,8 @@ public final class MapscapeParser { } // The cache is packed by region, so we need to parse it along the local-x/y coordinates for (int z = 0; z < 4; z++) { - for (int localX = 0; localX < 64; localX++) { - for (int localY = 0; localY < 64; localY++) { + for (int localX = 0; localX < Region.SIZE; localX++) { + for (int localY = 0; localY < Region.SIZE; localY++) { int chunkX = localX >> 3; int chunkY = localY >> 3; int chunkOffsetX = localX & 7; @@ -33,7 +33,7 @@ public final class MapscapeParser { boolean[][] landscape; if (chunk == null) { // Still need to consume the buffer data even for null chunks - landscape = new boolean[8][8]; + landscape = new boolean[RegionChunk.SIZE][RegionChunk.SIZE]; } else { landscape = chunk.getFlags().getLandscape(); } @@ -71,15 +71,15 @@ public final class MapscapeParser { * @param mapscape The mapscape. */ public static void clipMapscape(Region r, RegionChunk[][][] chunks, byte[][][] mapscape) { - for (int z = 0; z < 4; z++) { - for (int chunkX = 0; chunkX < 8; chunkX++) { - for (int chunkY = 0; chunkY < 8; chunkY++) { + for (int z = 0; z < Region.PLANES; z++) { + for (int chunkX = 0; chunkX < RegionChunk.SIZE; chunkX++) { + for (int chunkY = 0; chunkY < RegionChunk.SIZE; chunkY++) { RegionChunk chunk = chunks[chunkX][chunkY][z]; - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < RegionChunk.SIZE; x++) { + for (int y = 0; y < RegionChunk.SIZE; y++) { chunk.getFlags().flagEmptyTile(x, y); - int chunkOffsetX = chunkX*8 + x; - int chunkOffsetY = chunkY*8 + y; + int chunkOffsetX = chunkX*RegionChunk.SIZE + x; + int chunkOffsetY = chunkY*RegionChunk.SIZE + y; if ((mapscape[z][chunkOffsetX][chunkOffsetY] & 0x1) == 1) { int plane = z; if ((mapscape[1][chunkOffsetX][chunkOffsetY] & 0x2) == 2) { diff --git a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java index 56352e7b6..be5f59b64 100644 --- a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java +++ b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java @@ -64,11 +64,6 @@ public class ModeratorZone extends MapZone { return true; } - @Override - public boolean interact(Entity entity, Node target, Option option) { - return super.interact(entity, target, option); - } - @Override public void configure() { register(new ZoneBorders(2840, 5204, 2853, 5224)); diff --git a/Server/src/main/core/game/world/update/ChunkDirtyListener.kt b/Server/src/main/core/game/world/update/ChunkDirtyListener.kt index 668c73ce7..38fba5192 100644 --- a/Server/src/main/core/game/world/update/ChunkDirtyListener.kt +++ b/Server/src/main/core/game/world/update/ChunkDirtyListener.kt @@ -1,7 +1,22 @@ package core.game.world.update import core.game.world.map.RegionChunk +import java.util.Collections +import java.util.IdentityHashMap +object ChunkUpdateTracker : ChunkDirtyListener { + private val dirty = Collections.newSetFromMap(IdentityHashMap()) + + override fun onFlagged(chunk: RegionChunk) { + dirty.add(chunk) + } + + /** Resets flags on exactly the chunks flagged this tick. Must run after all per-player flushes. */ + fun resetAll() { + dirty.forEach { it.resetUpdateFlags() } + dirty.clear() + } +} fun interface ChunkDirtyListener { fun onFlagged(chunk: RegionChunk) -} +} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt b/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt deleted file mode 100644 index 3db33d592..000000000 --- a/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt +++ /dev/null @@ -1,19 +0,0 @@ -package core.game.world.update - -import core.game.world.map.RegionChunk -import java.util.Collections -import java.util.IdentityHashMap - -object ChunkUpdateTracker : ChunkDirtyListener { - private val dirty = Collections.newSetFromMap(IdentityHashMap()) - - override fun onFlagged(chunk: RegionChunk) { - dirty.add(chunk) - } - - /** Resets flags on exactly the chunks flagged this tick. Must run after all per-player flushes. */ - fun resetAll() { - dirty.forEach { it.resetUpdateFlags() } - dirty.clear() - } -} diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 883dd0d86..22fd11b8d 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -3,7 +3,6 @@ package core.game.world.update import core.game.node.entity.player.Player import core.game.world.map.Location import core.game.world.map.RegionChunk -import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk @@ -14,7 +13,8 @@ import java.util.* * @author Emperor */ object MapChunkRenderer { - const val buildAreaDepth = 6 + const val BUILD_AREA_DEPTH = 6 + const val BUILD_AREA_SIZE = 2*BUILD_AREA_DEPTH + 1 /** * Sends the map chunk rendering packet. @@ -23,8 +23,8 @@ object MapChunkRenderer { @JvmStatic fun render(player: Player) { val last = player.playerFlags.lastViewport - val updated: MutableList = ArrayList() - val current: MutableList> = ArrayList() + val updated: ArrayList = ArrayList() + val current: ArrayList> = ArrayList() // Center the build area on the loaded scene anchor (lastSceneGraph), NOT the live player position. // The client's 13x13 build area is anchored at lastSceneGraph; addressing chunks relative to it keeps @@ -33,9 +33,9 @@ object MapChunkRenderer { // pushes the viewport edge to drift+6 chunks from the anchor, off-window, so edge items never render. val anchor = player.playerFlags.lastSceneGraph ?: player.location val center = Location.create(anchor.x, anchor.y, player.location.z) - for (dcx in -buildAreaDepth..+buildAreaDepth) { + for (dcx in -BUILD_AREA_DEPTH..BUILD_AREA_DEPTH) { val addX = ArrayList() - for (dcy in -buildAreaDepth..+buildAreaDepth) { + for (dcy in -BUILD_AREA_DEPTH..BUILD_AREA_DEPTH) { val newloc = center.transform(dcx * 8, dcy * 8, 0) addX.add(newloc.chunk) } diff --git a/Server/src/main/core/game/world/update/NPCRenderer.kt b/Server/src/main/core/game/world/update/NPCRenderer.kt index 026c8860f..01997e849 100644 --- a/Server/src/main/core/game/world/update/NPCRenderer.kt +++ b/Server/src/main/core/game/world/update/NPCRenderer.kt @@ -6,6 +6,7 @@ import core.game.world.map.RegionManager import core.net.packet.IoBuffer import core.net.packet.PacketHeader import core.game.world.GameWorld +import core.game.world.map.MapDistance import java.nio.ByteBuffer import java.util.* @@ -30,7 +31,7 @@ object NPCRenderer { val it: Iterator = localNPCs.iterator() while (it.hasNext()) { val npc = it.next() - val withinDistance = player.location.withinDistance(npc.location, 15) + val withinDistance = player.location.withinDistance(npc.location, MapDistance.RENDERING.distance) if (npc.isHidden(player) || !withinDistance || npc.properties.isTeleporting) { buffer.putBits(1, 1).putBits(2, 3) toRemove.add(npc) @@ -51,7 +52,7 @@ object NPCRenderer { } } localNPCs.removeAll(toRemove) - for (npc in RegionManager.getLocalNPCs(player.location, 15)) { + for (npc in RegionManager.getLocalNPCs(player.location, MapDistance.RENDERING.distance)) { if (localNPCs.size >= 255) { break } diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags.java b/Server/src/main/core/game/world/update/flag/PlayerFlags.java index 41d0cb441..2b9ea7c97 100644 --- a/Server/src/main/core/game/world/update/flag/PlayerFlags.java +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags.java @@ -2,6 +2,7 @@ package core.game.world.update.flag; import core.game.world.map.Location; import core.game.world.map.RegionChunk; +import core.game.world.update.MapChunkRenderer; /** * A class holding a player's updating flags. @@ -17,7 +18,7 @@ public final class PlayerFlags { /** * The last viewport. */ - private RegionChunk[][] lastViewport = new RegionChunk[13][13]; + private RegionChunk[][] lastViewport = new RegionChunk[MapChunkRenderer.BUILD_AREA_SIZE][MapChunkRenderer.BUILD_AREA_SIZE]; /** * The location the player was standing on when last scene graph update diff --git a/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt index 9482068c7..c10d937f2 100644 --- a/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt +++ b/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt @@ -69,4 +69,4 @@ class SnowStormHolidayRandomNPC : HolidayRandomEventNPC(NPCs.SNOW_6740) { override fun talkTo(npc: NPC) { } -} +} \ No newline at end of file diff --git a/Server/src/main/core/net/packet/out/BuildDynamicScene.java b/Server/src/main/core/net/packet/out/BuildDynamicScene.java index f9719651f..d8fba5d7a 100644 --- a/Server/src/main/core/net/packet/out/BuildDynamicScene.java +++ b/Server/src/main/core/net/packet/out/BuildDynamicScene.java @@ -5,6 +5,7 @@ import core.game.world.map.Region; import core.game.world.map.RegionChunk; import core.game.world.map.RegionManager; import core.game.world.map.build.DynamicRegion; +import core.game.world.update.MapChunkRenderer; import core.net.packet.IoBuffer; import core.net.packet.OutgoingPacket; import core.net.packet.PacketHeader; @@ -29,12 +30,12 @@ public final class BuildDynamicScene implements OutgoingPacket> 3) << 8 | (y >> 3)); if (r instanceof DynamicRegion) { chunks[x - baseX][y - baseY][z] = r.getChunks()[x - (r.getX() << 3)][y - (r.getY() << 3)][z]; @@ -42,9 +43,9 @@ public final class BuildDynamicScene implements OutgoingPacket { - static final int buildAreaDepthInTiles = (2*MapChunkRenderer.buildAreaDepth+1) * 8; + static final int buildAreaDepthInTiles = (2*MapChunkRenderer.BUILD_AREA_DEPTH +1) * 8; @Override public void send(ClearChunkContext context) { diff --git a/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt b/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt index 870d1b265..8926443f1 100644 --- a/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt +++ b/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt @@ -242,4 +242,4 @@ class BlastFurnaceAreaTests { BlastFurnaceListeners().defineListeners() } } -} +} \ No newline at end of file From da4f3acf186bd2acf7d0ca00982bd2b6994841bd Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 28 Jul 2026 21:06:19 +0200 Subject: [PATCH 83/94] One more magic number --- Server/src/main/core/net/packet/out/ClearRegionChunk.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/src/main/core/net/packet/out/ClearRegionChunk.java b/Server/src/main/core/net/packet/out/ClearRegionChunk.java index c6ff4153d..29821c568 100644 --- a/Server/src/main/core/net/packet/out/ClearRegionChunk.java +++ b/Server/src/main/core/net/packet/out/ClearRegionChunk.java @@ -1,6 +1,7 @@ package core.net.packet.out; import core.game.world.map.Location; +import core.game.world.map.RegionChunk; import core.game.world.update.MapChunkRenderer; import core.net.packet.IoBuffer; import core.net.packet.OutgoingPacket; @@ -11,7 +12,7 @@ import core.net.packet.context.ClearChunkContext; * @author Emperor */ public final class ClearRegionChunk implements OutgoingPacket { - static final int buildAreaDepthInTiles = (2*MapChunkRenderer.BUILD_AREA_DEPTH +1) * 8; + static final int buildAreaDepthInTiles = MapChunkRenderer.BUILD_AREA_SIZE * RegionChunk.SIZE; @Override public void send(ClearChunkContext context) { @@ -24,5 +25,4 @@ public final class ClearRegionChunk implements OutgoingPacket context.getPlayer().getSession().write(buffer); } } - } From fb326cf08d2b038d54f3390a50d92b6a1a563d4e Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 29 Jul 2026 22:47:37 +0200 Subject: [PATCH 84/94] fix oopsies. These don't require retesting since they're just restoring code that was already there. --- .../src/main/content/global/skill/magic/lunar/HealSpell.java | 2 +- .../content/global/skill/magic/lunar/StatRestoreSpell.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java index 7059385aa..228f92af2 100644 --- a/Server/src/main/content/global/skill/magic/lunar/HealSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/HealSpell.java @@ -112,7 +112,7 @@ public final class HealSpell extends MagicSpell { playGlobalAudio(o.getLocation(), Sounds.LUNAR_HEAL_OTHER_INDIVIDUAL_2892); o.graphics(GRAPHICS); } else { - if (!super.meetsRequirements(player, true, true)) { + if (!super.meetsRequirements(player, true, true)) { return false; } int percentage = (int) Math.ceil(player.getSkills().getLifepoints() * 0.75); diff --git a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java index 7915590ba..bd05e85c9 100644 --- a/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java +++ b/Server/src/main/content/global/skill/magic/lunar/StatRestoreSpell.java @@ -45,7 +45,10 @@ public class StatRestoreSpell extends MagicSpell { final Player player = ((Player) entity); Item item = ((Item) target); player.getInterfaceManager().setViewedTab(6); - + if (Consumables.getConsumableById(item.getId()) == null) { + player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); + return false; + } final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable(); if (potion == null) { player.getPacketDispatch().sendMessage("You can only cast this spell on a potion."); From a3323c5778918cc829b52e4bd980bf2a8050946f Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 29 Jul 2026 22:51:23 +0200 Subject: [PATCH 85/94] make greg not yell at me --- Server/src/main/core/net/packet/out/ClearRegionChunk.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/src/main/core/net/packet/out/ClearRegionChunk.java b/Server/src/main/core/net/packet/out/ClearRegionChunk.java index 29821c568..8a46171b7 100644 --- a/Server/src/main/core/net/packet/out/ClearRegionChunk.java +++ b/Server/src/main/core/net/packet/out/ClearRegionChunk.java @@ -12,14 +12,14 @@ import core.net.packet.context.ClearChunkContext; * @author Emperor */ public final class ClearRegionChunk implements OutgoingPacket { - static final int buildAreaDepthInTiles = MapChunkRenderer.BUILD_AREA_SIZE * RegionChunk.SIZE; + static final int BUILD_AREA_DEPTH_IN_TILES = MapChunkRenderer.BUILD_AREA_SIZE * RegionChunk.SIZE; @Override public void send(ClearChunkContext context) { Location l = context.getPlayer().getPlayerFlags().getLastSceneGraph(); int x = context.getChunk().getCurrentBase().getSceneX(l); int y = context.getChunk().getCurrentBase().getSceneY(l); - if (x >= 0 && y >= 0 && x < buildAreaDepthInTiles && y < buildAreaDepthInTiles) { + if (x >= 0 && y >= 0 && x < BUILD_AREA_DEPTH_IN_TILES && y < BUILD_AREA_DEPTH_IN_TILES) { IoBuffer buffer = new IoBuffer(112).put(x).putC(y); buffer.cypherOpcode(context.getPlayer().getSession().getIsaacPair().getOutput()); context.getPlayer().getSession().write(buffer); From 883eac2015482aa92aa2059a1ee3b85645659737 Mon Sep 17 00:00:00 2001 From: Player Name Date: Thu, 30 Jul 2026 14:25:33 +0200 Subject: [PATCH 86/94] Fix totally busted getScenery --- .../karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java | 6 +++--- Server/src/main/core/api/ContentAPI.kt | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java b/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java index ea8c0cd6b..893a2bb5e 100644 --- a/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java +++ b/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java @@ -370,7 +370,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { } int size = (LOBBY_PLAYERS.size() + WAR_PLAYERS.size()) - 1; if (!WAR_PLAYERS.isEmpty()) { - setVarp(WAR_PLAYERS.get(0), 560, size); + setVarp(WAR_PLAYERS.get(0), 560, size); } for (Iterator it = LOBBY_PLAYERS.iterator(); it.hasNext();) { Player p = it.next(); @@ -382,7 +382,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { } p.getSkullManager().setSkullCheckDisabled(true); p.getSkullManager().setWilderness(true); - setVarp(p, 560, size); + setVarp(p, 560, size); p.getProperties().setTeleportLocation(getZoneDestination()); p.getInteraction().set(Option._P_ATTACK); tokkulAmount += p.getProperties().getCurrentCombatLevel(); @@ -464,7 +464,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { */ public static void sendPlayersRemaining(int value) { for (Player p : WAR_PLAYERS) { - setVarp(p, 560, value); + setVarp(p, 560, value); } } diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 904f5cb6c..7e1d6f813 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -1078,10 +1078,9 @@ fun findNPC(id: Int): NPC? { * @param x the X coordinate to use * @param y the Y coordinate to use * @param z the Z coordinate to use - * @param type the scenery type, -1 if any */ -fun getScenery(x: Int, y: Int, z: Int, type: Int = -1): Scenery? { - return RegionManager.getObject(z, x, y, type, -1) +fun getScenery(x: Int, y: Int, z: Int): Scenery? { + return RegionManager.getObject(z, x, y) } /** From 54b894f6e600530e1b2159edaf85ac41750f9b96 Mon Sep 17 00:00:00 2001 From: Player Name Date: Thu, 30 Jul 2026 14:29:43 +0200 Subject: [PATCH 87/94] Correct order of getObject arguments and add default args for at least the Kotlin callers --- .../skill/agility/brimhaven/BrimhavenArena.java | 13 ++++++------- .../decoration/chapel/BoneOfferPlugin.java | 9 ++++----- .../handlers/wguild/cyclopes/CyclopesRoom.java | 3 +-- .../FortressGuardDialogue.java | 2 +- .../handlers/gwd/GodwarsEntranceHandler.java | 2 +- .../quest/tearsofguthix/TearsOfGuthixMinigame.kt | 2 +- Server/src/main/core/api/ContentAPI.kt | 2 +- Server/src/main/core/game/bots/AIPlayer.java | 16 ++++++++-------- .../game/global/action/DoorActionHandler.java | 2 +- .../core/game/system/command/MapDumpCommand.kt | 3 +-- .../main/core/game/world/map/RegionManager.kt | 12 ++++++------ .../src/main/core/net/packet/PacketProcessor.kt | 6 +++--- 12 files changed, 34 insertions(+), 38 deletions(-) diff --git a/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java b/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java index e70f39fa8..0bae1f57c 100644 --- a/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java +++ b/Server/src/main/content/global/skill/agility/brimhaven/BrimhavenArena.java @@ -19,7 +19,6 @@ import core.game.world.GameWorld; import core.game.world.map.*; import core.game.world.map.zone.MapZone; import core.game.world.map.zone.ZoneBuilder; -import core.game.world.repository.Repository; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; import core.plugin.Plugin; @@ -251,19 +250,19 @@ public final class BrimhavenArena extends MapZone implements Plugin { if (GameWorld.getTicks() % ticks == 0) { sawBladeActive = !sawBladeActive; if (sawBladeActive) { - Scenery object = RegionManager.getObject(3, 2788, 9579); + Scenery object = RegionManager.getObject(2788, 9579, 3); SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2789, 9579); + object = RegionManager.getObject(2789, 9579, 3); SceneryBuilder.replace(object, object.transform(0), ticks); - object = RegionManager.getObject(3, 2783, 9551); + object = RegionManager.getObject(2783, 9551, 3); SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2783, 9552); + object = RegionManager.getObject(2783, 9552, 3); SceneryBuilder.replace(object, object.transform(0), ticks); - object = RegionManager.getObject(3, 2761, 9584); + object = RegionManager.getObject(2761, 9584, 3); SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks); - object = RegionManager.getObject(3, 2761, 9585); + object = RegionManager.getObject(2761, 9585, 3); SceneryBuilder.replace(object, object.transform(0), ticks); } } diff --git a/Server/src/main/content/global/skill/construction/decoration/chapel/BoneOfferPlugin.java b/Server/src/main/content/global/skill/construction/decoration/chapel/BoneOfferPlugin.java index e681c861d..0ca3bc038 100644 --- a/Server/src/main/content/global/skill/construction/decoration/chapel/BoneOfferPlugin.java +++ b/Server/src/main/content/global/skill/construction/decoration/chapel/BoneOfferPlugin.java @@ -8,7 +8,6 @@ import core.game.node.entity.skill.Skills; import core.game.interaction.NodeUsageEvent; import core.game.interaction.UseWithHandler; import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.audio.Audio; import core.game.node.item.Item; import core.game.node.scenery.Scenery; import core.game.system.task.Pulse; @@ -60,11 +59,11 @@ public class BoneOfferPlugin extends UseWithHandler { Scenery left = null; Scenery right = null; if (event.getUsedWith().asScenery().getRotation() % 2 == 0) { - left = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX() + 3, event.getUsedWith().getLocation().getY()); - right = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX() - 2, event.getUsedWith().getLocation().getY()); + left = RegionManager.getObject(event.getUsedWith().getLocation().getX() + 3, event.getUsedWith().getLocation().getY(), event.getUsedWith().getLocation().getZ()); + right = RegionManager.getObject(event.getUsedWith().getLocation().getX() - 2, event.getUsedWith().getLocation().getY(), event.getUsedWith().getLocation().getZ()); } else { - left = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX(), event.getUsedWith().getLocation().getY() + 3); - right = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX(), event.getUsedWith().getLocation().getY() - 2); + left = RegionManager.getObject(event.getUsedWith().getLocation().getX(), event.getUsedWith().getLocation().getY() + 3, event.getUsedWith().getLocation().getZ()); + right = RegionManager.getObject(event.getUsedWith().getLocation().getX(), event.getUsedWith().getLocation().getY() - 2, event.getUsedWith().getLocation().getZ()); } Bones b = Bones.forId(event.getUsedItem().getId()); if (b != null) { diff --git a/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/cyclopes/CyclopesRoom.java b/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/cyclopes/CyclopesRoom.java index 98111f7c1..829a95099 100644 --- a/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/cyclopes/CyclopesRoom.java +++ b/Server/src/main/content/region/asgarnia/burthorpe/handlers/wguild/cyclopes/CyclopesRoom.java @@ -31,7 +31,6 @@ import core.plugin.Plugin; import core.plugin.ClassScanner; import core.tools.RandomFunction; import kotlin.Unit; -import kotlin.jvm.functions.Function1; import static core.api.ContentAPIKt.clearLogoutListener; import static core.api.ContentAPIKt.registerLogoutListener; @@ -73,7 +72,7 @@ public final class CyclopesRoom extends MapZone implements Plugin { Pathfinder.find(p.getLocation(), Location.create(2847, 3541, 2)).walk(p); p.lock(50); } else { - Scenery object = RegionManager.getObject(2, 2847, 3541); + Scenery object = RegionManager.getObject(2847, 3541, 2); if (object != null && p.getLocation().getX() == 2847 && p.getLocation().getY() == 3541) { DoorActionHandler.handleAutowalkDoor(p, object); leave(p); diff --git a/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java b/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java index 7910ec29c..0f33d69ce 100644 --- a/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java +++ b/Server/src/main/content/region/asgarnia/falador/quest/blackknightsfortress/FortressGuardDialogue.java @@ -200,7 +200,7 @@ public class FortressGuardDialogue extends DialoguePlugin { break; case 54: end(); - DoorActionHandler.handleAutowalkDoor(player, RegionManager.getObject(0, 3020, 3515)); + DoorActionHandler.handleAutowalkDoor(player, RegionManager.getObject(3020, 3515, 0)); List npcs = RegionManager.getLocalNPCs(player.getLocation()); for (NPC npc : npcs) { if (npc.getId() == 179) { diff --git a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodwarsEntranceHandler.java b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodwarsEntranceHandler.java index 8803d9d88..6ec32b53d 100644 --- a/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodwarsEntranceHandler.java +++ b/Server/src/main/content/region/asgarnia/trollheim/handlers/gwd/GodwarsEntranceHandler.java @@ -83,7 +83,7 @@ public final class GodwarsEntranceHandler extends OptionHandler { GameWorld.getPulser().submit(new Pulse(12, player) { @Override public boolean pulse() { - player.getPacketDispatch().sendSceneryAnimation(RegionManager.getObject(0, 2898, 3716), Animation.create(6981)); + player.getPacketDispatch().sendSceneryAnimation(RegionManager.getObject(2898, 3716, 0), Animation.create(6981)); return true; } }); diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt index c6594cb64..ffe8c0b1e 100644 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/tearsofguthix/TearsOfGuthixMinigame.kt @@ -367,7 +367,7 @@ class TearsOfGuthixGlobalTick : TickListener { */ wallStates.forEachIndexed { index, state -> val wallLocation = allWalls[index + 1] - val currentWaterfall = RegionManager.getObject(wallLocation.z, wallLocation.x, wallLocation.y, -1, 4)!! + val currentWaterfall = RegionManager.getObject(wallLocation.x, wallLocation.y, wallLocation.z, -1, 4)!! val newWaterfallId = when (state) { 2 -> { if (index + 1 <= 5) Scenery.GREEN_TEARS_6662 else Scenery.GREEN_TEARS_6666 diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 7e1d6f813..3f5c36f30 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -1080,7 +1080,7 @@ fun findNPC(id: Int): NPC? { * @param z the Z coordinate to use */ fun getScenery(x: Int, y: Int, z: Int): Scenery? { - return RegionManager.getObject(z, x, y) + return RegionManager.getObject(x, y, z) } /** diff --git a/Server/src/main/core/game/bots/AIPlayer.java b/Server/src/main/core/game/bots/AIPlayer.java index 4788417ad..8b575559c 100644 --- a/Server/src/main/core/game/bots/AIPlayer.java +++ b/Server/src/main/core/game/bots/AIPlayer.java @@ -323,19 +323,19 @@ public class AIPlayer extends Player { } for (int x = 0; x < range; x++) { for (int y = 0; y < range - x; y++) { - Node node = RegionManager.getObject(0, meX + x, meY + y); + Node node = RegionManager.getObject(meX + x, meY + y, 0); if (node != null) if (node.getId() == entry) nodes.add(node); - Node node2 = RegionManager.getObject(0, meX + x, meY - y); + Node node2 = RegionManager.getObject(meX + x, meY - y, 0); if (node2 != null) if (node2.getId() == entry) nodes.add(node2); - Node node3 = RegionManager.getObject(0, meX - x, meY + y); + Node node3 = RegionManager.getObject(meX - x, meY + y, 0); if (node3 != null) if (node3.getId() == entry) nodes.add(node3); - Node node4 = RegionManager.getObject(0, meX - x, meY - y); + Node node4 = RegionManager.getObject(meX - x, meY - y, 0); if (node4 != null) if (node4.getId() == entry) nodes.add(node4); @@ -356,19 +356,19 @@ public class AIPlayer extends Player { } for (int x = 0; x < range; x++) { for (int y = 0; y < range - x; y++) { - Node node = RegionManager.getObject(0, meX + x, meY + y); + Node node = RegionManager.getObject(meX + x, meY + y, 0); if (node != null) if (entrys.contains(node.getId())) nodes.add(node); - Node node2 = RegionManager.getObject(0, meX + x, meY - y); + Node node2 = RegionManager.getObject(meX + x, meY - y, 0); if (node2 != null) if (entrys.contains(node2.getId())) nodes.add(node2); - Node node3 = RegionManager.getObject(0, meX - x, meY + y); + Node node3 = RegionManager.getObject(meX - x, meY + y, 0); if (node3 != null) if (entrys.contains(node3.getId())) nodes.add(node3); - Node node4 = RegionManager.getObject(0, meX - x, meY - y); + Node node4 = RegionManager.getObject(meX - x, meY - y, 0); if (node4 != null) if (entrys.contains(node4.getId())) nodes.add(node4); diff --git a/Server/src/main/core/game/global/action/DoorActionHandler.java b/Server/src/main/core/game/global/action/DoorActionHandler.java index fcf0bdab6..2a7ee7959 100644 --- a/Server/src/main/core/game/global/action/DoorActionHandler.java +++ b/Server/src/main/core/game/global/action/DoorActionHandler.java @@ -491,7 +491,7 @@ public final class DoorActionHandler { } private static Scenery getAdjacentDoor(Location location, int type) { - return RegionManager.getObject(location.getZ(), location.getX(), location.getY(), -1, type); + return RegionManager.getObject(location.getX(), location.getY(), location.getZ(), -1, type); } /** diff --git a/Server/src/main/core/game/system/command/MapDumpCommand.kt b/Server/src/main/core/game/system/command/MapDumpCommand.kt index 2743af899..a837ba4a1 100644 --- a/Server/src/main/core/game/system/command/MapDumpCommand.kt +++ b/Server/src/main/core/game/system/command/MapDumpCommand.kt @@ -1,7 +1,6 @@ package core.game.system.command import core.game.node.entity.player.Player -import core.game.system.command.CommandSet import core.game.world.map.Location import core.game.world.map.RegionManager import core.plugin.Initializable @@ -34,7 +33,7 @@ class MapDumpCommand : CommandPlugin() { for (x in 0 until xmax - 1) { for (y in 0 until ymax - 1) { for (z in 0 until zmax - 1) { - val temp = RegionManager.getObject(z, x, y) + val temp = RegionManager.getObject(x, y, z) if (temp != null) { GameObjectMap[Location(x, y, z)] = temp.id } diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index aca27af9f..c1ffac807 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -300,32 +300,32 @@ object RegionManager { */ @JvmStatic fun getObject(l: Location): Scenery? { - return getObject(l.z, l.x, l.y) + return getObject(l.x, l.y, l.z) } /** * Gets the scenery on the current absolute coordinates. - * @param z The height. * @param x The x-coordinate. * @param y The y-coordinate. + * @param z The height. * @return The scenery, or `null` if no object was found. */ @JvmStatic - fun getObject(z: Int, x: Int, y: Int): Scenery? { - return getObject(z, x, y, -1, -1) + fun getObject(x: Int, y: Int, z: Int): Scenery? { + return getObject(x, y, z, -1, -1) } /** * Gets the object on the given absolute coordinates. - * @param z The height. * @param x The x-coordinate. * @param y The y-coordinate. + * @param z The height. * @param objectId The object id. May be -1, which means 'any'. * @param type The scenery type. May be -1, which means 'any'. * @return The scenery, or `null` if no object was found. */ @JvmStatic - fun getObject(z: Int, x: Int, y: Int, objectId: Int, type: Int): Scenery? { + fun getObject(x: Int, y: Int, z: Int, objectId: Int = -1, type: Int = -1): Scenery? { val loc = Location(x, y, z) val region = forId(loc.regionId) Region.load(region) diff --git a/Server/src/main/core/net/packet/PacketProcessor.kt b/Server/src/main/core/net/packet/PacketProcessor.kt index b7c10c50f..b94cb886c 100644 --- a/Server/src/main/core/net/packet/PacketProcessor.kt +++ b/Server/src/main/core/net/packet/PacketProcessor.kt @@ -406,7 +406,7 @@ object PacketProcessor { player = pkt.player child = pkt.child iface = pkt.iface - target = RegionManager.getObject(player.location.z, pkt.x, pkt.y) ?: return sendClearMinimap(player) + target = RegionManager.getObject(pkt.x, pkt.y, player.location.z) ?: return sendClearMinimap(player) targetId = pkt.sceneryId type = SpellListener.OBJECT } @@ -579,7 +579,7 @@ object PacketProcessor { } else if (pkt is Packet.UseWithScenery) { item = pkt.player.inventory[pkt.slot] ?: return sendClearMinimap(pkt.player) - node = RegionManager.getObject(pkt.player.location.z, pkt.x, pkt.y, pkt.sceneryId, -1) ?: return sendClearMinimap(pkt.player) + node = RegionManager.getObject(pkt.x, pkt.y, pkt.player.location.z, pkt.sceneryId, -1) ?: return sendClearMinimap(pkt.player) childNode = node.asScenery().getChild(pkt.player) itemId = pkt.itemId nodeId = node.id @@ -680,7 +680,7 @@ object PacketProcessor { private fun processSceneryAction(pkt: Packet.SceneryAction) { val player = pkt.player - var scenery = RegionManager.getObject(player.location.z, pkt.x, pkt.y, pkt.id, -1) + var scenery = RegionManager.getObject(pkt.x, pkt.y, player.location.z, pkt.id, -1) var objId = pkt.id //what follows is a series of hardcoded crimes against humanity From 45d9af67787a8a88ab9d0cc804b89f5c4bce4e4f Mon Sep 17 00:00:00 2001 From: Player Name Date: Thu, 30 Jul 2026 20:03:25 +0200 Subject: [PATCH 88/94] rotation fix --- Server/src/main/core/game/world/map/RegionChunk.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 17f4e7f08..f8423cb1f 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -667,7 +667,7 @@ public class RegionChunk { private static int NORTH_ROTATION = 0; private static int EAST_ROTATION = 1; private static int SOUTH_ROTATION = 2; - private static int WEST_ROTATION = 2; + private static int WEST_ROTATION = 3; private static int NUMBER_OF_CARDINAL_ROTATIONS = 4; /** From b2f0296630235ab702eb626d205ef4a58eb51ec5 Mon Sep 17 00:00:00 2001 From: Player Name Date: Thu, 30 Jul 2026 20:11:50 +0200 Subject: [PATCH 89/94] make constants final --- Server/src/main/core/game/world/map/RegionChunk.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index f8423cb1f..a252921f0 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -664,11 +664,11 @@ public class RegionChunk { /** * Rotation consts. Greg loves these :) */ - private static int NORTH_ROTATION = 0; - private static int EAST_ROTATION = 1; - private static int SOUTH_ROTATION = 2; - private static int WEST_ROTATION = 3; - private static int NUMBER_OF_CARDINAL_ROTATIONS = 4; + private final static int NORTH_ROTATION = 0; + private final static int EAST_ROTATION = 1; + private final static int SOUTH_ROTATION = 2; + private final static int WEST_ROTATION = 3; + private final static int NUMBER_OF_CARDINAL_ROTATIONS = 4; /** * Rotates the chunk. From bd5d495847099a82b2731a0192989494ecf0324d Mon Sep 17 00:00:00 2001 From: Player Name Date: Thu, 30 Jul 2026 20:54:29 +0200 Subject: [PATCH 90/94] forgot to commit test fix to new getObject arg order --- Server/src/test/kotlin/core/PathfinderTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/test/kotlin/core/PathfinderTests.kt b/Server/src/test/kotlin/core/PathfinderTests.kt index 621bbebc0..c27cdd2f4 100644 --- a/Server/src/test/kotlin/core/PathfinderTests.kt +++ b/Server/src/test/kotlin/core/PathfinderTests.kt @@ -45,7 +45,7 @@ class PathfinderTests { @Test fun movementPulseShouldStopEarlyIfNextToATileOccupiedByTargetObject() { val start = Location.create(2731, 3481) - val dest = RegionManager.getObject(0, 2720, 3475, 1307, -1) + val dest = RegionManager.getObject(2720, 3475, 0, 1307, -1) val p = TestUtils.getMockPlayer("treefindtest") p.location = start p.init() From 09344d4d66e630d6cc3f8dd007426f3d5527f286 Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 31 Jul 2026 16:55:17 +0200 Subject: [PATCH 91/94] fixed a few regressions, fortunately already covered by tests that are to be done anyway --- .../item/equipment/special/SweepSpecialHandler.java | 2 +- Server/src/main/core/game/node/entity/Entity.java | 1 + .../core/game/node/entity/combat/MultihitTargets.kt | 11 ++++------- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index 3c9217d8f..ce7bcd9be 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -96,7 +96,7 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); - List list = findMultihitTargets(vl, entity, null); + List list = findMultihitTargets(vl, entity, CombatStyle.RANGE); //RANGE is correct because halberds are able to attack from a distance for (Entity n : list) { if (n == victim) { continue; diff --git a/Server/src/main/core/game/node/entity/Entity.java b/Server/src/main/core/game/node/entity/Entity.java index 0203fd3e3..ec659429d 100644 --- a/Server/src/main/core/game/node/entity/Entity.java +++ b/Server/src/main/core/game/node/entity/Entity.java @@ -241,6 +241,7 @@ public abstract class Entity extends Node { // In that situation, the NPC never actually got created so it doesn't need to be removed from any chunk. If it had been, however, we do so now. if (this instanceof Player) { location.getChunk().removePlayer(asPlayer()); + location.getRegion().decrementViewAmount(); } if (this instanceof NPC) { location.getChunk().remove(asNpc()); diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt index 26f1c9168..4cbb4b87f 100644 --- a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -8,22 +8,19 @@ import core.game.world.map.Location import core.game.world.map.RegionManager.getLocalEntities import core.game.world.map.zone.impl.WildernessZone -private fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatStyle?, wilderness: Boolean): Boolean { - if (combatStyle == null) { - return true - } +private fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatStyle, wilderness: Boolean): Boolean { if (wilderness) { return WildernessZone.getInstance().continueAttack(attacker, victim, combatStyle, false) } return victim.isAttackable(attacker, combatStyle, false) } -fun findMultihitTargets(center: Location, attacker: Entity, combatStyle: CombatStyle?): List { +fun findMultihitTargets(center: Location, attacker: Entity, combatStyle: CombatStyle): List { val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } return targets.take(9) //https://runescape.wiki/w/Vesta%27s_spear "the opponent and up to 9 additional targets in a 3x3 area around the player"; https://oldschool.runescape.wiki/w/Ice_Barrage "up to nine targets" } -fun findMultihitTargetsForD2h(center: Location, attacker: Entity, combatStyle: CombatStyle?): List { +fun findMultihitTargetsForD2h(center: Location, attacker: Entity, combatStyle: CombatStyle): List { val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } return targets.filter { it.location.withinDistance(center, 1) } .take(14) //runescape.wiki/w/Dragon_2h_sword?oldid=859949 "up to 14 enemies in the squares around the player (Only directly in front of and to the sides, it does not attack those diagonal of the player)" } @@ -39,7 +36,7 @@ fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: } return entity.owner in players && isAttackable(entity.owner, attacker, CombatStyle.RANGE, true) } - targets = targetCandidates.filter { (it is Player && isAttackable(attacker, it, CombatStyle.RANGE, true)) || isFamiliarOf(it, players) } + targets = targetCandidates.filter { (it is Player && isAttackable(it, attacker, CombatStyle.RANGE, true)) || isFamiliarOf(it, players) } } else { val npcs = targetCandidates.filterIsInstance() fun isOwnerOf(entity: Entity, npcs: List): Boolean { From 3d626fac460b702271af26401c3d572c24d14fae Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 31 Jul 2026 22:34:43 +0200 Subject: [PATCH 92/94] wait, this can be ArrayList rather than MutableList, which greg prefers --- .../special/ChinchompaSwingHandler.java | 2 +- .../special/PowerstabSpecialHandler.java | 2 +- .../special/SweepSpecialHandler.java | 14 ++------ .../skill/magic/ancient/BloodSpells.java | 2 +- .../global/skill/magic/ancient/IceSpells.java | 2 +- .../skill/magic/ancient/MiasmicSpells.java | 2 +- .../skill/magic/ancient/ShadowSpells.java | 2 +- .../skill/magic/ancient/SmokeSpells.java | 2 +- .../node/entity/combat/MultihitTargets.kt | 32 ++++++++++++------- .../main/core/game/world/map/RegionManager.kt | 7 ++-- 10 files changed, 35 insertions(+), 32 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java index 73b034e06..fff663592 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/ChinchompaSwingHandler.java @@ -56,7 +56,7 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { } boolean accurate = isAccurateImpact(entity, victim, CombatStyle.RANGE); - List targetCandidates = findMultihitTargetsForChinchompa(victim.getLocation(), entity, victim); + List targetCandidates = findMultihitTargetsForChinchompa(victim, entity); BattleState[] targets = new BattleState[targetCandidates.size()]; int count = 0; for (Entity e : targetCandidates) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index ca7efb145..5498d6a24 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -73,7 +73,7 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargetsForD2h(entity.getLocation(), entity, CombatStyle.MELEE); + List list = findMultihitTargetsForD2h(entity, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index ce7bcd9be..3d34735b8 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -19,7 +19,7 @@ import core.tools.RandomFunction; import org.rs09.consts.Sounds; import static core.api.ContentAPIKt.playGlobalAudio; -import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargetsForDragonHalberd; /** * Handles the Dragon halberd special attack. @@ -96,17 +96,9 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); - List list = findMultihitTargets(vl, entity, CombatStyle.RANGE); //RANGE is correct because halberds are able to attack from a distance + List list = findMultihitTargetsForDragonHalberd(victim, entity); for (Entity n : list) { - if (n == victim) { - continue; - } - if (n.getLocation().equals(vl.transform(dir.getStepY(), dir.getStepX(), 0)) || n.getLocation().equals(vl.transform(-dir.getStepY(), -dir.getStepX(), 0))) { - l.add(new BattleState(entity, n)); - if (l.size() >= 3) { - break; - } - } + l.add(new BattleState(entity, n)); } return l.toArray(new BattleState[l.size()]); } diff --git a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java index 44280fe75..8bb2703fe 100644 --- a/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/BloodSpells.java @@ -121,7 +121,7 @@ public final class BloodSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target, entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java index d854979e4..0cdd2216d 100644 --- a/Server/src/main/content/global/skill/magic/ancient/IceSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/IceSpells.java @@ -146,7 +146,7 @@ public final class IceSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target, entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java index 6cdfe11c7..1353981c3 100644 --- a/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/MiasmicSpells.java @@ -160,7 +160,7 @@ public final class MiasmicSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target, entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java index c8d390dba..2f55e002d 100644 --- a/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/ShadowSpells.java @@ -117,7 +117,7 @@ public final class ShadowSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target, entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java index 187f7249c..c7aab06ec 100644 --- a/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java +++ b/Server/src/main/content/global/skill/magic/ancient/SmokeSpells.java @@ -125,7 +125,7 @@ public final class SmokeSpells extends CombatSpell { return super.getTargets(entity, target); } - List list = MultihitTargetsKt.findMultihitTargets(target.getLocation(), entity, CombatStyle.MAGIC); + List list = MultihitTargetsKt.findMultihitTargets(target, entity, CombatStyle.MAGIC); BattleState[] targets = new BattleState[list.size()]; int index = 0; for (Entity e : list) { diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt index 4cbb4b87f..9901189a0 100644 --- a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -4,7 +4,7 @@ import content.global.skill.summoning.familiar.Familiar 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.Direction.getDirection import core.game.world.map.RegionManager.getLocalEntities import core.game.world.map.zone.impl.WildernessZone @@ -15,20 +15,30 @@ private fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatSt return victim.isAttackable(attacker, combatStyle, false) } -fun findMultihitTargets(center: Location, attacker: Entity, combatStyle: CombatStyle): List { - val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } - return targets.take(9) //https://runescape.wiki/w/Vesta%27s_spear "the opponent and up to 9 additional targets in a 3x3 area around the player"; https://oldschool.runescape.wiki/w/Ice_Barrage "up to nine targets" +fun findMultihitTargets(target: Entity, attacker: Entity, combatStyle: CombatStyle): List { + val targets = getLocalEntities(target.location, 1).filter { it != attacker && it != target && isAttackable(it, attacker, combatStyle, false) } + return listOf(target) + targets.take(9) //https://runescape.wiki/w/Vesta%27s_spear "the opponent and up to 9 additional targets in a 3x3 area around the player"; https://oldschool.runescape.wiki/w/Ice_Barrage "up to nine targets" } -fun findMultihitTargetsForD2h(center: Location, attacker: Entity, combatStyle: CombatStyle): List { - val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } - return targets.filter { it.location.withinDistance(center, 1) } .take(14) //runescape.wiki/w/Dragon_2h_sword?oldid=859949 "up to 14 enemies in the squares around the player (Only directly in front of and to the sides, it does not attack those diagonal of the player)" +fun findMultihitTargetsForDragonHalberd(target: Entity, attacker: Entity): List { + val direction = getDirection(target.location.x - attacker.location.x, target.location.y - attacker.location.y) + val targets = ArrayList() //should not add the victim here + for (delta in listOf(-1, 1)) { + val add = getLocalEntities(target.location.transform(delta * direction.stepY, delta * direction.stepX, 0), 0) + targets += add.filter { it != attacker && isAttackable(it, attacker, CombatStyle.RANGE, false) }.take(1) //RANGE is correct because halberds are able to attack from a distance + } + return targets } -fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: Entity): List { - val targetCandidates = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, CombatStyle.RANGE, false) } +fun findMultihitTargetsForD2h(attacker: Entity, combatStyle: CombatStyle): List { + val targets = getLocalEntities(attacker.location, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } + return targets.filter { it.location.withinDistance(attacker.location, 1) }.take(14) //runescape.wiki/w/Dragon_2h_sword?oldid=859949 "up to 14 enemies in the squares around the player (Only directly in front of and to the sides, it does not attack those diagonal of the player)" +} + +fun findMultihitTargetsForChinchompa(target: Entity, attacker: Entity): List { + val targetCandidates = getLocalEntities(target.location, 1).filter { it != attacker && it != target && isAttackable(it, attacker, CombatStyle.RANGE, false) } val targets: List? - if (victim is Player) { + if (target is Player) { val players = targetCandidates.filterIsInstance() fun isFamiliarOf(entity: Entity, players: List): Boolean { if (entity !is Familiar) { @@ -52,5 +62,5 @@ fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: } targets = targetCandidates.filter { it is NPC || isOwnerOf(it, npcs) } } - return targets.take(9) //https://runescape.wiki/w/Chinchompa "up to 9 enemies" + return listOf(target) + targets.take(9) //https://runescape.wiki/w/Chinchompa "up to 9 enemies" } diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index c1ffac807..d34cc2d47 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -394,9 +394,10 @@ object RegionManager { * @return the list. */ private inline fun getLocalEntitiesOfType(location: Location, distance: Int): List { - val entities: MutableList = ArrayList(20) - for (cx in (location.absChunkX - 8)..(location.absChunkX + 8)) { - for (cy in (location.absChunkY - 8)..(location.absChunkY + 8)) { + val entities: ArrayList = ArrayList(20) + val radius = (distance / 8) + 1 + for (cx in (location.absChunkX - radius)..(location.absChunkX + radius)) { + for (cy in (location.absChunkY - radius)..(location.absChunkY + radius)) { val chunk = Location(cx shl 3, cy shl 3, location.z).chunk if (T::class.java.isAssignableFrom(Player::class.java)) { entities.addAll(chunk.players.filterIsInstance()) From 572ec0513771e28bd79c7b0066189b36d9c17eac Mon Sep 17 00:00:00 2001 From: Player Name Date: Fri, 31 Jul 2026 22:44:02 +0200 Subject: [PATCH 93/94] leftover issues --- .../item/equipment/special/SpearWallSpecialHandler.java | 2 +- .../item/equipment/special/SweepSpecialHandler.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java index 3abb1e50f..727c51767 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SpearWallSpecialHandler.java @@ -74,7 +74,7 @@ public final class SpearWallSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargets(entity.getLocation(), entity, CombatStyle.MELEE); + List list = findMultihitTargets(victim, entity, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java index 3d34735b8..40e7a79bc 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/SweepSpecialHandler.java @@ -10,8 +10,6 @@ import core.game.node.entity.combat.CombatStyle; import core.game.node.entity.combat.MeleeSwingHandler; import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.player.Player; -import core.game.world.map.Direction; -import core.game.world.map.Location; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Plugin; @@ -90,10 +88,6 @@ public final class SweepSpecialHandler extends MeleeSwingHandler implements Plug if (!entity.getProperties().isMultiZone() || !victim.getProperties().isMultiZone()) { return new BattleState[]{state}; } - Location vl = victim.getLocation(); - int x = vl.getX(); - int y = vl.getY(); - Direction dir = Direction.getDirection(x - entity.getLocation().getX(), y - entity.getLocation().getY()); List l = new ArrayList<>(20); l.add(new BattleState(entity, victim)); List list = findMultihitTargetsForDragonHalberd(victim, entity); From 7e0b684a2080ba3a0f24e74d255c092b70d652be Mon Sep 17 00:00:00 2001 From: Player Name Date: Sat, 1 Aug 2026 04:37:36 +0200 Subject: [PATCH 94/94] another mutablelist>arraylist --- .../src/main/core/game/world/update/MapChunkRenderer.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 22fd11b8d..3d0d644a9 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -24,13 +24,8 @@ object MapChunkRenderer { fun render(player: Player) { val last = player.playerFlags.lastViewport val updated: ArrayList = ArrayList() - val current: ArrayList> = ArrayList() + val current: ArrayList> = ArrayList() - // Center the build area on the loaded scene anchor (lastSceneGraph), NOT the live player position. - // The client's 13x13 build area is anchored at lastSceneGraph; addressing chunks relative to it keeps - // every chunk packet inside the client's scene window even when the player has drifted up to 3 chunks - // from the anchor (the scene graph only rebuilds at a drift of 4). Using player.location here instead - // pushes the viewport edge to drift+6 chunks from the anchor, off-window, so edge items never render. val anchor = player.playerFlags.lastSceneGraph ?: player.location val center = Location.create(anchor.x, anchor.y, player.location.z) for (dcx in -BUILD_AREA_DEPTH..BUILD_AREA_DEPTH) { @@ -76,7 +71,7 @@ object MapChunkRenderer { * @param c The region chunk. * @return `True` if so. */ - private fun containsChunk(list: MutableList>, c: RegionChunk): Boolean { + private fun containsChunk(list: ArrayList>, c: RegionChunk): Boolean { val sizeList = list.size for (x in 0 until sizeList) { val chunkSize: Int = list[x].size