diff --git a/Server/build.gradle b/Server/build.gradle index cc0a72780..07adf3761 100644 --- a/Server/build.gradle +++ b/Server/build.gradle @@ -22,7 +22,7 @@ repositories { dependencies { implementation("com.github.ajalt.mordant:mordant:2.0.0-alpha2") - implementation "org.jetbrains:markdown-jvm:0.2.0" + implementation "org.jetbrains:markdown-jvm:0.2.4" implementation 'com.google.guava:guava:29.0-jre' implementation 'mysql:mysql-connector-java:8.0.21' implementation 'io.github.classgraph:classgraph:4.8.98' diff --git a/Server/data/configs/drop_tables.json b/Server/data/configs/drop_tables.json index abdaa0510..471b300f8 100644 --- a/Server/data/configs/drop_tables.json +++ b/Server/data/configs/drop_tables.json @@ -46329,213 +46329,111 @@ "main": [ { "minAmount": "1", - "weight": "50.0", - "id": "1339", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "1341", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "1119", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "1121", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "1181", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "50.0", - "id": "1141", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "5.0", - "id": "1357", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "5.0", - "id": "1145", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "1161", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "1345", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", + "weight": "0.15", "id": "1201", "maxAmount": "1" }, { "minAmount": "1", - "weight": "25.0", + "weight": "1.0", + "id": "1161", + "maxAmount": "1" + }, + { + "minAmount": "1", + "weight": "1.0", + "id": "1181", + "maxAmount": "1" + }, + { + "minAmount": "1", + "weight": "1.0", + "id": "1121", + "maxAmount": "1" + }, + { + "minAmount": "1", + "weight": "0.098", "id": "1347", "maxAmount": "1" }, { "minAmount": "1", - "weight": "25.0", - "id": "3122", + "weight": "1.0", + "id": "1341", "maxAmount": "1" }, { "minAmount": "8", - "weight": "50.0", + "weight": "1.0", "id": "557", - "maxAmount": "60" + "maxAmount": "36" }, { - "minAmount": "2", - "weight": "25.0", + "minAmount": "12", + "weight": "0.65", "id": "563", "maxAmount": "12" }, { "minAmount": "7", - "weight": "25.0", + "weight": "0.65", "id": "561", - "maxAmount": "8" + "maxAmount": "7" }, { "minAmount": "1", - "weight": "25.0", - "id": "5323", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "5280", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "50.0", + "weight": "1.0", "id": "5104", "maxAmount": "1" }, { "minAmount": "1", - "weight": "25.0", - "id": "5105", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", + "weight": "1.0", "id": "5100", "maxAmount": "1" }, { "minAmount": "1", - "weight": "50.0", - "id": "5292", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "5.0", - "id": "5296", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", + "weight": "0.038", "id": "5295", "maxAmount": "1" }, + { + "minAmount": "6", + "weight": "1.0", + "id": "454", + "maxAmount": "6" + }, { "minAmount": "1", - "weight": "50.0", - "id": "203", + "weight": "1.0", + "id": "1759", + "maxAmount": "1" + }, + { + "minAmount": "3", + "weight": "1.0", + "id": "353", + "maxAmount": "3" + }, + { + "minAmount": "1", + "weight": "0.098", + "id": "3122", "maxAmount": "1" }, { "minAmount": "1", - "weight": "50.0", + "weight": "1.0", "id": "199", "maxAmount": "1" }, { "minAmount": "1", - "weight": "50.0", + "weight": "1.0", "id": "201", "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "207", - "maxAmount": "1" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "205", - "maxAmount": "1" - }, - { - "minAmount": "8", - "weight": "50.0", - "id": "995", - "maxAmount": "200" - }, - { - "minAmount": "1", - "weight": "25.0", - "id": "1759", - "maxAmount": "42" - }, - { - "minAmount": "3", - "weight": "25.0", - "id": "453", - "maxAmount": "6" - }, - { - "minAmount": "3", - "weight": "25.0", - "id": "353", - "maxAmount": "3" - }, - { - "minAmount": "5", - "weight": "25.0", - "id": "401", - "maxAmount": "5" - }, - { - "minAmount": "6", - "weight": "25.0", - "id": "383", - "maxAmount": "7" } ] }, diff --git a/Server/data/configs/music_configs.json b/Server/data/configs/music_configs.json index 6aee332d7..0a66a3f51 100644 --- a/Server/data/configs/music_configs.json +++ b/Server/data/configs/music_configs.json @@ -1067,6 +1067,12 @@ "indexId": "365", "borders": "{1792,4352,1855,4415}-{1920,4352,1983,4415}" }, + { + "id": "220", + "name": "Island of the Trolls", + "indexId": "441", + "borders": "{2304,3842,2428,3901}" + }, { "id": "241", "name": "Stagnant", diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index f40e0c9bb..6e30e2cbf 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -10718,5 +10718,17 @@ { "npc_id": "5517", "loc_data": "{2403,3853,0,1,0}-{2328,3830,0,1,0}-{2405,3860,0,1,0}-{2335,3894,0,1,0}" + }, + { + "npc_id": "3848", + "loc_data": "{2410,3780,0,1,0}-{2414,3780,0,1,0}" + }, + { + "npc_id": "313", + "loc_data":"{2401,3781,0,1,0}" + }, + { + "npc_id": "312", + "loc_data": "{2421,3789,0,1,0}" } ] \ No newline at end of file diff --git a/Server/src/main/java/core/game/interaction/inter/GrandExchangeInterface.java b/Server/src/main/java/core/game/interaction/inter/GrandExchangeInterface.java index e5714afd8..8ffe33bdf 100644 --- a/Server/src/main/java/core/game/interaction/inter/GrandExchangeInterface.java +++ b/Server/src/main/java/core/game/interaction/inter/GrandExchangeInterface.java @@ -343,6 +343,8 @@ public class GrandExchangeInterface extends ComponentPlugin { String s = value.toString(); s = s.replace("k","000"); s = s.replace("K","000"); + s = s.replace("m","000000"); + s = s.replace("M","000000"); setOfferAmount(player, offer, Integer.parseInt(s)); return Unit.INSTANCE; }); @@ -379,6 +381,8 @@ public class GrandExchangeInterface extends ComponentPlugin { String s = value.toString(); s = s.replace("k","000"); s = s.replace("K","000"); + s = s.replace("m","000000"); + s = s.replace("M","000000"); setOfferValue(player, offer, Integer.parseInt(s)); return Unit.INSTANCE; }); diff --git a/Server/src/main/java/core/game/interaction/inter/TradeInterfacePlugin.java b/Server/src/main/java/core/game/interaction/inter/TradeInterfacePlugin.java index 4b1702fb1..88fb909be 100644 --- a/Server/src/main/java/core/game/interaction/inter/TradeInterfacePlugin.java +++ b/Server/src/main/java/core/game/interaction/inter/TradeInterfacePlugin.java @@ -72,6 +72,8 @@ public final class TradeInterfacePlugin extends ComponentPlugin { String s = value.toString(); s = s.replace("k","000"); s = s.replace("K","000"); + s = s.replace("m","000000"); + s = s.replace("M","000000"); int val = Integer.parseInt(s); module.getContainer().withdraw(slot, val); return Unit.INSTANCE; diff --git a/Server/src/main/java/core/game/interaction/object/BankingPlugin.java b/Server/src/main/java/core/game/interaction/object/BankingPlugin.java index c841b6ffd..71e3914b5 100644 --- a/Server/src/main/java/core/game/interaction/object/BankingPlugin.java +++ b/Server/src/main/java/core/game/interaction/object/BankingPlugin.java @@ -376,6 +376,8 @@ public final class BankingPlugin extends OptionHandler { String s = value.toString(); s = s.replace("k","000"); s = s.replace("K","000"); + s = s.replace("m","000000"); + s = s.replace("M","000000"); int val = Integer.parseInt(s); p.getBank().takeItem(slot, val); p.getBank().updateLastAmountX(val); diff --git a/Server/src/main/java/core/game/node/entity/player/link/request/trade/TradeContainer.java b/Server/src/main/java/core/game/node/entity/player/link/request/trade/TradeContainer.java index a6a496a0e..25a0d86cc 100644 --- a/Server/src/main/java/core/game/node/entity/player/link/request/trade/TradeContainer.java +++ b/Server/src/main/java/core/game/node/entity/player/link/request/trade/TradeContainer.java @@ -1,5 +1,6 @@ package core.game.node.entity.player.link.request.trade; +import api.ContentAPI; import core.cache.def.impl.ItemDefinition; import core.game.container.*; import core.game.node.entity.player.Player; @@ -10,6 +11,8 @@ import core.net.packet.PacketRepository; import core.net.packet.context.ContainerContext; import core.net.packet.out.ContainerPacket; +import static rs09.tools.stringtools.StringToolsKt.colorize; + /** * Represents the container during a trade session. * @author 'Vexia @@ -148,10 +151,23 @@ public final class TradeContainer extends Container { */ private boolean tradeable(final Item item) { final ItemDefinition definition = ItemDefinition.forId(item.getId()); + Player target = TradeModule.getExtension(player).getTarget(); + boolean playerIsBot = player.getAttribute("not_on_highscores",false); + boolean targetIsBot = target.getAttribute("not_on_highscores",false); + String playerIP = player.getDetails().getIpAddress(); + String targetIP = target.getDetails().getIpAddress(); + String playerMac = player.getDetails().getMacAddress(); + String targetMac = target.getDetails().getMacAddress(); + String playerHost = player.getDetails().getCompName(); + String targetHost = target.getDetails().getCompName(); if (item.getId() == 11174 || item.getId() == 11173 || item.getId() == 759) { return true; } - if (player.getIronmanManager().isIronman() || TradeModule.getExtension(player).getTarget() != null && TradeModule.getExtension(player).getTarget().getIronmanManager().isIronman()) { + if (player.getIronmanManager().isIronman() || target != null && target.getIronmanManager().isIronman()) { + return false; + } + if ((playerIsBot || targetIsBot) && (playerIP.equals(targetIP) || playerMac.equals(targetMac) || playerHost.equals(targetHost))){ + ContentAPI.sendMessage(player, colorize("%RYou can not trade items with your own bot accounts.")); return false; } if (item.getName().equals("Coins") && item.getId() != 995) { diff --git a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java index 9ba15f22f..40fab98d2 100644 --- a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java +++ b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java @@ -5,6 +5,7 @@ import core.game.node.entity.player.Player; import core.game.node.item.Item; import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; +import org.rs09.consts.Items; import java.util.HashMap; @@ -25,7 +26,9 @@ public enum FishingOption { BIG_NET(new Item(305), 16, Animation.create(620), null, "net", Fish.MACKEREL, Fish.COD, Fish.BASS, Fish.SEAWEED), N_HARPOON(new Item(311), 76, Animation.create(618), null, "harpoon", Fish.SHARK), H_NET(new Item(303), 1, Animation.create(621), null, "net", Fish.MONKFISH), - C_CAGE(new Item(301), 85, Animation.create(619), new Item(14943), "cage", Fish.DARK_CRAB); + C_CAGE(new Item(301), 85, Animation.create(619), new Item(14943), "cage", Fish.DARK_CRAB), + KBWANJI_NET(new Item(Items.SMALL_FISHING_NET_303), 5, Animation.create(621), null, "net", Fish.KARAMBWANJI), + KARAMBWAN_VES(new Item(Items.KARAMBWAN_VESSEL_3157), 65, Animation.create(1193), new Item(Items.RAW_KARAMBWANJI_3150), "fish", Fish.KARAMBWAN); public static HashMap nameMap = new HashMap<>(); static{ diff --git a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java index 045fa780e..57d115c0c 100644 --- a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java +++ b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java @@ -13,7 +13,9 @@ public enum FishingSpot { CAGE_HARPOON(new int[] { 312, 321, 324, 333, 405, 1332, 1399, 3804, 5470, 7046}, FishingOption.CAGE, FishingOption.HARPOON), NET_HARPOON(new int[] { 313, 322, 334, 406, 1191, 1333, 1405, 1406, 3574, 3575, 5471, 7044 }, FishingOption.BIG_NET, FishingOption.N_HARPOON), HARPOON_NET(new int[] { 3848, 3849 }, FishingOption.HARPOON, FishingOption.H_NET, FishingOption.BARB_HARPOON), - CRAB_CAGE(new int[] {8665}, FishingOption.C_CAGE); + CRAB_CAGE(new int[] {8665}, FishingOption.C_CAGE), + SPOT_KBWANJI(new int[] {1174}, FishingOption.KBWANJI_NET), + SPOT_KARAMBWAN(new int[] {1177}, FishingOption.KARAMBWAN_VES); public static HashMap spotMap = new HashMap<>(); diff --git a/Server/src/main/java/core/game/node/entity/skill/runecrafting/RunecraftingPlugin.java b/Server/src/main/java/core/game/node/entity/skill/runecrafting/RunecraftingPlugin.java index 0418e904f..051d032fb 100644 --- a/Server/src/main/java/core/game/node/entity/skill/runecrafting/RunecraftingPlugin.java +++ b/Server/src/main/java/core/game/node/entity/skill/runecrafting/RunecraftingPlugin.java @@ -10,7 +10,6 @@ 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.info.Rights; -import core.game.node.entity.skill.runecrafting.abyss.AbyssPlugin; import core.game.node.item.Item; import core.game.node.object.Scenery; import core.game.system.task.Pulse; @@ -35,7 +34,6 @@ public class RunecraftingPlugin extends OptionHandler { @Override public Plugin newInstance(Object arg) throws Throwable { addNodes(); - PluginManager.definePlugin(new AbyssPlugin()); PluginManager.definePlugin(new TiaraPlugin()); PluginManager.definePlugin(new RunePouchPlugin()); PluginManager.definePlugin(new EnchantTiaraPlugin()); diff --git a/Server/src/main/java/core/game/node/entity/skill/runecrafting/abyss/AbyssPlugin.java b/Server/src/main/java/core/game/node/entity/skill/runecrafting/abyss/AbyssPlugin.java deleted file mode 100644 index d90ee90f2..000000000 --- a/Server/src/main/java/core/game/node/entity/skill/runecrafting/abyss/AbyssPlugin.java +++ /dev/null @@ -1,440 +0,0 @@ -package core.game.node.entity.skill.runecrafting.abyss; - -import core.cache.def.impl.NPCDefinition; -import core.cache.def.impl.SceneryDefinition; -import core.game.node.entity.skill.gather.SkillingTool; -import core.game.node.entity.skill.runecrafting.Altar; -import core.game.interaction.OptionHandler; -import core.game.node.Node; -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.node.object.Scenery; -import core.game.system.task.Pulse; -import rs09.game.world.GameWorld; -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; -import rs09.plugin.PluginManager; -import core.tools.RandomFunction; - -/** - * A plugin used to handle the abyss. - * @author Vexia - */ -public final class AbyssPlugin extends OptionHandler { - - @Override - public Plugin newInstance(Object arg) throws Throwable { - for (AbbysalObstacle obstacle : AbbysalObstacle.values()) { - for (int i : obstacle.getObjects()) { - SceneryDefinition.forId(i).getHandlers().put("option:" + obstacle.getOption(), this); - } - } - PluginManager.definePlugin(new AbyssalNPC()); - PluginManager.definePlugin(new DarkMageDialogue()); - SceneryDefinition.setOptionHandler("exit-through", this); - PluginManager.definePlugin(new ZamorakMageDialogue()); - NPCDefinition.forId(2259).getHandlers().put("option:teleport", this); - NPCDefinition.forId(2262).getHandlers().put("option:repair-pouches", this); - return null; - } - - @Override - public boolean handle(Player player, Node node, String option) { - switch (option) { - case "teleport": - teleport(player, (NPC) node); - break; - case "repair-pouches": - player.getDialogueInterpreter().open(node.getId(), node, true); - break; - case "exit-through": - Altar altar = Altar.forObject((Scenery) node); - if (altar != null) { - altar.enterRift(player); - } - break; - case "mine": - case "chop": - case "squeeze-through": - case "distract": - case "go-through": - case "burn-down": - final AbbysalObstacle obstacle = AbbysalObstacle.forObject(((Scenery) node)); - obstacle.handle(player, ((Scenery) node)); - break; - } - return true; - } - - /** - * Represents the teleporting to the abyss. - * @param player the player. - */ - public static void teleport(final Player player, final NPC npc) { - player.lock(3); - npc.visualize(new Animation(1979), new Graphics(4)); - npc.sendChat("Veniens! Sallakar! Rinnesset!"); - player.getSkills().decrementPrayerPoints(100); - player.getSkullManager().checkSkull(player); - GameWorld.getPulser().submit(new Pulse(2, player) { - @Override - public boolean pulse() { - player.getProperties().setTeleportLocation(Location.create(3021, 4847, 0)); - npc.getUpdateMasks().reset(); - return true; - } - }); - } - - /** - * Represents an obstacle in an abbsyal. - * @author 'Vexia - * @date 02/11/2013 - */ - public enum AbbysalObstacle { - BOIL("burn-down", new Location[] { Location.create(3024, 4833, 0), Location.create(3053, 4830, 0) }, 7165) { - @Override - public void handle(final Player player, final Scenery object) { - if (!player.getInventory().contains(590, 1)) { - player.getPacketDispatch().sendMessage("You don't have a tinderbox to burn it."); - return; - } - player.animate(new Animation(733)); - player.lock(3); - GameWorld.getPulser().submit(new Pulse(1, player) { - int count = 0; - - @Override - public boolean pulse() { - switch (count) { - case 1: - player.getPacketDispatch().sendMessage("You attempt to burn your way through.."); - break; - case 4: - if (RandomFunction.random(3) != 1) { - player.getPacketDispatch().sendMessage("...and manage to burn it down and get past."); - player.getProperties().setTeleportLocation(getLocations()[getIndex(object)]); - return true; - } else { - player.getPacketDispatch().sendMessage("You fail to set it on fire."); - return true; - } - } - count++; - return false; - } - - @Override - public void stop() { - super.stop(); - player.animate(new Animation(-1, Priority.HIGH)); - } - }); - } - }, - MINE("mine", new Location[] { Location.create(3030, 4821, 0), Location.create(3048, 4822, 0) }, 7158, 7153) { - @Override - public void handle(final Player player, final Scenery object) { - final SkillingTool tool = setTool(true, player); - if (tool == null) { - player.getPacketDispatch().sendMessage("You need a pickaxe in order to do that."); - return; - } - player.animate(tool.getAnimation()); - player.lock(3); - GameWorld.getPulser().submit(new Pulse(1, player) { - int count = 0; - - @Override - public boolean pulse() { - switch (count) { - case 1: - player.getPacketDispatch().sendMessage("You attempt to mine your way through.."); - break; - case 4: - if (RandomFunction.random(3) != 1) { - player.getPacketDispatch().sendMessage("...and manage to break through the rock."); - player.getProperties().setTeleportLocation(getLocations()[getIndex(object)]); - return true; - } else { - player.getPacketDispatch().sendMessage("...but fail to break-up the rock."); - return true; - } - } - count++; - return false; - } - - @Override - public void stop() { - super.stop(); - player.animate(new Animation(-1, Priority.HIGH)); - } - }); - } - }, - CHOP("chop", new Location[] { Location.create(3050, 4824, 0), Location.create(3028, 4824, 0) }, 7161, 7144) { - @Override - public void handle(final Player player, final Scenery object) { - final SkillingTool tool = setTool(false, player); - if (tool == null) { - player.getPacketDispatch().sendMessage("You need an axe in order to do that."); - return; - } - player.animate(tool.getAnimation()); - player.lock(3); - GameWorld.getPulser().submit(new Pulse(1, player) { - int count = 0; - - @Override - public boolean pulse() { - switch (count) { - case 1: - player.getPacketDispatch().sendMessage("You attempt to chop your way through..."); - break; - case 4: - if (RandomFunction.random(3) != 1) { - player.getPacketDispatch().sendMessage("...and manage to chop down the tendrils."); - player.getProperties().setTeleportLocation(getLocations()[getIndex(object)]); - return true; - } else { - player.getPacketDispatch().sendMessage("You fail to cut through the tendrils."); - return true; - } - } - count++; - return false; - } - - @Override - public void stop() { - super.stop(); - player.animate(new Animation(-1, Priority.HIGH)); - } - }); - } - }, - SQUEEZE("squeeze-through", new Location[] { Location.create(3048, 4842, 0), Location.create(3031, 4842, 0) }, 7164, 7147) { - @Override - public void handle(final Player player, final Scenery object) { - player.animate(new Animation(1331)); - player.lock(3); - player.lock(3); - GameWorld.getPulser().submit(new Pulse(1, player) { - int count = 0; - - @Override - public boolean pulse() { - switch (count) { - case 1: - player.getPacketDispatch().sendMessage("You attempt to squeeze through the narrow gap..."); - break; - case 2: - player.getPacketDispatch().sendMessage("...and you manage to crawl through."); - player.getProperties().setTeleportLocation(getLocations()[getIndex(object)]); - return true; - } - count++; - return false; - } - - @Override - public void stop() { - super.stop(); - player.animate(new Animation(-1, Priority.HIGH)); - } - }); - } - }, - DISTRACT("distract", new Location[] { Location.create(3029, 4841, 0), Location.create(3051, 4838, 0) }, 7168, 7150) { - @Override - public void handle(final Player player, final Scenery object) { - int[] emotes = { 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 2113, 2109, 2111, 2106, 2107, 2108, 0x558, 2105, 2110, 2112, 0x84F, 0x850, 1131, 1130, 1129, 1128, 1745, 3544, 3543, 2836 }; - int index = RandomFunction.random(emotes.length); - player.animate(new Animation(emotes[index])); - player.lock(3); - GameWorld.getPulser().submit(new Pulse(1, player) { - int count = 0; - - @Override - public boolean pulse() { - switch (count) { - case 1: - player.getPacketDispatch().sendMessage("You use your thieving skills to misdirect the eyes..."); - break; - case 4: - if (RandomFunction.random(3) != 1) { - player.getPacketDispatch().sendMessage("...and sneak past while they're not looking."); - player.getProperties().setTeleportLocation(getLocations()[getIndex(object)]); - } else { - player.getPacketDispatch().sendMessage("You fail to distract the eyes."); - return true; - } - return true; - } - count++; - return false; - } - - @Override - public void stop() { - super.stop(); - player.animate(new Animation(-1, Priority.HIGH)); - } - }); - } - }, - PASSAGE("go-through", new Location[] { Location.create(3040, 4844, 0) }, 7154) { - @Override - public void handle(final Player player, final Scenery object) { - player.getProperties().setTeleportLocation(getLocations()[0]); - } - }; - /** - * Constructs a new {@code RunecraftingOptionPlugin} {@code Object}. - * @param locations the locations. - * @param objects the objects. - */ - AbbysalObstacle(final String option, Location[] locations, int... objects) { - this.option = option; - this.objects = objects; - this.locations = locations; - this.option = option; - } - - /** - * Represents the option. - */ - private String option; - - /** - * Represents the corssing location. - */ - private final Location[] locations; - - /** - * Represents the object id. - */ - private final int[] objects; - - /** - * Gets the locations. - * @return The locations. - */ - public Location[] getLocations() { - return locations; - } - - /** - * Gets the objects. - * @return The objects. - */ - public int[] getObjects() { - return objects; - } - - /** - * Method used to get the abbysal obstacle. - * @param object the object. - * @return the AbbysalObstacle or Null. - */ - public static AbbysalObstacle forObject(final Scenery object) { - for (AbbysalObstacle obstacle : values()) { - for (int i : obstacle.getObjects()) { - if (i == object.getId()) { - return obstacle; - } - } - } - return null; - } - - /** - * Method used to get the index. - * @param object the object. - * @return the index. - */ - public int getIndex(final Scenery object) { - for (int i = 0; i < objects.length; i++) { - if (getObjects()[i] == object.getId()) { - return i; - } - } - return 0; - } - - /** - * Methhod used to handle the obstacle. - * @param player the player. - * @param object the object. - */ - public void handle(final Player player, final Scenery object) { - - } - - /** - * Gets the option. - * @return The option. - */ - public String getOption() { - return option; - } - - /** - * Sets the tool used. - */ - private static SkillingTool setTool(final boolean mining, final Player player) { - SkillingTool tool = null; - if (!mining) { - if (checkTool(player, SkillingTool.DRAGON_AXE)) { - tool = SkillingTool.DRAGON_AXE; - } else if (checkTool(player, SkillingTool.RUNE_AXE)) { - tool = SkillingTool.RUNE_AXE; - } else if (checkTool(player, SkillingTool.ADAMANT_AXE)) { - tool = SkillingTool.ADAMANT_AXE; - } else if (checkTool(player, SkillingTool.MITHRIL_AXE)) { - tool = SkillingTool.MITHRIL_AXE; - } else if (checkTool(player, SkillingTool.BLACK_AXE)) { - tool = SkillingTool.BLACK_AXE; - } else if (checkTool(player, SkillingTool.STEEL_AXE)) { - tool = SkillingTool.STEEL_AXE; - } else if (checkTool(player, SkillingTool.IRON_AXE)) { - tool = SkillingTool.IRON_AXE; - } else if (checkTool(player, SkillingTool.BRONZE_AXE)) { - tool = SkillingTool.BRONZE_AXE; - } - } else { - if (checkTool(player, SkillingTool.RUNE_PICKAXE)) { - tool = SkillingTool.RUNE_PICKAXE; - } else if (checkTool(player, SkillingTool.ADAMANT_PICKAXE)) { - tool = SkillingTool.ADAMANT_PICKAXE; - } else if (checkTool(player, SkillingTool.MITHRIL_PICKAXE)) { - tool = SkillingTool.MITHRIL_PICKAXE; - } else if (checkTool(player, SkillingTool.STEEL_PICKAXE)) { - tool = SkillingTool.STEEL_PICKAXE; - } else if (checkTool(player, SkillingTool.IRON_PICKAXE)) { - tool = SkillingTool.IRON_PICKAXE; - } else if (checkTool(player, SkillingTool.BRONZE_PICKAXE)) { - tool = SkillingTool.BRONZE_PICKAXE; - } - } - return tool; - } - - /** - * Checks if the player has a tool and if he can use it. - * @param tool The tool. - * @return {@code True} if the tool is usable. - */ - private static boolean checkTool(final Player player, SkillingTool tool) { - if (player.getEquipment().contains(tool.getId(), 1)) { - return true; - } - return player.getInventory().contains(tool.getId(), 1); - } - } - -} diff --git a/Server/src/main/java/core/net/packet/in/InteractionPacket.java b/Server/src/main/java/core/net/packet/in/InteractionPacket.java index 492b3fd38..d92d20cb3 100644 --- a/Server/src/main/java/core/net/packet/in/InteractionPacket.java +++ b/Server/src/main/java/core/net/packet/in/InteractionPacket.java @@ -187,7 +187,7 @@ public final class InteractionPacket implements IncomingPacket { player.debug("spawn=" + npc.getProperties().getSpawnLocation() + "."); player.debug("Varp ID= " + npc.getDefinition().getConfigId() + " Offset=" + npc.getDefinition().getVarbitOffset() + " Size=" + npc.getDefinition().getVarbitSize()); handleAIPLegion(player, 0, optionIndex, index); - if(InteractionListeners.run(npc.getId(),2, option.getName(),player,npc)){ + if(InteractionListeners.run(shown.getId(),2, option.getName(),player,npc)){ return; } if(PluginInteractionManager.handle(player,shown,option)){ diff --git a/Server/src/main/java/core/net/packet/in/RunScriptPacketHandler.java b/Server/src/main/java/core/net/packet/in/RunScriptPacketHandler.java index 1ea109ba9..6cc2f3e2f 100644 --- a/Server/src/main/java/core/net/packet/in/RunScriptPacketHandler.java +++ b/Server/src/main/java/core/net/packet/in/RunScriptPacketHandler.java @@ -1,5 +1,6 @@ package core.net.packet.in; +import api.ContentAPI; import core.game.node.entity.player.Player; import core.game.node.entity.player.link.RunScript; import core.net.packet.IncomingPacket; @@ -29,7 +30,11 @@ public class RunScriptPacketHandler implements IncomingPacket { } else { value = buffer.getInt(); } - script.invoke(value); + try { + script.invoke(value); + } catch (NumberFormatException nfe){ + ContentAPI.sendDialogue(player, "That number's a bit large, don't you think?"); + } player.removeAttribute("runscript"); } } diff --git a/Server/src/main/kotlin/rs09/game/ai/general/ScriptAPI.kt b/Server/src/main/kotlin/rs09/game/ai/general/ScriptAPI.kt index 914843913..b0fe0f876 100644 --- a/Server/src/main/kotlin/rs09/game/ai/general/ScriptAPI.kt +++ b/Server/src/main/kotlin/rs09/game/ai/general/ScriptAPI.kt @@ -9,6 +9,7 @@ import core.game.content.consumable.Food import core.game.content.consumable.effects.HealingEffect import core.game.interaction.DestinationFlag import core.game.interaction.MovementPulse +import core.game.interaction.Option import core.game.node.Node import core.game.node.`object`.Scenery import core.game.node.entity.Entity @@ -31,6 +32,8 @@ import org.rs09.consts.Items import rs09.game.ai.AIRepository import rs09.game.ge.GrandExchangeOffer import rs09.game.ge.OfferManager +import rs09.game.interaction.InteractionListener +import rs09.game.interaction.InteractionListeners import rs09.game.system.SystemLogger import rs09.game.system.config.ItemConfigParser import rs09.game.world.GameWorld @@ -58,6 +61,26 @@ class ScriptAPI(private val bot: Player) { return sqrt((n1.location.x - n2.location.x.toDouble()).pow(2.0) + (n2.location.y - n1.location.y.toDouble()).pow(2.0)) } + fun interact(bot: Player, node: Node?, option: String){ + + if(node == null) return + + val type = when(node){ + is Scenery -> InteractionListener.SCENERY + is NPC -> InteractionListener.NPC + is Item -> InteractionListener.ITEM + else -> -1 + } + val opt: Option? = node.interaction.options.filter {it != null && it.name.equals(option, true) }.firstOrNull() + + if(opt == null){ + SystemLogger.logWarn("Invalid option name provided: $option") + return + } + + if(!InteractionListeners.run(node.id, type, option, bot, node)) node.interaction.handle(bot, opt) + } + /** * Gets the nearest node with name entityName * @param entityName the name of the node to look for diff --git a/Server/src/main/kotlin/rs09/game/ai/general/scriptrepository/GnomeAgility.kt b/Server/src/main/kotlin/rs09/game/ai/general/scriptrepository/GnomeAgility.kt new file mode 100644 index 000000000..de32ecbaf --- /dev/null +++ b/Server/src/main/kotlin/rs09/game/ai/general/scriptrepository/GnomeAgility.kt @@ -0,0 +1,167 @@ +package rs09.game.ai.general.scriptrepository + +import api.ContentAPI +import core.game.world.map.zone.ZoneBorders +import rs09.game.ai.general.ScriptAPI +import rs09.game.ai.skillingbot.SkillingBotAssembler +import rs09.game.interaction.InteractionListener +import rs09.game.interaction.InteractionListeners + + +@PlayerCompatible +@ScriptName("Gnome Agility Course Script") +@ScriptDescription("Start the script while standing front of the balancing log") +@ScriptIdentifier("gnome_agility") +class GnomeAgility : Script() { + + var state = State.INIT + val startzone = ZoneBorders(2473,3436,2475,3437,0) + val afterlog = ZoneBorders(2474,3429,2474,3429,0) + val beforefirstnet = ZoneBorders(2473,3426,2474,3427,0) + val afterfirstnet = ZoneBorders(2471,3424,2476,3424,1) + val beforebranchup = ZoneBorders(2473,3423,2473,3423,1) + val afterbranchup = ZoneBorders(2473,3420,2473,3420,2) + val beforerope = ZoneBorders(2477,3420,2477,3420,2) + val afterrope = ZoneBorders(2483,3420,2483,3420,2) + val beforebranchdown = ZoneBorders(2485,3419,2486,3420,2) + val afterbranchdown = ZoneBorders(2487,3420,2487,3420,0) + val beforesecondnet = ZoneBorders(2483,3425,2488,3425,0) + val aftersecondnet = ZoneBorders(2483,3427,2488,3427,0) + val beforepipe = ZoneBorders(2484,3430,2487,3430,0) + val afterpipe = ZoneBorders(2484,3437,2487,3437,0) + var overlay: ScriptAPI.BottingOverlay? = null + var totalLaps = 0 + + override fun tick() { + + when (state) { + + State.INIT -> { + overlay = scriptAPI.getOverlay() + overlay!!.init() + overlay!!.setTitle("Agility Course") + overlay!!.setTaskLabel("Laps Run") + overlay!!.setAmount(0) + + state = State.START + } + + State.START -> { + if(!startzone.insideBorder(bot)){ + scriptAPI.walkTo(startzone.randomLoc) + } + if(startzone.insideBorder(bot)){ + state = State.LOG + } + } + + State.LOG -> { + val log = scriptAPI.getNearestNode("log balance",true) + if(startzone.insideBorder(bot)) { + scriptAPI.interact(bot, log, "walk-across") + } + if(afterlog.insideBorder(bot)){ + state = State.FIRSTNET + } + } + + State.FIRSTNET -> { + val firstnet = scriptAPI.getNearestNode("obstacle net",true) + if(!beforefirstnet.insideBorder(bot)){ + scriptAPI.walkTo(beforefirstnet.randomLoc) + } + if(beforefirstnet.insideBorder(bot)) { + scriptAPI.interact(bot, firstnet, "climb-over") + } + if(afterfirstnet.insideBorder(bot)){ + state = State.BRANCHUP + } + } + + State.BRANCHUP -> { + val branchup = scriptAPI.getNearestNode("tree branch", true) + if(!beforebranchup.insideBorder(bot) && !afterbranchup.insideBorder(bot)){ + scriptAPI.walkTo(beforebranchup.randomLoc) + } + else if(beforebranchup.insideBorder(bot)){ + scriptAPI.interact(bot,branchup,"climb") + } + else if(afterbranchup.insideBorder(bot)){ + state = State.ROPE + } + } + + State.ROPE -> { + val rope = scriptAPI.getNearestNode("balancing rope",true) + if(!beforerope.insideBorder(bot) && !afterrope.insideBorder(bot)){ + scriptAPI.walkTo(beforerope.randomLoc) + } + else if(beforerope.insideBorder(bot)){ + scriptAPI.interact(bot,rope,"walk-on") + } + else if(afterrope.insideBorder(bot)){ + state = State.BRANCHDOWN + } + } + + State.BRANCHDOWN -> { + val branchdown = scriptAPI.getNearestNode("tree branch",true) + if(!beforebranchdown.insideBorder(bot) && !afterbranchdown.insideBorder(bot)){ + scriptAPI.walkTo(beforebranchdown.randomLoc) + } + else if(beforebranchdown.insideBorder(bot)){ + scriptAPI.interact(bot,branchdown,"climb-down") + } + else if(afterbranchdown.insideBorder(bot)){ + state = State.SECONDNET + } + } + + State.SECONDNET -> { + val secondnet = scriptAPI.getNearestNode("obstacle net",true) + if(!beforesecondnet.insideBorder(bot) && !aftersecondnet.insideBorder(bot)){ + scriptAPI.walkTo(beforesecondnet.randomLoc) + } + else if(beforesecondnet.insideBorder(bot)){ + scriptAPI.interact(bot,secondnet,"climb-over") + } + else if(aftersecondnet.insideBorder(bot)){ + state = State.PIPE + } + } + + State.PIPE -> { + val pipe = scriptAPI.getNearestNode("obstacle pipe",true) + if(!beforepipe.insideBorder(bot) && !afterpipe.insideBorder(bot)){ + scriptAPI.walkTo((beforepipe.randomLoc)) + } + if(beforepipe.insideBorder(bot)){ + scriptAPI.interact(bot,pipe,"squeeze-through") + } + if(afterpipe.insideBorder(bot)){ + totalLaps += 1 + overlay!!.setAmount(totalLaps) + state = State.START + } + } + } + } + + override fun newInstance(): Script { + val script = GnomeAgility() + script.bot = SkillingBotAssembler().produce(SkillingBotAssembler.Wealth.POOR,bot.startLocation) + return script + } + + enum class State { + START, + LOG, + FIRSTNET, + BRANCHUP, + ROPE, + BRANCHDOWN, + SECONDNET, + PIPE, + INIT + } +} \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/ai/general/scriptrepository/GnomeBowstring.kt b/Server/src/main/kotlin/rs09/game/ai/general/scriptrepository/GnomeBowstring.kt new file mode 100644 index 000000000..e264ec422 --- /dev/null +++ b/Server/src/main/kotlin/rs09/game/ai/general/scriptrepository/GnomeBowstring.kt @@ -0,0 +1,173 @@ +package rs09.game.ai.general.scriptrepository + +import api.ContentAPI +import core.game.interaction.DestinationFlag +import core.game.interaction.MovementPulse +import core.game.node.entity.skill.crafting.spinning.SpinningItem +import core.game.node.entity.skill.crafting.spinning.SpinningPulse +import core.game.node.item.Item +import core.game.world.map.Location +import core.game.world.map.path.Pathfinder +import core.game.world.map.zone.ZoneBorders +import org.rs09.consts.Items +import rs09.game.ai.general.ScriptAPI + +@PlayerCompatible +@ScriptName("Gnome Stronghold Bowstring") +@ScriptDescription("Start in Gnome Stronghold, South of the Agility Course") +@ScriptIdentifier("gnome_bowstring") +class GnomeBowstring : Script() { + var state = State.PICKING + var stage = 0 + var bLadderSwitch = false + var sLadderSwitch = false + val flaxzone = ZoneBorders(2457,3391,2493,3413,0) + val bankbottomLadder = ZoneBorders(2444, 3413, 2445, 3414, 0) + val banktopLadder = ZoneBorders(2445, 3415, 2446, 3414, 1) + val spinnerbottomLadder = ZoneBorders (2475, 3400, 2476, 3399, 0) + val spinnertopLadder = ZoneBorders (2474, 3397, 2476, 3399, 1) + val pick = ZoneBorders(2478, 3394, 339, 9) + val bank = ZoneBorders(2447, 3415, 2444, 3434) + var overlay: ScriptAPI.BottingOverlay? = null + override fun tick() { + + when(state){ + + State.INIT -> { + overlay = scriptAPI.getOverlay() + overlay!!.init() + overlay!!.setTitle("Picking") + overlay!!.setTaskLabel("Flax Picked") + overlay!!.setAmount(0) + } + + State.PICKING -> { + bot.interfaceManager.close() + if(!flaxzone.insideBorder(bot)){ + scriptAPI.walkTo(flaxzone.randomLoc) + } else if(flaxzone.insideBorder(bot)) { + var flax = scriptAPI.getNearestNode(2646, true) + scriptAPI.interact(bot,flax,"pick") + } + if(bot.inventory.getAmount(Items.FLAX_1779) > 27){ + sLadderSwitch = true + state = State.TO_SPINNER + } + } + + State.TO_SPINNER -> { + if(sLadderSwitch){ + if(!spinnerbottomLadder.insideBorder(bot.location)){ + scriptAPI.walkTo(spinnerbottomLadder.randomLoc) + } else { + val ladder = scriptAPI.getNearestNode("Staircase", true) + if(ladder != null){ + ladder.interaction.handle(bot, ladder.interaction[0]) + sLadderSwitch = false + } else { + scriptAPI.walkTo(spinnerbottomLadder.randomLoc) + } + } + } + if(stage == 0) + Pathfinder.find(bot, Location.create(2475,3399, 1)).walk(bot).also { stage++ } + when(bot.location){ + Location.create(2475,3399, 1) -> Pathfinder.find(bot, Location.create(2477, 3399,1)).walk(bot) + Location.create(2477,3399, 1) -> Pathfinder.find(bot, Location.create(2477,3398, 1)).walk(bot) + Location.create(2477,3398, 1) -> Pathfinder.find(bot, Location.create(2476,3398, 1)).walk(bot) + Location.create(2476,3398, 1) -> { + val spinner = scriptAPI.getNearestNode(2644, true) + bot.faceLocation(spinner?.location) + bot.pulseManager.run(object: MovementPulse(bot,spinner, DestinationFlag.OBJECT){ + override fun pulse(): Boolean { + bot.faceLocation(spinner?.location) + state = State.SPINNING + return true + } + }) + } + } + } + + State.SPINNING -> { + bot.pulseManager.run(SpinningPulse(bot, Item(Items.FLAX_1779),bot.inventory.getAmount(Items.FLAX_1779),SpinningItem.FLAX)) + sLadderSwitch = true + state = State.FIND_BANK + } + + State.FIND_BANK -> { + if(sLadderSwitch){ + val ladder = scriptAPI.getNearestNode("staircase", true) + if(ladder != null){ + ladder.interaction.handle(bot, ladder.interaction[0]) + sLadderSwitch = false + } + } + if(!bankbottomLadder.insideBorder(bot.location) && !spinnertopLadder.insideBorder(bot)){ + scriptAPI.walkTo(bankbottomLadder.randomLoc) + }else if(bankbottomLadder.insideBorder(bot)){ + bLadderSwitch = true + } + if(bLadderSwitch){ + val ladder = scriptAPI.getNearestNode("staircase", true) + if(ladder != null){ + ladder.interaction.handle(bot, ladder.interaction[0]) + bLadderSwitch = false + } + } + if(banktopLadder.insideBorder(bot)){ + state = State.BANKING + } + } + + State.BANKING -> { + val bank = scriptAPI.getNearestNode(2213, true) + if(bank != null) { + bot.pulseManager.run(object : MovementPulse(bot, bank, DestinationFlag.OBJECT) { + override fun pulse(): Boolean { + bot.faceLocation(bank.location) + scriptAPI.bankItem(Items.BOW_STRING_1777) + return true + } + }) + } + if(ContentAPI.freeSlots(bot) > 27){ + bLadderSwitch = true + state = State.RETURN_TO_FLAX + } + } + + State.RETURN_TO_FLAX -> { + if(!banktopLadder.insideBorder(bot.location) && bLadderSwitch){ + scriptAPI.walkTo(banktopLadder.randomLoc) + } else if(bLadderSwitch){ + val ladder = scriptAPI.getNearestNode("Staircase", true) + if(ladder != null){ + ladder.interaction.handle(bot, ladder.interaction[0]) + bLadderSwitch = false + } else { + scriptAPI.walkTo(banktopLadder.randomLoc) + } + } + if(!flaxzone.insideBorder(bot)){ + scriptAPI.walkTo(flaxzone.randomLoc) + } else if(flaxzone.insideBorder(bot)){ + state = State.PICKING + } + } + } + } + override fun newInstance(): Script { + TODO("Not yet implemented") + } +} +enum class State { + PICKING, + MINING, + SPINNING, + TO_SPINNER, + FIND_BANK, + RETURN_TO_FLAX, + BANKING, + INIT +} diff --git a/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt b/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt index 8374cb7be..4705a3e5c 100644 --- a/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt +++ b/Server/src/main/kotlin/rs09/game/content/activity/barrows/RewardChest.kt @@ -85,8 +85,7 @@ object RewardChest { } } val rewards: MutableList = ArrayList() - var maxRolls = 2 + RandomFunction.random(0,player.savedData.activityData.barrowKills / 3) - if(maxRolls > 6) maxRolls = 6 + var maxRolls = 2 + RandomFunction.random(1,4) for (i in 0 until maxRolls) { rewards.addAll(DROP_TABLE.roll()) } diff --git a/Server/src/main/kotlin/rs09/game/content/quest/free/dragonslayer/NedDialogue.kt b/Server/src/main/kotlin/rs09/game/content/quest/free/dragonslayer/NedDialogue.kt index 1c4ff72aa..3e1c93f67 100644 --- a/Server/src/main/kotlin/rs09/game/content/quest/free/dragonslayer/NedDialogue.kt +++ b/Server/src/main/kotlin/rs09/game/content/quest/free/dragonslayer/NedDialogue.kt @@ -222,21 +222,23 @@ class NedDialogue(player: Player? = null) : DialoguePlugin(player) { if (diary == null) { diary = player.achievementDiaryManager.getDiary(DiaryType.LUMBRIDGE) } - if (diary!!.isComplete(level, false) && !diary!!.isLevelRewarded(level)) { - player("I've done all the hard tasks in my Lumbridge", "Achievement Diary.") + if (diary!!.isComplete(level, true) && !diary!!.isLevelRewarded(level)) { + player("I've done all the medium tasks in my Lumbridge", "Achievement Diary.") stage = 950 } - if (diary!!.isLevelRewarded(level) && diary!!.isComplete(level, true) && !player.hasItem(diary!!.type.getRewards(level)[0])) { + else if (diary!!.isLevelRewarded(level) && diary!!.isComplete(level, true) && !player.hasItem(diary!!.type.getRewards(level)[0])) { player("I've seemed to have lost my explorer's ring...") stage = 960 } - options( - "What is the Achievement Diary?", - "What are the rewards?", - "How do I claim the rewards?", - "See you later." - ) - stage = 901 + else { + options( + "What is the Achievement Diary?", + "What are the rewards?", + "How do I claim the rewards?", + "See you later." + ) + stage = 901 + } } 901 -> when (buttonId) { 1 -> { diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt index ac4c1b321..703659303 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt @@ -61,7 +61,10 @@ enum class FarmingPatch(val varpIndex: Int, val varpOffset: Int, val type: Patch //Spirit Tree ETCETERIA_SPIRIT_TREE(507,8,PatchType.SPIRIT_TREE), PORT_SARIM_SPIRIT_TREE(507,0,PatchType.SPIRIT_TREE), - KARAMJA_SPIRIT_TREE(507,16,PatchType.SPIRIT_TREE); + KARAMJA_SPIRIT_TREE(507,16,PatchType.SPIRIT_TREE), + + //Other + DRAYNOR_BELLADONNA(512, 16, PatchType.BELLADONNA); companion object { @JvmField diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FruitAndBerryPicker.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FruitAndBerryPicker.kt index 69b2b21ae..1df49e318 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FruitAndBerryPicker.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FruitAndBerryPicker.kt @@ -1,5 +1,6 @@ package rs09.game.node.entity.skill.farming +import api.ContentAPI import core.cache.def.impl.SceneryDefinition import core.game.interaction.OptionHandler import core.game.node.Node @@ -23,6 +24,7 @@ class FruitAndBerryPicker : OptionHandler() { SceneryDefinition.setOptionHandler("pick-papaya",this) SceneryDefinition.setOptionHandler("pick-leaf",this) SceneryDefinition.setOptionHandler("pick-from",this) + SceneryDefinition.setOptionHandler("pick-fruit",this) return this } @@ -58,7 +60,7 @@ class FruitAndBerryPicker : OptionHandler() { player.pulseManager.run(object : Pulse(animation.duration){ override fun pulse(): Boolean { player.animator.animate(animation) - player.inventory.add(reward) + ContentAPI.addItemOrDrop(player,reward.id,reward.amount) player.skills.addExperience(Skills.FARMING,plantable.harvestXP) patch.setCurrentState(patch.getCurrentState() - 1) diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/HealthChecker.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/HealthChecker.kt index f65466443..59df17019 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/HealthChecker.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/HealthChecker.kt @@ -30,7 +30,10 @@ class HealthChecker : OptionHandler(){ return true } + if(!patch.isCheckHealth) return true + player.skills.addExperience(Skills.FARMING,patch.plantable?.checkHealthXP ?: 0.0) + patch.isCheckHealth = false when(type){ PatchType.TREE -> patch.setCurrentState(patch.getCurrentState() + 1) PatchType.FRUIT_TREE -> patch.setCurrentState(patch.getCurrentState() - 14) @@ -42,7 +45,7 @@ class HealthChecker : OptionHandler(){ patch.nextGrowth = TimeUnit.MINUTES.toMillis(45) } - patch.isCheckHealth = false + patch.update() return true } diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt index cd53f8e25..285c2571c 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt @@ -53,7 +53,6 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl PatchType.BUSH -> player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,250 + (plantable!!.ordinal - Plantable.REDBERRY_SEED.ordinal)) else -> SystemLogger.logWarn("Invalid setting of isCheckHealth for patch type: " + patch.type.name) } - isCheckHealth = false } else { when(patch.type){ PatchType.ALLOTMENT,PatchType.FLOWER,PatchType.HOPS -> { @@ -63,6 +62,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl PatchType.BUSH -> { if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,getBushDeathValue()) else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,getBushDiseaseValue()) + else player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, plantable?.value ?: 0 + currentGrowthStage) } PatchType.TREE -> { if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset + 7,1) @@ -72,6 +72,11 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset,getFruitTreeDeathValue()) else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getFruitTreeDiseaseValue()) } + PatchType.BELLADONNA -> { + if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getBelladonnaDeathValue()) + else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getBelladonnaDiseaseValue()) + else player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, (plantable?.value ?: 0) + currentGrowthStage) + } else -> {} } } @@ -110,11 +115,19 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl } private fun getFruitTreeDiseaseValue(): Int { - return (plantable?.value ?: 0) + currentGrowthStage + 13 + return (plantable?.value ?: 0) + currentGrowthStage + 12 } private fun getFruitTreeDeathValue(): Int { - return (plantable?.value ?: 0) + currentGrowthStage + 19 + return (plantable?.value ?: 0) + currentGrowthStage + 18 + } + + private fun getBelladonnaDiseaseValue(): Int { + return (plantable?.value ?: 0) + currentGrowthStage + 4 + } + + private fun getBelladonnaDeathValue(): Int { + return (plantable?.value ?: 0) + currentGrowthStage + 7 } private fun grow(){ @@ -154,7 +167,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl } } - if(plantable?.stages ?: 0 > currentGrowthStage){ + if(plantable?.stages ?: 0 > currentGrowthStage && !isGrown()){ currentGrowthStage++ setCurrentState(getCurrentState() + 1) isWatered = false diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt index 11ce96b62..bd66f56a8 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt @@ -8,5 +8,6 @@ enum class PatchType(val stageGrowthTime: Int) { BUSH(20), FLOWER(5), HERB(20), - SPIRIT_TREE(293) + SPIRIT_TREE(293), + BELLADONNA(80) } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt index cfeb444e9..5de521b1f 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt @@ -67,13 +67,16 @@ enum class Plantable(val itemID: Int, val value: Int, val stages: Int, val plant RANARR_SEED(5295,39,4,27.0,30.5,0.0,32,PatchType.HERB,Items.GRIMY_RANARR_207), TOADFLAX_SEED(5296,47,4,34.0,38.5,0.0,38,PatchType.HERB,Items.GRIMY_TOADFLAX_3049), IRIT_SEED(5297,54,4,43.0,48.5,0.0,44,PatchType.HERB,Items.GRIMY_IRIT_209), - AVANTOE_SEED(5298,61,4,54.5,61.5,0.0,50,PatchType.HERB,Items.GRIMY_AVANTOE_211), + AVANTOE_SEED(5298,204,4,54.5,61.5,0.0,50,PatchType.HERB,Items.GRIMY_AVANTOE_211), KWUARM_SEED(5299,68,4,69.0,78.0,0.0,56,PatchType.HERB,Items.GRIMY_KWUARM_213), SNAPDRAGON_SEED(5300,75,4,87.5,98.5,0.0,62,PatchType.HERB,Items.GRIMY_SNAPDRAGON_3051), CADANTINE_SEED(5301,82,4,106.5,120.0,0.0,67,PatchType.HERB,Items.GRIMY_CADANTINE_215), LANTADYME_SEED(5302,89,4,134.5,151.5,0.0,73,PatchType.HERB,Items.GRIMY_LANTADYME_2485), DWARF_WEED_SEED(5303,96,4,170.5,192.0,0.0,79,PatchType.HERB,Items.GRIMY_DWARF_WEED_217), - TORSTOL_SEED(5304,103,4,199.5,224.5,0.0,85,PatchType.HERB,Items.GRIMY_TORSTOL_219) + TORSTOL_SEED(5304,103,4,199.5,224.5,0.0,85,PatchType.HERB,Items.GRIMY_TORSTOL_219), + + //Other + BELLADONNA_SEED(5281, 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA, Items.CAVE_NIGHTSHADE_2398) ; constructor(itemID: Int, value: Int, stages: Int, plantingXP: Double, harvestXP: Double, checkHealthXP: Double, requiredLevel: Int, applicablePatch: PatchType, harvestItem: Int, protectionFlower: Plantable) diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/GatheringSkillOptionListeners.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/GatheringSkillOptionListeners.kt index 706cad747..efc3903cb 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/GatheringSkillOptionListeners.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/GatheringSkillOptionListeners.kt @@ -35,6 +35,7 @@ class GatheringSkillOptionListeners : InteractionListener() { on(NPC,"bait"){player,node -> return@on fish(player,node,"bait")} on(NPC,"harpoon"){player,node -> return@on fish(player,node,"harpoon")} on(NPC,"cage"){player,node -> return@on fish(player,node,"cage")} + on(NPC,"fish"){player, node -> return@on fish(player,node,"fish") } } fun fish(player: Player, node: Node, opt: String): Boolean{ diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/runecrafting/abyss/AbyssPlugin.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/runecrafting/abyss/AbyssPlugin.kt new file mode 100644 index 000000000..d3342ea4a --- /dev/null +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/runecrafting/abyss/AbyssPlugin.kt @@ -0,0 +1,468 @@ +package core.game.node.entity.skill.runecrafting.abyss + +import api.ContentAPI +import rs09.plugin.PluginManager.definePlugin +import rs09.tools.stringtools.colorize +import rs09.game.system.SystemLogger.logInfo +import core.game.node.`object`.Scenery +import core.game.node.entity.impl.Animator +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.node.entity.skill.Skills +import core.game.node.entity.skill.gather.SkillingTool +import core.game.node.entity.skill.runecrafting.Altar +import core.game.system.task.Pulse +import core.game.world.map.Location +import core.game.world.update.flag.context.Animation +import core.game.world.update.flag.context.Graphics +import core.tools.RandomFunction +import org.rs09.consts.NPCs +import rs09.game.interaction.InteractionListener +import rs09.game.world.GameWorld + +/** + * A plugin used to handle the abyss. + * @author cfunny + */ +class AbyssPlugin : InteractionListener() { + + val OBSTACLE = AbbysalObstacle.values().filter { it != AbbysalObstacle.MINE && it != AbbysalObstacle.SQUEEZE }.map { it.option }.toTypedArray() + val miningObstacle = 7158 + val agilityObstacle = 7164 + + override fun defineListeners() { + definePlugin(AbyssalNPC()) + definePlugin(DarkMageDialogue()) + definePlugin(ZamorakMageDialogue()) + on(NPCs.MAGE_OF_ZAMORAK_2259, NPC, "teleport"){ player, node -> + teleport(player, node as NPC) + return@on true + } + on(NPCs.DARK_MAGE_2262, NPC, "repair-pouches"){ player, node -> + player.dialogueInterpreter.open(node.id, node, true) + return@on true + } + on(SCENERY, "exit-through"){ player, node -> + val altar = Altar.forObject(node as Scenery) + altar?.enterRift(player) + return@on true + } + on(SCENERY, *OBSTACLE){ player, node -> + val obstacle = AbbysalObstacle.forObject(node as Scenery) + obstacle!!.handle(player, node as Scenery) + return@on true + } + on(miningObstacle, SCENERY, "mine"){ player, node -> + val obstacle = AbbysalObstacle.forObject(node as Scenery) + obstacle!!.handle(player, node as Scenery) + return@on true + } + on(agilityObstacle, SCENERY, "squeeze-through"){ player, node -> + val obstacle = AbbysalObstacle.forObject(node as Scenery) + obstacle!!.handle(player, node as Scenery) + return@on true + } + + + } + + /** + * Represents an obstacle in an abbsyal. + * @author cfunny + * @date 02/11/2013 + */ + enum class AbbysalObstacle( + /** + * Represents the option. + */ + var option: String, + /** + * Represents the corssing location. + */ + val locations: Array, + /** + * Represents the object id. + */ + vararg val objects: Int + ) { + BOIL("burn-down", arrayOf(Location.create(3024, 4833, 0), Location.create(3053, 4830, 0)), 7165) { + override fun handle(player: Player, `object`: Scenery?) { + `object` ?: return + if (!ContentAPI.inInventory(player, 590, 1)) { + ContentAPI.sendMessage(player, "You don't have a tinderbox to burn it.") + return + } + player.animate(Animation(733)) + player.lock() + GameWorld.Pulser.submit(object : Pulse(1, player) { + var count = 0 + override fun pulse(): Boolean { + when (count) { + 1 -> ContentAPI.sendMessage(player, "You attempt to burn your way through..") + 4 -> return if (RandomFunction.random(100) < ContentAPI.getStatLevel( + player, + Skills.FIREMAKING + ) + ) { + ContentAPI.sendMessage( + player, + colorize("%G...and manage to burn it down and get past.") + ) + player.properties.teleportLocation = locations[getIndex(`object`)] + player.unlock() + true + } else { + ContentAPI.sendMessage(player, colorize("%RYou fail to set it on fire.")) + player.unlock() + true + } + } + count++ + return false + } + + override fun stop() { + super.stop() + player.animate(Animation(-1, Animator.Priority.HIGH)) + } + }) + } + }, + MINE("mine", arrayOf(Location.create(3030, 4821, 0), Location.create(3048, 4822, 0)), 7158, 7153) { + override fun handle(player: Player, `object`: Scenery?) { + `object` ?: return + logInfo("handled abyss mine") + val tool: SkillingTool = ContentAPI.getTool(player, true) ?: return + if (tool == null) { + ContentAPI.sendMessage(player, "You need a pickaxe in order to do that.") + return + } + player.animate(tool.getAnimation()) + player.lock() + GameWorld.Pulser.submit(object : Pulse(1, player) { + var count = 0 + override fun pulse(): Boolean { + when (count) { + 1 -> ContentAPI.sendMessage(player, "You attempt to mine your way through..") + 4 -> return if (RandomFunction.random(100) < ContentAPI.getStatLevel( + player, + Skills.MINING + ) + ) { + ContentAPI.sendMessage(player, colorize("%G...and manage to break through the rock.")) + player.properties.teleportLocation = locations[getIndex(`object`)] + player.unlock() + true + } else { + ContentAPI.sendMessage(player, colorize("%R...but fail to break-up the rock.")) + player.unlock() + true + } + } + count++ + return false + } + + override fun stop() { + super.stop() + player.animate(Animation(-1, Animator.Priority.HIGH)) + } + }) + } + }, + CHOP("chop", arrayOf(Location.create(3050, 4824, 0), Location.create(3028, 4824, 0)), 7161, 7144) { + override fun handle(player: Player, `object`: Scenery?) { + `object` ?: return + val tool: SkillingTool? = setTool(false, player) + if (tool == null) { + player.packetDispatch.sendMessage("You need an axe in order to do that.") + return + } + player.animate(tool.getAnimation()) + player.lock() + GameWorld.Pulser.submit(object : Pulse(1, player) { + var count = 0 + override fun pulse(): Boolean { + when (count) { + 1 -> ContentAPI.sendMessage(player, "You attempt to chop your way through...") + 4 -> return if (RandomFunction.random(100) < ContentAPI.getStatLevel( + player, + Skills.WOODCUTTING + ) + ) { + ContentAPI.sendMessage(player, colorize("%G...and manage to chop down the tendrils.")) + player.properties.teleportLocation = locations[getIndex(`object`)] + player.unlock() + true + } else { + ContentAPI.sendMessage(player, colorize("%RYou fail to cut through the tendrils.")) + player.unlock() + true + } + } + count++ + return false + } + + override fun stop() { + super.stop() + player.animate(Animation(-1, Animator.Priority.HIGH)) + } + }) + } + }, + SQUEEZE( + "squeeze-through", + arrayOf(Location.create(3048, 4842, 0), Location.create(3031, 4842, 0)), + 7164, + 7147 + ) { + override fun handle(player: Player, `object`: Scenery?) { + `object` ?: return + player.animate(Animation(1331)) + player.lock() + GameWorld.Pulser.submit(object : Pulse(1, player) { + var count = 0 + override fun pulse(): Boolean { + when (count) { + 1 -> ContentAPI.sendMessage(player, "You attempt to squeeze through the narrow gap...") + 4 -> return if (RandomFunction.random(100) < ContentAPI.getStatLevel( + player, + Skills.AGILITY + ) + ) { + ContentAPI.sendMessage(player, colorize("%G...and you manage to crawl through.")) + player.properties.teleportLocation = locations[getIndex(`object`)] + player.unlock() + true + } else { + ContentAPI.sendMessage(player, colorize("%RYou fail to squeeze through the narrow gap")) + player.unlock() + true + } + } + count++ + return false + } + + override fun stop() { + super.stop() + player.animate(Animation(-1, Animator.Priority.HIGH)) + } + }) + } + }, + DISTRACT("distract", arrayOf(Location.create(3029, 4841, 0), Location.create(3051, 4838, 0)), 7168, 7150) { + override fun handle(player: Player, `object`: Scenery?) { + `object` ?: return + val emotes = intArrayOf( + 855, + 856, + 857, + 858, + 859, + 860, + 861, + 862, + 863, + 864, + 865, + 866, + 2113, + 2109, + 2111, + 2106, + 2107, + 2108, + 0x558, + 2105, + 2110, + 2112, + 0x84F, + 0x850, + 1131, + 1130, + 1129, + 1128, + 1745, + 3544, + 3543, + 2836 + ) + val index: Int = RandomFunction.random(emotes.size) + player.animate(Animation(emotes[index])) + player.lock() + GameWorld.Pulser.submit(object : Pulse(1, player) { + var count = 0 + override fun pulse(): Boolean { + when (count) { + 1 -> ContentAPI.sendMessage(player, "You use your thieving skills to misdirect the eyes...") + 4 -> return if (RandomFunction.random(100) < ContentAPI.getStatLevel( + player, + Skills.THIEVING + ) + ) { + ContentAPI.sendMessage( + player, + colorize("%G...and sneak past while they're not looking.") + ) + player.properties.teleportLocation = locations[getIndex(`object`)] + player.unlock() + true + } else { + ContentAPI.sendMessage(player, colorize("%RYou fail to distract the eyes.")) + player.unlock() + true + } + } + count++ + return false + } + + override fun stop() { + super.stop() + player.animate(Animation(-1, Animator.Priority.HIGH)) + } + }) + } + }, + PASSAGE("go-through", arrayOf(Location.create(3040, 4844, 0)), 7154) { + override fun handle(player: Player, `object`: Scenery?) { + player.properties.teleportLocation = locations[0] + } + }; + /** + * Gets the option. + * @return The option. + */ + /** + * Gets the locations. + * @return The locations. + */ + /** + * Gets the objects. + * @return The objects. + */ + + /** + * Method used to get the index. + * @param object the object. + * @return the index. + */ + fun getIndex(`object`: Scenery): Int { + for (i in objects.indices) { + if (objects[i] == `object`.getId()) { + return i + } + } + return 0 + } + + /** + * Method used to handle the obstacle. + * @param player the player. + * @param object the object. + */ + open fun handle(player: Player, `object`: Scenery?) {} + + companion object { + /** + * Method used to get the abbysal obstacle. + * @param object the object. + * @return the `AbbysalObstacle` or `Null`. + */ + fun forObject(`object`: Scenery): AbbysalObstacle? { + for (obstacle in values()) { + for (i in obstacle.objects) { + if (i == `object`.getId()) { + return obstacle + } + } + } + return null + } + + /** + * Sets the tool used. + */ + private fun setTool(mining: Boolean, player: Player): SkillingTool? { + var tool: SkillingTool? = null + if (!mining) { + if (checkTool(player, SkillingTool.DRAGON_AXE)) { + tool = SkillingTool.DRAGON_AXE + } else if (checkTool(player, SkillingTool.RUNE_AXE)) { + tool = SkillingTool.RUNE_AXE + } else if (checkTool(player, SkillingTool.ADAMANT_AXE)) { + tool = SkillingTool.ADAMANT_AXE + } else if (checkTool(player, SkillingTool.MITHRIL_AXE)) { + tool = SkillingTool.MITHRIL_AXE + } else if (checkTool(player, SkillingTool.BLACK_AXE)) { + tool = SkillingTool.BLACK_AXE + } else if (checkTool(player, SkillingTool.STEEL_AXE)) { + tool = SkillingTool.STEEL_AXE + } else if (checkTool(player, SkillingTool.IRON_AXE)) { + tool = SkillingTool.IRON_AXE + } else if (checkTool(player, SkillingTool.BRONZE_AXE)) { + tool = SkillingTool.BRONZE_AXE + } + } else { + if (checkTool(player, SkillingTool.RUNE_PICKAXE)) { + tool = SkillingTool.RUNE_PICKAXE + } else if (checkTool(player, SkillingTool.ADAMANT_PICKAXE)) { + tool = SkillingTool.ADAMANT_PICKAXE + } else if (checkTool(player, SkillingTool.MITHRIL_PICKAXE)) { + tool = SkillingTool.MITHRIL_PICKAXE + } else if (checkTool(player, SkillingTool.STEEL_PICKAXE)) { + tool = SkillingTool.STEEL_PICKAXE + } else if (checkTool(player, SkillingTool.IRON_PICKAXE)) { + tool = SkillingTool.IRON_PICKAXE + } else if (checkTool(player, SkillingTool.BRONZE_PICKAXE)) { + tool = SkillingTool.BRONZE_PICKAXE + } + } + return tool + } + + /** + * Checks if the player has a tool and if he can use it. + * @param tool The tool. + * @return `True` if the tool is usable. + */ + private fun checkTool(player: Player, tool: SkillingTool): Boolean { + return if (player.equipment.contains(tool.getId(), 1)) { + true + } else player.inventory.contains(tool.getId(), 1) + } + } + + /** + * Constructs a new `RunecraftingOptionPlugin` `Object`. + * @param locations the locations. + * @param objects the objects. + */ + init { + option = option + } + } + + companion object { + /** + * Represents the teleporting to the abyss. + * @param player the player. + */ + fun teleport(player: Player, npc: NPC) { + player.lock(3) + npc.visualize(Animation(1979), Graphics(4)) + npc.sendChat("Veniens! Sallakar! Rinnesset!") + player.skills.decrementPrayerPoints(100.0) + player.skullManager.checkSkull(player) + GameWorld.Pulser.submit(object : Pulse(2, player) { + override fun pulse(): Boolean { + player.properties.teleportLocation = Location.create(3021, 4847, 0) + npc.updateMasks.reset() + return true + } + }) + } + } +} \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt index 2297a85aa..e5ae69574 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt @@ -113,7 +113,7 @@ class FarmingState(player: Player? = null) : State(player) { } } - if((savedState - (patch?.plantable?.value ?: 0)) > patch.plantable?.value ?: 0 + patch.currentGrowthStage){ + if((savedState - (patch?.plantable?.value ?: 0)) > patch.currentGrowthStage){ patch.setCurrentState(savedState) } else { patch.setCurrentState((patch.plantable?.value ?: 0) + patch.currentGrowthStage) diff --git a/Server/src/main/kotlin/rs09/net/packet/PacketWriteQueue.kt b/Server/src/main/kotlin/rs09/net/packet/PacketWriteQueue.kt index cd20b29f9..2262c397f 100644 --- a/Server/src/main/kotlin/rs09/net/packet/PacketWriteQueue.kt +++ b/Server/src/main/kotlin/rs09/net/packet/PacketWriteQueue.kt @@ -29,7 +29,7 @@ object PacketWriteQueue { @JvmStatic fun flush(){ while(!PacketsToWrite.isEmpty()){ - val p = PacketsToWrite.poll() + val p = PacketsToWrite.poll() ?: continue write(p.out,p.context) } }