From 80c8b219ead162da62b644f698352667372b54e2 Mon Sep 17 00:00:00 2001 From: GregF Date: Wed, 3 Jun 2026 11:19:33 +0000 Subject: [PATCH 1/3] Rewrote the cooking skill, which fixes a number of bugs and broken recipes --- Server/data/configs/item_configs.json | 6 +- .../content/data/consumables/Consumables.java | 2 + .../global/skill/cooking/CakeListener.kt | 39 +++++ .../skill/cooking/CakeMakingPlugin.java | 69 --------- .../global/skill/cooking/CoconutListener.kt | 31 ++++ .../skill/cooking/CoconutMakePlugin.java | 56 -------- .../skill/cooking/CookingRecipePlugin.java | 134 ------------------ .../global/skill/cooking/PieShellPlugin.java | 56 -------- .../skill/cooking/SkeweredFoodListener.kt | 38 +++++ .../skill/cooking/SkeweredFoodPlugin.java | 115 --------------- .../skill/cooking/WatermelonSliceListener.kt | 20 +++ .../skill/cooking/WatermelonSlicePlugin.java | 59 -------- .../skill/cooking/WineFermentListener.kt | 30 ++++ .../skill/cooking/WineFermentPlugin.java | 63 -------- .../cooking/recipe/ChocolateCakeListener.kt | 31 ++++ .../skill/cooking/recipe/CurryListener.kt | 37 +++++ .../global/skill/cooking/recipe/MixHandler.kt | 72 ++++++++++ .../global/skill/cooking/recipe/MixScript.kt | 57 ++++++++ .../skill/cooking/recipe/OomlieWrap.java | 57 -------- .../cooking/recipe/OomlieWrapListener.kt | 29 ++++ .../skill/cooking/recipe/PieListener.kt | 79 +++++++++++ .../skill/cooking/recipe/PieShellListener.kt | 29 ++++ .../skill/cooking/recipe/PizzaListener.kt | 66 +++++++++ .../skill/cooking/recipe/PotatoListener.kt | 77 ++++++++++ .../global/skill/cooking/recipe/Recipe.java | 134 ------------------ .../skill/cooking/recipe/StewListener.kt | 62 ++++++++ .../skill/cooking/recipe/ToppingListener.kt | 84 +++++++++++ .../cooking/recipe/cake/ChocolateCake.java | 72 ---------- .../skill/cooking/recipe/pie/PieRecipe.java | 38 ----- .../cooking/recipe/pie/impl/AdmiralPie.java | 64 --------- .../cooking/recipe/pie/impl/ApplePie.java | 34 ----- .../cooking/recipe/pie/impl/FishPie.java | 64 --------- .../cooking/recipe/pie/impl/GardenPie.java | 64 --------- .../cooking/recipe/pie/impl/MeatPie.java | 58 -------- .../skill/cooking/recipe/pie/impl/MudPie.java | 64 --------- .../cooking/recipe/pie/impl/RedberryPie.java | 33 ----- .../cooking/recipe/pie/impl/SummerPie.java | 64 --------- .../cooking/recipe/pie/impl/WildPie.java | 64 --------- .../cooking/recipe/pizza/PizzaRecipe.java | 63 -------- .../recipe/pizza/impl/AnchovyPizza.java | 44 ------ .../cooking/recipe/pizza/impl/MeatPizza.java | 49 ------- .../recipe/pizza/impl/PineapplePizza.java | 55 ------- .../cooking/recipe/pizza/impl/PlainPizza.java | 81 ----------- .../cooking/recipe/potato/PotatoRecipe.java | 76 ---------- .../recipe/potato/impl/ButterPotato.java | 72 ---------- .../recipe/potato/impl/CheesePotato.java | 49 ------- .../recipe/potato/impl/ChilliPotato.java | 49 ------- .../cooking/recipe/potato/impl/EggPotato.java | 49 ------- .../recipe/potato/impl/MushroomPotato.java | 49 ------- .../recipe/potato/impl/TunaPotato.java | 49 ------- .../cooking/recipe/stew/CurryRecipe.java | 89 ------------ .../skill/cooking/recipe/stew/StewRecipe.java | 92 ------------ .../cooking/recipe/topping/ToppingRecipe.java | 58 -------- .../recipe/topping/impl/ChilliConCarne.java | 81 ----------- .../recipe/topping/impl/ChoppedOnion.java | 69 --------- .../recipe/topping/impl/ChoppedTuna.java | 69 --------- .../recipe/topping/impl/EggAndTomato.java | 72 ---------- .../recipe/topping/impl/MushroomAndOnion.java | 72 ---------- .../recipe/topping/impl/SlicedMushroom.java | 69 --------- .../recipe/topping/impl/SpicySauce.java | 84 ----------- .../recipe/topping/impl/TunaAndCorn.java | 72 ---------- .../recipe/topping/impl/UncookedEgg.java | 54 ------- 62 files changed, 788 insertions(+), 2929 deletions(-) create mode 100644 Server/src/main/content/global/skill/cooking/CakeListener.kt delete mode 100644 Server/src/main/content/global/skill/cooking/CakeMakingPlugin.java create mode 100644 Server/src/main/content/global/skill/cooking/CoconutListener.kt delete mode 100644 Server/src/main/content/global/skill/cooking/CoconutMakePlugin.java delete mode 100644 Server/src/main/content/global/skill/cooking/CookingRecipePlugin.java delete mode 100644 Server/src/main/content/global/skill/cooking/PieShellPlugin.java create mode 100644 Server/src/main/content/global/skill/cooking/SkeweredFoodListener.kt delete mode 100644 Server/src/main/content/global/skill/cooking/SkeweredFoodPlugin.java create mode 100644 Server/src/main/content/global/skill/cooking/WatermelonSliceListener.kt delete mode 100644 Server/src/main/content/global/skill/cooking/WatermelonSlicePlugin.java create mode 100644 Server/src/main/content/global/skill/cooking/WineFermentListener.kt delete mode 100644 Server/src/main/content/global/skill/cooking/WineFermentPlugin.java create mode 100644 Server/src/main/content/global/skill/cooking/recipe/ChocolateCakeListener.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/CurryListener.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/MixHandler.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/MixScript.kt delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/OomlieWrap.java create mode 100644 Server/src/main/content/global/skill/cooking/recipe/OomlieWrapListener.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/PieListener.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/PieShellListener.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/PizzaListener.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/PotatoListener.kt delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/Recipe.java create mode 100644 Server/src/main/content/global/skill/cooking/recipe/StewListener.kt create mode 100644 Server/src/main/content/global/skill/cooking/recipe/ToppingListener.kt delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/cake/ChocolateCake.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/PieRecipe.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/AdmiralPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/ApplePie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/FishPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/GardenPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/MeatPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/MudPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/RedberryPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/SummerPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pie/impl/WildPie.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pizza/PizzaRecipe.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pizza/impl/AnchovyPizza.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pizza/impl/MeatPizza.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PineapplePizza.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PlainPizza.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/potato/PotatoRecipe.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/potato/impl/ButterPotato.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/potato/impl/CheesePotato.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/potato/impl/ChilliPotato.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/potato/impl/EggPotato.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/potato/impl/MushroomPotato.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/potato/impl/TunaPotato.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/stew/CurryRecipe.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/stew/StewRecipe.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/ToppingRecipe.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChilliConCarne.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedOnion.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedTuna.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/EggAndTomato.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/MushroomAndOnion.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/SlicedMushroom.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/SpicySauce.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/TunaAndCorn.java delete mode 100644 Server/src/main/content/global/skill/cooking/recipe/topping/impl/UncookedEgg.java diff --git a/Server/data/configs/item_configs.json b/Server/data/configs/item_configs.json index 64b2c1e89..33454ce50 100644 --- a/Server/data/configs/item_configs.json +++ b/Server/data/configs/item_configs.json @@ -20859,8 +20859,10 @@ { "ge_buy_limit": "200", "grand_exchange_price": "177", + "examine": "I need to add some meat too.", "durability": null, "name": "Incomplete stew", + "tradeable": "true", "archery_ticket_price": "0", "id": "1997" }, @@ -20876,8 +20878,10 @@ { "ge_buy_limit": "200", "grand_exchange_price": "210", + "examine": "I need to add some potato too.", "durability": null, "name": "Incomplete stew", + "tradeable": "true", "archery_ticket_price": "0", "id": "1999" }, @@ -64514,7 +64518,7 @@ }, { "ge_buy_limit": "10000", - "examine": "Raw sweetcorn.", + "examine": "A bowl of cooked sweetcorn.", "grand_exchange_price": "110", "durability": null, "name": "Sweetcorn", diff --git a/Server/src/main/content/data/consumables/Consumables.java b/Server/src/main/content/data/consumables/Consumables.java index 3730caf32..20cae3a18 100644 --- a/Server/src/main/content/data/consumables/Consumables.java +++ b/Server/src/main/content/data/consumables/Consumables.java @@ -118,6 +118,8 @@ public enum Consumables { EGG_AND_TOMATO(new Food(new int[] {7064, 1923}, new HealingEffect(8))), SWEET_CORN(new Food(new int[] {5988}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(10)))), SWEETCORN_BOWL(new Food(new int[] {7088, 1923}, new MultiEffect(new HealingEffect(1), new PercentageHealthEffect(10)))), + CHOPPED_TUNA(new Food(new int[] {7086, 1923}, new HealingEffect(10))), + CHOPPED_ONION(new Food(new int[] {1871, 1923}, new HealingEffect(1))), POTATO_WITH_BUTTER(new Food(new int[] {6703}, new HealingEffect(7))), CHILLI_POTATO(new Food(new int[] {7054}, new HealingEffect(14))), FRIED_ONIONS(new Food(new int[] {7084, 1923}, new HealingEffect(5))), diff --git a/Server/src/main/content/global/skill/cooking/CakeListener.kt b/Server/src/main/content/global/skill/cooking/CakeListener.kt new file mode 100644 index 000000000..dc8eb948f --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/CakeListener.kt @@ -0,0 +1,39 @@ +package content.global.skill.cooking + +import core.api.* +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.skill.Skills +import org.rs09.consts.Items + +class CakeListener : InteractionListener { + private val cakeArr = intArrayOf( + Items.EGG_1944, + Items.BUCKET_OF_MILK_1927, + Items.POT_OF_FLOUR_1933 + ) + + override fun defineListeners() { + onUseWith(IntType.ITEM, cakeArr, Items.CAKE_TIN_1887) { player, _, _ -> + if (getDynLevel(player, Skills.COOKING) < 40) { + sendMessage(player, "You need a Cooking level of at least 40 in order to do this.") + return@onUseWith true + } + + if(inInventory(player, Items.EGG_1944) && inInventory(player, Items.BUCKET_OF_MILK_1927) && inInventory(player, Items.POT_OF_FLOUR_1933) && inInventory(player, Items.CAKE_TIN_1887)) { + if(removeItem(player, Items.EGG_1944) && removeItem(player, Items.BUCKET_OF_MILK_1927) && removeItem(player, Items.POT_OF_FLOUR_1933) && removeItem(player, Items.CAKE_TIN_1887)){ + addItem(player, Items.EMPTY_POT_1931) + addItem(player, Items.UNCOOKED_CAKE_1889) + addItem(player, Items.BUCKET_1925) + sendMessage(player, "You mix the milk, flour and egg together to make a raw cake mix.") + + } + } + else{ + // Not sure about the authentic message + sendMessage(player, "You don't have enough ingredients to make that.") + } + return@onUseWith true + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/CakeMakingPlugin.java b/Server/src/main/content/global/skill/cooking/CakeMakingPlugin.java deleted file mode 100644 index 084abf4c4..000000000 --- a/Server/src/main/content/global/skill/cooking/CakeMakingPlugin.java +++ /dev/null @@ -1,69 +0,0 @@ -package content.global.skill.cooking; - -import core.game.interaction.NodeUsageEvent; -import core.game.interaction.UseWithHandler; -import core.game.node.item.Item; -import core.plugin.Initializable; -import core.plugin.Plugin; - -/** - * Represents the plugin used to make a cake. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class CakeMakingPlugin extends UseWithHandler { - - /** - * Represents the bucket of milk item. - */ - private static final Item BUCKET_OF_MILK = new Item(1927); - - /** - * Represents the egg item. - */ - private static final Item EGG = new Item(1944); - - /** - * Represents the cake tin item. - */ - private static final Item CAKE_TIN = new Item(1887); - - /** - * Represents the pot of flour item. - */ - private static final Item POT_OF_FLOUR = new Item(1933); - - /** - * Represents the uncooked cake item. - */ - private static final Item UNCOOKED_CAKE = new Item(1889); - - /** - * Constructs a new {@code CakeMakingPlugin} {@code Object}. - */ - public CakeMakingPlugin() { - super(1933); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(1887, ITEM_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - if (event.getUsedItem().getId() == 1887 && ((Item) event.getUsedWith()).getId() == 1933 || event.getUsedWith().getName().equalsIgnoreCase("cake tin") && ((Item) event.getUsedItem()).getName().equalsIgnoreCase("pot of flour")) { - if (event.getPlayer().getInventory().contains(1933, 1) && event.getPlayer().getInventory().contains(1927, 1) && event.getPlayer().getInventory().contains(1944, 1)) { - if (event.getPlayer().getInventory().remove(BUCKET_OF_MILK, EGG, CAKE_TIN, POT_OF_FLOUR)) { - event.getPlayer().getInventory().add(UNCOOKED_CAKE); - event.getPlayer().getPacketDispatch().sendMessage("You mix the milk, flour and egg together to make a raw cake mix."); - return true; - } - } - } - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/CoconutListener.kt b/Server/src/main/content/global/skill/cooking/CoconutListener.kt new file mode 100644 index 000000000..5f7da66d4 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/CoconutListener.kt @@ -0,0 +1,31 @@ +package content.global.skill.cooking + +import core.api.addItem +import core.api.removeItem +import core.api.sendMessage +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class CoconutListener : InteractionListener { + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.COCONUT_5974, Items.HAMMER_2347) { player, used, _ -> + if(removeItem(player, used.id)) { + addItem(player, Items.COCONUT_5976) + sendMessage(player, "You crush the coconut with a hammer.") + return@onUseWith true + } + return@onUseWith false + } + onUseWith(IntType.ITEM, Items.COCONUT_5976, Items.VIAL_229) { player, used, with -> + if(removeItem(player, used.id) && removeItem(player, with.id)) { + addItem(player, Items.COCONUT_SHELL_5978) + addItem(player, Items.COCONUT_MILK_5935) + sendMessage(player, "You overturn the coconut into a vial.") + return@onUseWith true + } + return@onUseWith false + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/CoconutMakePlugin.java b/Server/src/main/content/global/skill/cooking/CoconutMakePlugin.java deleted file mode 100644 index 7520ff115..000000000 --- a/Server/src/main/content/global/skill/cooking/CoconutMakePlugin.java +++ /dev/null @@ -1,56 +0,0 @@ -package content.global.skill.cooking; - -import core.game.interaction.NodeUsageEvent; -import core.game.interaction.UseWithHandler; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.plugin.Initializable; -import core.plugin.Plugin; - -/** - * Represents the plugin used to make a coconut. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class CoconutMakePlugin extends UseWithHandler { - - /** - * Represents the items related to coconut making plugin. - */ - private static final Item[] ITEMS = new Item[] { new Item(5974, 1), new Item(5976, 1), new Item(229), new Item(5935, 1), new Item(5978) }; - - /** - * Constructs a new {@code CoconutMakePlugin} {@code Object}. - */ - public CoconutMakePlugin() { - super(5974, 5976); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(2347, ITEM_TYPE, this); - addHandler(229, ITEM_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - final Item usedWith = (Item) event.getUsedWith(); - if (usedWith.getId() == 5974 && event.getUsedItem().getId() == 2347 || usedWith.getId() == 2347 && event.getUsedItem().getId() == 5974) { - player.getInventory().remove(ITEMS[0]); - player.getInventory().add(ITEMS[1]); - player.getPacketDispatch().sendMessage("You crush the coconut with a hammer."); - } - if (usedWith.getId() == 5976 && event.getUsedItem().getId() == 229 || usedWith.getId() == 229 && event.getUsedItem().getId() == 5976) { - player.getInventory().remove(ITEMS[1]); - player.getInventory().remove(ITEMS[2]); - player.getInventory().add(ITEMS[3]); - player.getInventory().add(ITEMS[4]); - player.getPacketDispatch().sendMessage("You overturn the coconut into a vial."); - } - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/CookingRecipePlugin.java b/Server/src/main/content/global/skill/cooking/CookingRecipePlugin.java deleted file mode 100644 index 067217358..000000000 --- a/Server/src/main/content/global/skill/cooking/CookingRecipePlugin.java +++ /dev/null @@ -1,134 +0,0 @@ -package content.global.skill.cooking; - -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.interaction.UseWithHandler; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.game.system.task.Pulse; -import core.plugin.Initializable; -import core.plugin.Plugin; -import core.game.dialogue.SkillDialogueHandler.SkillDialogue; -import core.game.dialogue.SkillDialogueHandler; - -import java.util.ArrayList; -import java.util.List; - -/** - * Represents a cooking recipe plugin. This is used to handle the multiple - * recipes used in cooking these recipes can range from making a pizza or making - * a pie. - * @author 'Vexia - * @version 1.9 - */ -@Initializable -public final class CookingRecipePlugin extends UseWithHandler { - - /** - * Constructs a new {@code CookingRecipePlugin} {@code Object}. - */ - public CookingRecipePlugin() { - super(getAllowedNodes()); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - for (Recipe recipe : Recipe.RECIPES) { - for (Item ingredient : recipe.getIngredients()) { - addHandler(ingredient.getId(), ITEM_TYPE, this); - } - } - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - Recipe recipe = null; - Item part = null; - // TODO: Transitioning to a Listener would save an O(n) pass through the recipes list on every use-with - recipeloop: - for (Recipe temp : Recipe.RECIPES) { - if (temp.isSingular()) { - if (temp.getBase().getId() == event.getUsedItem().getId() || temp.getBase().getId() == event.getBaseItem().getId()) { - for (Item ingredient : temp.getIngredients()) { - if (ingredient.getId() == event.getBaseItem().getId() || ingredient.getId() == event.getUsedItem().getId()) { - recipe = temp; - break recipeloop; - } - } - } - } else { - for (int k = 0; k < temp.getParts().length; k++) { - for (int i = 0; i < temp.getIngredients().length; i++) { - Item tempPart = temp.getParts()[k]; - Item ingredient = temp.getIngredients()[i]; - if (tempPart.getId() == event.getUsedItem().getId() && ingredient.getId() == event.getBaseItem().getId() || tempPart.getId() == event.getBaseItem().getId() && ingredient.getId() == event.getUsedItem().getId()) { - if (k == i) {// represents that this ingredient can - // mix with the other. - recipe = temp; - part = tempPart; - break recipeloop; - } - } - } - } - } - } - if (recipe != null) { - final Player player = event.getPlayer(); - final Recipe recipe_ = recipe; - final Item part_ = part; - SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, recipe.getProduct()) { - @Override - public void create(final int amount, int index) { - player.getPulseManager().run(new Pulse(2) { - int count = 0; - @Override - public boolean pulse() { - recipe_.mix(player, event); - return ++count >= amount; - } - }); - } - - @Override - public int getAll(int index) { - return player.getInventory().getAmount(part_ != null ? part_ : recipe_.getBase()); - } - }; - if (player.getInventory().getAmount(recipe.getBase()) == 1) { - recipe_.mix(player, event); - } else { - handler.open(); - } - return true; - } - return false; - } - - /** - * Method used to get the allowed nodes for this plugin. - * @return the allowed nodes. - */ - private final static int[] getAllowedNodes() { - List bases = new ArrayList<>(10); - for (Recipe recipe : Recipe.RECIPES) { - for (Item base : recipe.getParts()) { - if (bases.contains(base.getId())) { - continue; - } - bases.add(base.getId()); - } - if (bases.contains(recipe.getBase().getId())) { - continue; - } - bases.add(recipe.getBase().getId()); - } - int[] baseArray = new int[bases.size()]; - for (int i = 0; i < bases.size(); i++) { - baseArray[i] = bases.get(i); - } - return baseArray; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/PieShellPlugin.java b/Server/src/main/content/global/skill/cooking/PieShellPlugin.java deleted file mode 100644 index 4278836e8..000000000 --- a/Server/src/main/content/global/skill/cooking/PieShellPlugin.java +++ /dev/null @@ -1,56 +0,0 @@ -package content.global.skill.cooking; - -import core.game.interaction.NodeUsageEvent; -import core.game.interaction.UseWithHandler; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.plugin.Initializable; -import core.plugin.Plugin; - -/** - * Represents the pie shell making plugin. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class PieShellPlugin extends UseWithHandler { - - /** - * Represents the pie sell item. - */ - private static final Item PIE_SHELL = new Item(2315, 1); - - /** - * Represents the pie dish item. - */ - private static final Item PIE_DISH = new Item(2313, 1); - - /** - * Represents the pastry dough item. - */ - private static final Item PASTRY_DOUGH = new Item(1953, 1); - - /** - * Constructs a new {@code PieMakingPlugin} {@code Object}. - */ - public PieShellPlugin() { - super(1953); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(2313, ITEM_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - if (player.getInventory().remove(PASTRY_DOUGH, PIE_DISH)) { - player.getInventory().add(PIE_SHELL); - player.getPacketDispatch().sendMessage("You put the pastry dough into the pie dish to make a pie shell."); - } - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/SkeweredFoodListener.kt b/Server/src/main/content/global/skill/cooking/SkeweredFoodListener.kt new file mode 100644 index 000000000..8465d2b88 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/SkeweredFoodListener.kt @@ -0,0 +1,38 @@ +package content.global.skill.cooking + +import core.api.* +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.skill.Skills +import org.rs09.consts.Items + +class SkeweredFoodListener : InteractionListener { + val skewerMap = hashMapOf( + Items.RAW_CHOMPY_2876 to Items.SKEWERED_CHOMPY_7230, + Items.RAW_RABBIT_3226 to Items.SKEWERED_RABBIT_7224, + Items.RAW_BIRD_MEAT_9978 to Items.SKEWERED_BIRD_MEAT_9984, + Items.RAW_BEAST_MEAT_9986 to Items.SKEWERED_BEAST_9992 + ) + + override fun defineListeners() { + onUseWith(IntType.ITEM, skewerMap.keys.toIntArray(), Items.IRON_SPIT_7225) { player, used, with -> + val level = when (used.id) { + Items.RAW_BIRD_MEAT_9978 -> 11 + Items.RAW_RABBIT_3226 -> 16 + Items.RAW_BEAST_MEAT_9986 -> 21 + Items.RAW_CHOMPY_2876 -> 30 + else -> 0 + } + + if (getDynLevel(player, Skills.COOKING) < level) { + sendMessage(player, "You need a Cooking level of at least $level in order to do this.") + return@onUseWith true + } + if (removeItem(player, used.id) && removeItem(player, with.id)) { + skewerMap[used.id]?.let { addItem(player, it) } + return@onUseWith true + } + return@onUseWith false + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/SkeweredFoodPlugin.java b/Server/src/main/content/global/skill/cooking/SkeweredFoodPlugin.java deleted file mode 100644 index 8f02bfcb9..000000000 --- a/Server/src/main/content/global/skill/cooking/SkeweredFoodPlugin.java +++ /dev/null @@ -1,115 +0,0 @@ -package content.global.skill.cooking; - -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.item.Item; -import core.plugin.Initializable; -import core.plugin.Plugin; -import org.rs09.consts.Items; - -/** - * Represents the plugin used to make skwered items. - * @author 'Vexia - * @date 22/12/2013 - */ -@Initializable -public class SkeweredFoodPlugin extends UseWithHandler { - - /** - * Represents the level required. - */ - private final int LEVEL = 20; - - /** - * Constructs a new {@code SkeweredFoodPlugin} {@code Object}. - */ - public SkeweredFoodPlugin() { - super(7225); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - for (SkeweredSet set : SkeweredSet.values()) { - addHandler(set.getRaw().getId(), ITEM_TYPE, this); - } - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - if (player.getSkills().getLevel(Skills.FIREMAKING) < LEVEL) { - player.getPacketDispatch().sendMessage("You meed a Firemaking level of at least " + LEVEL + " in order to do this."); - return true; - } - final SkeweredSet set = SkeweredSet.forItem(event.getBaseItem().getId() == 7225 ? event.getUsedItem() : event.getBaseItem()); - if (player.getInventory().remove(event.getBaseItem()) && player.getInventory().remove(event.getUsedItem())) { - player.getInventory().add(set.getProduct()); - } - return true; - } - - /** - * Represents a set of skwered items. - * @author 'Vexia - * @date 22/12/2013 - */ - public enum SkeweredSet { - CHOMPY(new Item(Items.RAW_CHOMPY_2876), new Item(Items.SKEWERED_CHOMPY_7230)), - RABBIT(new Item(Items.RAW_RABBIT_3226), new Item(Items.SKEWERED_RABBIT_7224)), - BIRD(new Item(Items.RAW_BIRD_MEAT_9978), new Item(Items.SKEWERED_BIRD_MEAT_9984)), - BEAST(new Item(Items.RAW_BEAST_MEAT_9986), new Item(Items.SKEWERED_BEAST_9992)); - - /** - * Represents the raw item. - */ - private final Item raw; - - /** - * Represents the product item. - */ - private final Item product; - - /** - * Constructs a new {@code SkeweredFoodPlugin} {@code Object}. - * @param raw the raw item. - * @param product the product. - */ - private SkeweredSet(Item raw, Item product) { - this.raw = raw; - this.product = product; - } - - /** - * Gets the raw. - * @return The raw. - */ - public Item getRaw() { - return raw; - } - - /** - * Gets the product. - * @return The product. - */ - public Item getProduct() { - return product; - } - - /** - * Gets the skwered set. - * @param item the item. - * @return the set. - */ - public static SkeweredSet forItem(final Item item) { - for (SkeweredSet set : values()) { - if (set.getRaw().getId() == item.getId()) { - return set; - } - } - return null; - } - } -} diff --git a/Server/src/main/content/global/skill/cooking/WatermelonSliceListener.kt b/Server/src/main/content/global/skill/cooking/WatermelonSliceListener.kt new file mode 100644 index 000000000..12f1ee22d --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/WatermelonSliceListener.kt @@ -0,0 +1,20 @@ +package content.global.skill.cooking + +import core.api.* +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class WatermelonSliceListener : InteractionListener { + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.WATERMELON_5982, Items.KNIFE_946) { player, used, _ -> + if(removeItem(player, used.asItem())) { + addItemOrDrop(player, Items.WATERMELON_SLICE_5984, 3) + sendMessage(player, "You slice the watermelon into three slices.") + return@onUseWith true + } + return@onUseWith false + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/WatermelonSlicePlugin.java b/Server/src/main/content/global/skill/cooking/WatermelonSlicePlugin.java deleted file mode 100644 index d8273968f..000000000 --- a/Server/src/main/content/global/skill/cooking/WatermelonSlicePlugin.java +++ /dev/null @@ -1,59 +0,0 @@ -package content.global.skill.cooking; - -import core.game.interaction.NodeUsageEvent; -import core.game.interaction.UseWithHandler; -import core.game.node.item.GroundItemManager; -import core.game.node.item.Item; -import core.plugin.Initializable; -import core.plugin.Plugin; - -/** - * Represents the plugin used to slice a watermelon. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class WatermelonSlicePlugin extends UseWithHandler { - - /** - * Represents the knife item. - */ - private static final Item KNIFE = new Item(946); - - /** - * Represents the watermelon item. - */ - private static final Item WATERMELON = new Item(5982); - - /** - * Represents the watermelon slice item. - */ - private static final Item WATERMELON_SLICE = new Item(5984); - - /** - * Constructs a new {@code WatermelonSlicePlugin.java} {@code Object}. - */ - public WatermelonSlicePlugin() { - super(KNIFE.getId()); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(5982, ITEM_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - if (event.getPlayer().getInventory().remove(WATERMELON)) { - for (int i = 0; i < 3; i++) { - if (!event.getPlayer().getInventory().add(WATERMELON_SLICE)) { - GroundItemManager.create(WATERMELON_SLICE, event.getPlayer()); - } - } - event.getPlayer().getPacketDispatch().sendMessage("You slice the watermelon into three slices."); - } - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/WineFermentListener.kt b/Server/src/main/content/global/skill/cooking/WineFermentListener.kt new file mode 100644 index 000000000..1c4c67b9d --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/WineFermentListener.kt @@ -0,0 +1,30 @@ +package content.global.skill.cooking + +import content.global.skill.cooking.fermenting.WineFermentingPulse +import core.api.addItem +import core.api.getDynLevel +import core.api.removeItem +import core.api.sendMessage +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.skill.Skills +import core.game.world.GameWorld.Pulser +import org.rs09.consts.Items + +class WineFermentListener : InteractionListener { + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.GRAPES_1987, Items.JUG_OF_WATER_1937) { player, used, with -> + if (getDynLevel(player, Skills.COOKING) < 35) { + sendMessage(player, "You need a cooking level of 35 to do this.") + return@onUseWith true + } + if (removeItem(player, used.id) && removeItem(player, with.id)) { + addItem(player, Items.UNFERMENTED_WINE_1995) + Pulser.submit(WineFermentingPulse(1, player)) + return@onUseWith true + } + return@onUseWith false + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/WineFermentPlugin.java b/Server/src/main/content/global/skill/cooking/WineFermentPlugin.java deleted file mode 100644 index b2e96678d..000000000 --- a/Server/src/main/content/global/skill/cooking/WineFermentPlugin.java +++ /dev/null @@ -1,63 +0,0 @@ -package content.global.skill.cooking; - -import core.plugin.Initializable; -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.fermenting.WineFermentingPulse; -import core.game.interaction.NodeUsageEvent; -import core.game.interaction.UseWithHandler; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.game.world.GameWorld; -import core.plugin.Plugin; - -/** - * Represents the plugin used to ferment wine. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class WineFermentPlugin extends UseWithHandler { - - /** - * Represents the grapes item. - */ - private static final Item GRAPES = new Item(1987, 1); - - /** - * Represents the jug of water item. - */ - private static final Item JUG_OF_WATER = new Item(1937, 1); - - /** - * Represents the unfermented wine item. - */ - private static final Item UNFERMENTED_WINE = new Item(1995, 1); - - /** - * Constructs a new {@code WineFermentPlugin} {@code Object}. - */ - public WineFermentPlugin() { - super(1937); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(1987, ITEM_TYPE, this); - return this; - } - - @Override - public boolean handle(NodeUsageEvent event) { - final Player player = event.getPlayer(); - if (player.getSkills().getLevel(Skills.COOKING) < 35) { - player.getPacketDispatch().sendMessage("You need a cooking level of 35 to do this."); - return true; - } - if (player.getInventory().remove(GRAPES, JUG_OF_WATER)) { - player.getInventory().add(UNFERMENTED_WINE); - GameWorld.getPulser().submit(new WineFermentingPulse(1, player)); - } - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/ChocolateCakeListener.kt b/Server/src/main/content/global/skill/cooking/recipe/ChocolateCakeListener.kt new file mode 100644 index 000000000..0661c9417 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/ChocolateCakeListener.kt @@ -0,0 +1,31 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class ChocolateCakeListener : InteractionListener { + + val chocolate = intArrayOf(Items.CHOCOLATE_BAR_1973, Items.CHOCOLATE_DUST_1975) + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.CAKE_1891, *chocolate) { player, used, with -> + val product = Items.CHOCOLATE_CAKE_1897 + val level = 50 + val experience = 30.0 + val message = "" + val failMessage = "You need a Cooking level of $level in order to do that." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/CurryListener.kt b/Server/src/main/content/global/skill/cooking/recipe/CurryListener.kt new file mode 100644 index 000000000..b6be43bb4 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/CurryListener.kt @@ -0,0 +1,37 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.item.Item +import org.rs09.consts.Items + +class CurryListener : InteractionListener { + + val added = intArrayOf(Items.CURRY_LEAF_5970, Items.SPICE_2007) + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.UNCOOKED_STEW_2001, *added) { player, used, with -> + val product = Items.UNCOOKED_CURRY_2009 + val amountAdded = when (with.id) { + Items.CURRY_LEAF_5970 -> 3 + Items.SPICE_2007 -> 1 + else -> 0 + } + val level = 60 + val experience = 0.0 + val message = "You mix the spice with the stew." + val failMessage = "You need a Cooking level of at least $level in order to do this." + + return@onUseWith standardMix( + player, + used.asItem(), + Item(with.id, amountAdded), + product, + level, + experience, + message, + failMessage + ) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/MixHandler.kt b/Server/src/main/content/global/skill/cooking/recipe/MixHandler.kt new file mode 100644 index 000000000..aa3b8bc59 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/MixHandler.kt @@ -0,0 +1,72 @@ +package content.global.skill.cooking.recipe + +import core.api.* +import core.game.dialogue.SkillDialogueHandler +import core.game.node.entity.player.Player +import core.game.node.entity.skill.Skills +import core.game.node.item.Item +import kotlin.math.min + +fun standardMix(player: Player, used: Item, with: Item, product: Int, level: Int, experience: Double, message: String, failMessage: String): Boolean { + // Avoids sending dialogue if not enough ingredients to create (relevant only for curry leaves) + if (amountInInventory(player, used.id) < used.amount || amountInInventory(player, with.id) < with.amount) { + // Not sure about the authentic message + sendMessage(player, "You don't have enough ingredients to make that.") + return true + } + + // Avoids sending dialogue if only one can be created + if (amountInInventory(player, used.id) == used.amount || amountInInventory(player, with.id) == with.amount) { + if (getDynLevel(player, Skills.COOKING) < level) { + sendDialogue(player, failMessage) + return true + } + + if (removeItem(player, used) && removeItem(player, with)) { + sendMessage(player, message) + rewardXP(player, Skills.COOKING, experience) + addItem(player, product) + containerIngredient(player, used.id) + containerIngredient(player, with.id) + } + return true + } + + mixHandler( + player, + used, + with, + product, + level, + experience, + message, + failMessage + ).open() + return true +} + +private fun mixHandler(player: Player, used: Item, with: Item, product: Int, level: Int, experience: Double, message: String, failMessage: String): SkillDialogueHandler { + val handler: SkillDialogueHandler = + object : SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, product.asItem()) { + override fun create(amount: Int, index: Int) { + if (!playerMeetsInitialRequirements()) return + MixScript(player, used, with, product, amount, level, experience, message, failMessage).invoke() + } + + private fun playerMeetsInitialRequirements(): Boolean { + if (getDynLevel(player, Skills.COOKING) < level) { + sendDialogue(player, failMessage) + return false + } + return true + } + + override fun getAll(index: Int): Int { + return min( + amountInInventory(player, used.id)/used.amount, + amountInInventory(player, with.id)/with.amount + ) + } + } + return handler +} diff --git a/Server/src/main/content/global/skill/cooking/recipe/MixScript.kt b/Server/src/main/content/global/skill/cooking/recipe/MixScript.kt new file mode 100644 index 000000000..245c078af --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/MixScript.kt @@ -0,0 +1,57 @@ +package content.global.skill.cooking.recipe + +import core.api.* +import core.game.node.entity.player.Player +import core.game.node.entity.skill.Skills +import core.game.node.item.Item +import org.rs09.consts.Items + +class MixScript( + private val player: Player, + private val used: Item, + private val with: Item, + private val product: Int, + private val sets: Int, + private val level: Int, + private val experience: Double, + private val message: String, + private val failMessage: String +) { + + private val delay = 2 + + fun invoke() { + queueScript(player, delay) { stage -> Int + if (getDynLevel(player, Skills.COOKING) < level) { + sendDialogue(player, failMessage) + return@queueScript stopExecuting(player) + } + + if (inInventory(player, used.id, used.amount) && inInventory(player, with.id, with.amount)) { + if(removeItem(player, used) && removeItem(player, with)) { + sendMessage(player, message) + rewardXP(player, Skills.COOKING, experience) + addItem(player, product) + containerIngredient(player, used.id) + containerIngredient(player, with.id) + } + } else { + return@queueScript stopExecuting(player) + } + + if (stage >= sets - 1) { + return@queueScript stopExecuting(player) + } + + return@queueScript delayScript(player, delay) + } + } +} + +fun containerIngredient(player: Player, ingredient: Int): Boolean{ + return when (ingredient) { + Items.BUCKET_OF_WATER_1929, Items.COMPOST_6032 -> addItem(player, Items.BUCKET_1925) + Items.FRIED_MUSHROOMS_7082 -> addItem(player, Items.BOWL_1923) + else -> false + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/OomlieWrap.java b/Server/src/main/content/global/skill/cooking/recipe/OomlieWrap.java deleted file mode 100644 index d5e8ee5f7..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/OomlieWrap.java +++ /dev/null @@ -1,57 +0,0 @@ -package content.global.skill.cooking.recipe; - -import org.rs09.consts.Items; -import core.game.node.entity.skill.Skills; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * @author afaroutdude - */ -public class OomlieWrap extends Recipe { - - private static final Item OOMLIE_WRAP = new Item(Items.WRAPPED_OOMLIE_2341); - private static final Item RAW_OOMLIE = new Item(Items.RAW_OOMLIE_2337); - private static final Item PALM_LEAF = new Item(Items.PALM_LEAF_2339); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 50) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of 50 in order to do that."); - return; - } - super.mix(player, event); - } - - @Override - public Item getBase() { - return RAW_OOMLIE; - } - - @Override - public Item getProduct() { - return OOMLIE_WRAP; - } - - @Override - public Item[] getIngredients() { - return new Item[] { PALM_LEAF }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You wrap the raw oomlie in the palm leaf."; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/OomlieWrapListener.kt b/Server/src/main/content/global/skill/cooking/recipe/OomlieWrapListener.kt new file mode 100644 index 000000000..79024be71 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/OomlieWrapListener.kt @@ -0,0 +1,29 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class OomlieWrapListener : InteractionListener { + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.RAW_OOMLIE_2337, Items.PALM_LEAF_2339) { player, used, with -> + val product = Items.WRAPPED_OOMLIE_2341 + val level = 50 + val experience = 0.0 + val message = "You wrap the raw oomlie in the palm leaf." + val failMessage = "You need a Cooking level of at least $level in order to do that." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/PieListener.kt b/Server/src/main/content/global/skill/cooking/recipe/PieListener.kt new file mode 100644 index 000000000..8f6b1a841 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/PieListener.kt @@ -0,0 +1,79 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class PieListener : InteractionListener { + + val base = PieProduct.values().map { it.base }.toIntArray() + val added = PieProduct.values().map { it.added }.toIntArray() + + override fun defineListeners() { + onUseWith(IntType.ITEM, base, *added) { player, used, with -> + val pie = PieProduct.productMap[used.id] ?: return@onUseWith true + + if (pie.added != with.id) { + return@onUseWith false + } + + val product = pie.product + val level = pie.minimumLevel + val experience = 0.0 + val message = "You fill the pie with ${pie.ingredientMessage}." + val failMessage = "You need a Cooking level of ${pie.minimumLevel} to make this." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } + + enum class PieProduct( + val base: Int, + val added: Int, + val product: Int, + val minimumLevel: Int, + val ingredientMessage: String, + ) { + REDBERRY_PIE(Items.REDBERRIES_1951, Items.PIE_SHELL_2315, Items.UNCOOKED_BERRY_PIE_2321, 10, "redberries"), + MEAT_PIE(Items.COOKED_MEAT_2142, Items.PIE_SHELL_2315, Items.UNCOOKED_MEAT_PIE_2319, 20, "meat"), + MUD_PIE_1(Items.COMPOST_6032, Items.PIE_SHELL_2315, Items.PART_MUD_PIE_7164, 29, "compost"), + MUD_PIE_2(Items.PART_MUD_PIE_7164, Items.BUCKET_OF_WATER_1929, Items.PART_MUD_PIE_7166, 29, "water"), + MUD_PIE_3(Items.PART_MUD_PIE_7166, Items.CLAY_434, Items.RAW_MUD_PIE_7168, 29, "clay"), + APPLE_PIE(Items.COOKING_APPLE_1955, Items.PIE_SHELL_2315, Items.UNCOOKED_APPLE_PIE_2317, 30, "cooking apple"), + GARDEN_PIE_1(Items.TOMATO_1982, Items.PIE_SHELL_2315, Items.PART_GARDEN_PIE_7172, 34, "tomato"), + GARDEN_PIE_2(Items.PART_GARDEN_PIE_7172, Items.ONION_1957, Items.PART_GARDEN_PIE_7174, 34, "onion"), + GARDEN_PIE_3(Items.PART_GARDEN_PIE_7174, Items.CABBAGE_1965, Items.RAW_GARDEN_PIE_7176, 34, "cabbage"), + FISH_PIE_1(Items.TROUT_333, Items.PIE_SHELL_2315, Items.PART_FISH_PIE_7182, 47, "trout"), + FISH_PIE_2(Items.PART_FISH_PIE_7182, Items.COD_339, Items.PART_FISH_PIE_7184, 47, "cod"), + FISH_PIE_3(Items.PART_FISH_PIE_7184, Items.POTATO_1942, Items.RAW_FISH_PIE_7186, 47, "potato"), + ADMIRAL_PIE_1(Items.SALMON_329, Items.PIE_SHELL_2315, Items.PART_ADMIRAL_PIE_7192, 70, "salmon"), + ADMIRAL_PIE_2(Items.PART_ADMIRAL_PIE_7192, Items.TUNA_361, Items.PART_ADMIRAL_PIE_7194, 70, "tuna"), + ADMIRAL_PIE_3(Items.PART_ADMIRAL_PIE_7194, Items.POTATO_1942, Items.RAW_ADMIRAL_PIE_7196, 70, "potato"), + WILD_PIE_1(Items.RAW_BEAR_MEAT_2136, Items.PIE_SHELL_2315, Items.PART_WILD_PIE_7202, 85, "raw bear meat"), + WILD_PIE_2(Items.PART_WILD_PIE_7202, Items.RAW_CHOMPY_2876, Items.PART_WILD_PIE_7204, 85, "raw chompy"), + WILD_PIE_3(Items.PART_WILD_PIE_7204, Items.RAW_RABBIT_3226, Items.RAW_WILD_PIE_7206, 85, "raw rabbit"), + SUMMER_PIE_1(Items.STRAWBERRY_5504, Items.PIE_SHELL_2315, Items.PART_SUMMER_PIE_7212, 95, "strawberry"), + SUMMER_PIE_2(Items.PART_SUMMER_PIE_7212, Items.WATERMELON_5982, Items.PART_SUMMER_PIE_7214, 95, "watermelon"), + SUMMER_PIE_3(Items.PART_SUMMER_PIE_7214, Items.COOKING_APPLE_1955, Items.RAW_SUMMER_PIE_7216, 95, "apple"), + ; + + companion object { + val productMap = HashMap() + + init { + for (pie in PieProduct.values()) { + productMap[pie.base] = pie + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/PieShellListener.kt b/Server/src/main/content/global/skill/cooking/recipe/PieShellListener.kt new file mode 100644 index 000000000..b0e075575 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/PieShellListener.kt @@ -0,0 +1,29 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class PieShellListener : InteractionListener { + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.PIE_DISH_2313, Items.PASTRY_DOUGH_1953) { player, used, with -> + val product = Items.PIE_SHELL_2315 + val level = 1 + val experience = 0.0 + val message = "You put the pastry dough into the pie dish to make a pie shell." + val failMessage = "" + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/PizzaListener.kt b/Server/src/main/content/global/skill/cooking/recipe/PizzaListener.kt new file mode 100644 index 000000000..f70c32f35 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/PizzaListener.kt @@ -0,0 +1,66 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class PizzaListener : InteractionListener { + + val base = PizzaProduct.values().map { it.base }.toIntArray() + val added = PizzaProduct.values().map { it.added }.toIntArray() + + override fun defineListeners() { + onUseWith(IntType.ITEM, base, *added) { player, used, with -> + val pizza = PizzaProduct.productMap[used.id] ?: return@onUseWith true + + if (pizza.added != with.id) { + return@onUseWith false + } + + val product = pizza.product + val level = pizza.minimumLevel + val experience = pizza.experience + val message = "You add the ${pizza.message} to the pizza." + val failMessage = "You need a Cooking level of at least ${pizza.minimumLevel} in order to do this." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } + + enum class PizzaProduct( + val base: Int, + val added: Int, + val product: Int, + val minimumLevel: Int, + val experience: Double, + val message: String, + ) { + PIZZA_1(Items.TOMATO_1982, Items.PIZZA_BASE_2283, Items.INCOMPLETE_PIZZA_2285, 35, 0.0,"tomato"), + PIZZA_2(Items.CHEESE_1985, Items.INCOMPLETE_PIZZA_2285, Items.UNCOOKED_PIZZA_2287, 35, 0.0, "cheese"), + MEAT_PIZZA_1(Items.COOKED_MEAT_2142, Items.PLAIN_PIZZA_2289, Items.MEAT_PIZZA_2293, 45, 26.0, "meat"), + MEAT_PIZZA_2(Items.COOKED_CHICKEN_2140, Items.PLAIN_PIZZA_2289, Items.MEAT_PIZZA_2293, 45, 26.0, "cooked chicken"), + ANCHOVY_PIZZA(Items.ANCHOVIES_319, Items.PLAIN_PIZZA_2289, Items.ANCHOVY_PIZZA_2297, 55, 39.0, "anchovies"), + PINEAPPLE_PIZZA_1(Items.PINEAPPLE_CHUNKS_2116, Items.PLAIN_PIZZA_2289, Items.PINEAPPLE_PIZZA_2301, 65, 52.0, "pineapple"), + PINEAPPLE_PIZZA_2(Items.PINEAPPLE_RING_2118, Items.PLAIN_PIZZA_2289, Items.PINEAPPLE_PIZZA_2301, 65, 52.0, "pineapple"), + ; + + companion object { + val productMap = HashMap() + + init { + for (pizza in PizzaProduct.values()) { + productMap[pizza.base] = pizza + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/PotatoListener.kt b/Server/src/main/content/global/skill/cooking/recipe/PotatoListener.kt new file mode 100644 index 000000000..6e2cd5b5c --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/PotatoListener.kt @@ -0,0 +1,77 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class PotatoListener : InteractionListener { + + val added = PotatoProduct.values().map { it.added }.toIntArray() + + override fun defineListeners() { + onUseWith(IntType.ITEM, Items.BAKED_POTATO_6701, Items.PAT_OF_BUTTER_6697) { player, used, with -> + val product = Items.POTATO_WITH_BUTTER_6703 + val level = 39 + val experience = 40.5 + val message = "You add a pat of butter to the potato." + val failMessage = "You need a Cooking level of at least $level in order to do this." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + + onUseWith(IntType.ITEM, added, Items.POTATO_WITH_BUTTER_6703) { player, used, with -> + val topping = PotatoProduct.productMap[used.id] ?: return@onUseWith true + + val product = topping.product + val level = topping.minimumLevel + val experience = topping.experience + val message = "" + val failMessage = "You need a Cooking level of at least $level in order to do this." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } + + enum class PotatoProduct( + val added: Int, + val product: Int, + val minimumLevel: Int, + val experience: Double, + val message: String + ) { + CHEESE_POTATO(Items.CHEESE_1985, Items.POTATO_WITH_CHEESE_6705, 47, 10.0, ""), + CHILLI_POTATO(Items.CHILLI_CON_CARNE_7062, Items.CHILLI_POTATO_7054, 41, 15.0, ""), + EGG_POTATO(Items.EGG_AND_TOMATO_7064, Items.EGG_POTATO_7056, 51, 50.0, ""), + TUNA_POTATO(Items.TUNA_AND_CORN_7068, Items.TUNA_POTATO_7060, 68, 10.0, ""), + MUSHROOM_POTATO(Items.MUSHROOM_AND_ONION_7066, Items.MUSHROOM_POTATO_7058, 64, 55.0, ""), + ; + + companion object { + val productMap = HashMap() + + init { + for (topping in PotatoProduct.values()) { + productMap[topping.added] = topping + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/Recipe.java b/Server/src/main/content/global/skill/cooking/recipe/Recipe.java deleted file mode 100644 index 3e2eff513..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/Recipe.java +++ /dev/null @@ -1,134 +0,0 @@ -package content.global.skill.cooking.recipe; - -import content.global.skill.cooking.recipe.pie.impl.*; -import content.global.skill.cooking.recipe.pizza.impl.AnchovyPizza; -import content.global.skill.cooking.recipe.pizza.impl.MeatPizza; -import content.global.skill.cooking.recipe.pizza.impl.PineapplePizza; -import content.global.skill.cooking.recipe.pizza.impl.PlainPizza; -import content.global.skill.cooking.recipe.potato.impl.*; -import content.global.skill.cooking.recipe.stew.CurryRecipe; -import content.global.skill.cooking.recipe.stew.StewRecipe; -import content.global.skill.cooking.recipe.topping.impl.*; -import content.global.skill.cooking.recipe.cake.ChocolateCake; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents a cooking recipe, this is dynamic that can range from a pie to a - * pizza. - * @author 'Vexia - * @date 21/12/2013 - */ -public abstract class Recipe { - - /** - * Represents the array of active recipes in 2009Scape. - */ - // TODO: - // - Making this an enum would drastically save on file/line count, since the recipes seem to mostly be plain-old-data classes - // - Making pie shells a recipe would make make-x for them just work - // - Making pineapple cutting a recipe would probably fix their make-x making all with any option - public static final Recipe[] RECIPES = new Recipe[] { - new RedberryPie(), new MeatPie(), new ApplePie(), new MudPie(), new GardenPie(), new FishPie(), new AdmiralPie(), new WildPie(), new SummerPie(), - new StewRecipe(), new CurryRecipe(), - new PlainPizza(), new MeatPizza(), new AnchovyPizza(), new PineapplePizza(), - new ChocolateCake(), - new ButterPotato(), new ChilliPotato(), new CheesePotato(), new EggPotato(), new MushroomPotato(), new TunaPotato(), - new SpicySauce(), new ChilliConCarne(), new UncookedEgg(), new EggAndTomato(), new MushroomAndOnion(), new ChoppedOnion(), new SlicedMushroom(), new ChoppedTuna(), new TunaAndCorn(), new OomlieWrap() - }; - - /** - * Method used to get the base item. - * @return the item. - */ - public abstract Item getBase(); - - /** - * Method used to get the product item. - * @return the product item. - */ - public abstract Item getProduct(); - - /** - * Method used to get the ingredients in this recipe. - * @return the ingredients. - */ - public abstract Item[] getIngredients(); - - /** - * Method used to get the part items made from ingredients. - * @return the part items. - */ - public abstract Item[] getParts(); - - /** - * Method used to get the mixing message. - * @param event the node usage event. - * @return the message used to mix. - */ - public abstract String getMixMessage(final NodeUsageEvent event); - - /** - * Method used to check if this is a singular one step recipe. - * @return True if so. - */ - public abstract boolean isSingular(); - - /** - * Method used to mix this recipes ingredients. - * @param player the player. - * @param event the event. - */ - public void mix(final Player player, final NodeUsageEvent event) { - if (getIngredients().length == 1) { - singleMix(player, event); - } else { - multipleMix(player, event); - } - } - - /** - * Method used to handle a single mixing. - * @param player the player. - * @param event the event. - */ - public void singleMix(final Player player, final NodeUsageEvent event) { - if (player.getInventory().remove(event.getBaseItem()) && player.getInventory().remove(event.getUsedItem())) { - player.getInventory().add(getProduct()); - String message = getMixMessage(event); - if (message != null) { - player.getPacketDispatch().sendMessage(message); - } - } - } - - /** - * Method used to handle mixing multiple item recipes. - * @param player the player. - * @param event the event. - */ - public void multipleMix(final Player player, final NodeUsageEvent event) { - Item item = null; - int index = -1; - for (int counter = 0; counter < getIngredients().length; counter++) { - item = getIngredients()[counter]; - if (item.getId() == event.getUsedItem().getId() || item.getId() == event.getBaseItem().getId()) { - index = counter; - break; - } - } - if (index != -1) { - if (!player.getInventory().containItems(event.getBaseItem().getId(), event.getUsedItem().getId())) { - return; - } - if (player.getInventory().remove(event.getBaseItem()) && player.getInventory().remove(event.getUsedItem())) { - player.getInventory().add(getParts()[index + 1]); - String message = getMixMessage(event); - if (message != null) { - player.getPacketDispatch().sendMessage(message); - } - } - } - } -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/StewListener.kt b/Server/src/main/content/global/skill/cooking/recipe/StewListener.kt new file mode 100644 index 000000000..312aedcf0 --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/StewListener.kt @@ -0,0 +1,62 @@ +package content.global.skill.cooking.recipe + +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class StewListener : InteractionListener { + + val base = StewProduct.values().map { it.base }.toIntArray() + val added = StewProduct.values().map { it.added }.toIntArray() + + override fun defineListeners() { + onUseWith(IntType.ITEM, base, *added) { player, used, with -> + val stew = StewProduct.productMap[used.id] ?: return@onUseWith true + + if (stew.added != with.id) { + return@onUseWith false + } + + val product = stew.product + val level = stew.minimumLevel + val experience = 0.0 + val message = "You cut up the ${stew.message} and put it into the stew." + val failMessage = "You need a Cooking level of at least ${stew.minimumLevel} in order to do this." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } + + enum class StewProduct( + val base: Int, + val added: Int, + val product: Int, + val minimumLevel: Int, + val message: String, + ) { + STEW_1(Items.POTATO_1942, Items.BOWL_OF_WATER_1921, Items.INCOMPLETE_STEW_1997, 25, "potato"), + STEW_2(Items.INCOMPLETE_STEW_1997, Items.COOKED_MEAT_2142, Items.UNCOOKED_STEW_2001, 25, "meat"), + STEW_3(Items.COOKED_MEAT_2142, Items.BOWL_OF_WATER_1921, Items.INCOMPLETE_STEW_1999, 25, "meat"), + STEW_4(Items.INCOMPLETE_STEW_1999, Items.POTATO_1942, Items.UNCOOKED_STEW_2001, 25, "potato"), + ; + + companion object { + val productMap = HashMap() + + init { + for (stew in StewProduct.values()) { + productMap[stew.base] = stew + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/ToppingListener.kt b/Server/src/main/content/global/skill/cooking/recipe/ToppingListener.kt new file mode 100644 index 000000000..68e5c55bb --- /dev/null +++ b/Server/src/main/content/global/skill/cooking/recipe/ToppingListener.kt @@ -0,0 +1,84 @@ +package content.global.skill.cooking.recipe + +import core.api.inInventory +import core.api.sendDialogue +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import org.rs09.consts.Items + +class ToppingListener : InteractionListener { + + val base = ToppingProduct.values().map { it.base }.toIntArray() + val added = ToppingProduct.values().map { it.added }.toIntArray() + + override fun defineListeners() { + onUseWith(IntType.ITEM, base, *added) { player, used, with -> + val topping = ToppingProduct.productMap[used.id] ?: return@onUseWith true + val verb = if (with.id == Items.COOKED_MEAT_2142) "cut" else "slice" + + if (topping.added != with.id) { + return@onUseWith false + } + + if (topping.cut_name != "" && !inInventory(player, Items.KNIFE_946)) { + sendDialogue(player, "You need a knife in order to $verb up the ${topping.cut_name}.") + return@onUseWith true + } + + val product = topping.product + val level = topping.minimumLevel + val experience = topping.experience + val message = topping.message + val failMessage = "You need a Cooking level of at least ${topping.minimumLevel} in order to do this." + + return@onUseWith standardMix( + player, + used.asItem(), + with.asItem(), + product, + level, + experience, + message, + failMessage + ) + } + } + + enum class ToppingProduct( + val base: Int, + val added: Int, + val product: Int, + val minimumLevel: Int, + val experience: Double, + val message: String, + val cut_name: String + ) { + //Tuna and Corn: https://www.youtube.com/watch?v=wAavERc9p2c + //Uncooked Egg: https://www.youtube.com/watch?v=LiLq6PhCc2M + //Bowl of sweetcorn (OSRS source is only I could find) https://www.youtube.com/watch?v=pz8epXjkKYE + + UNCOOKED_EGG(Items.EGG_1944, Items.BOWL_1923, Items.UNCOOKED_EGG_7076, 1, 0.0, "You carefully break the egg into the bowl.", ""), + BOWL_OF_SWEETCORN(Items.COOKED_SWEETCORN_5988, Items.BOWL_1923, Items.SWEETCORN_7088, 1, 0.0, "You put the cooked sweetcorn into the bowl.", ""), + SLICED_MUSHROOM(Items.MUSHROOM_6004, Items.BOWL_1923, Items.SLICED_MUSHROOMS_7080, 1, 0.0, "You chop the mushrooms into the bowl.", "mushrooms"), + CHOPPED_TUNA(Items.TUNA_361, Items.BOWL_1923, Items.CHOPPED_TUNA_7086, 1, 0.0, "You chop the tuna into the bowl.", "tuna"), + CHOPPED_ONION(Items.ONION_1957, Items.BOWL_1923, Items.CHOPPED_ONION_1871, 1, 0.0, "You chop the onion into the bowl.", "onion"), + CHOPPED_GARLIC(Items.GARLIC_1550, Items.BOWL_1923, Items.CHOPPED_GARLIC_7074, 1, 0.0, "You chop the garlic into the bowl.", "garlic"), + SPICY_SAUCE(Items.CHOPPED_GARLIC_7074, Items.GNOME_SPICE_2169, Items.SPICY_SAUCE_7072, 9, 25.0, "You mix the ingredients to make the topping.", ""), //inauthentic, used generic mixing message + CHILLI_CON_CARNE(Items.SPICY_SAUCE_7072, Items.COOKED_MEAT_2142, Items.CHILLI_CON_CARNE_7062, 9, 0.0, "You mix the ingredients to make the topping.", "meat"), //inauthentic, used generic mixing message + EGG_AND_TOMATO(Items.TOMATO_1982, Items.SCRAMBLED_EGG_7078, Items.EGG_AND_TOMATO_7064, 23, 50.0, "You mix the ingredients to make the topping.", ""), + MUSHROOM_AND_ONION(Items.FRIED_MUSHROOMS_7082, Items.FRIED_ONIONS_7084, Items.MUSHROOM_AND_ONION_7066, 57, 120.0, "You mix the ingredients to make the topping.", ""), + TUNA_AND_CORN_1(Items.CHOPPED_TUNA_7086, Items.COOKED_SWEETCORN_5988, Items.TUNA_AND_CORN_7068, 67, 204.0, "You mix the ingredients to make the topping.", ""), + TUNA_AND_CORN_2(Items.SWEETCORN_7088, Items.TUNA_361, Items.TUNA_AND_CORN_7068, 67, 204.0, "You mix the ingredients to make the topping.", "tuna"), + ; + + companion object { + val productMap = HashMap() + + init { + for (topping in ToppingProduct.values()) { + productMap[topping.base] = topping + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/cooking/recipe/cake/ChocolateCake.java b/Server/src/main/content/global/skill/cooking/recipe/cake/ChocolateCake.java deleted file mode 100644 index 97ef11d88..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/cake/ChocolateCake.java +++ /dev/null @@ -1,72 +0,0 @@ -package content.global.skill.cooking.recipe.cake; - -import content.global.skill.cooking.recipe.Recipe; -import core.game.node.entity.skill.Skills; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the chocolate cake recipe. This recipe consists of adding a - * chocolate bar to a cake. - * @author 'Vexia - * @date 22/12/2013 - */ -public class ChocolateCake extends Recipe { - - /** - * Represents the cake item. - */ - private static final Item CAKE = new Item(1891); - - /** - * Represents the chocolate cake item. - */ - private static final Item CHOCOLATE_CAKE = new Item(1897); - - /** - * Represents the chocolate bar item. - */ - private static final Item CHOCOLATE_BAR = new Item(1973); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 50) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of 50 in order to do that."); - return; - } - super.mix(player, event); - player.getSkills().addExperience(Skills.COOKING, 30, true); - } - - @Override - public Item getBase() { - return CAKE; - } - - @Override - public Item getProduct() { - return CHOCOLATE_CAKE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { CHOCOLATE_BAR }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You add chocolate to the cake."; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/PieRecipe.java b/Server/src/main/content/global/skill/cooking/recipe/pie/PieRecipe.java deleted file mode 100644 index 878a3333f..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/PieRecipe.java +++ /dev/null @@ -1,38 +0,0 @@ -package content.global.skill.cooking.recipe.pie; - -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.item.Item; - -/** - * Represents the generic recipe for a pie. - * @author 'Vexia - * @date 21/12/2013 - */ -public abstract class PieRecipe extends Recipe { - - /** - * Represents the pie shell item. - */ - protected static final Item PIE_SHELL = new Item(2315); - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public Item getBase() { - return PIE_SHELL; - } - - @Override - public String getMixMessage(final NodeUsageEvent event) { - return "You fill the pie with " + (event.getBaseItem().getId() == 2315 ? event.getUsedItem().getName().toLowerCase() : event.getBaseItem().getName().toLowerCase()) + "."; - } - - @Override - public boolean isSingular() { - return true; - } -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/AdmiralPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/AdmiralPie.java deleted file mode 100644 index 9cc6a98eb..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/AdmiralPie.java +++ /dev/null @@ -1,64 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents the admiral pie recipe. This recipe conists of pixing a salmon, - * tuna and potato together. - * @author 'Vexia - * @date 21/12/2013 - */ -public class AdmiralPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(7196); - - /** - * Represents the salmon ingredient item. - */ - private static final Item SALMON = new Item(329); - - /** - * Represents the tuna ingredient item. - */ - private static final Item TUNA = new Item(361); - - /** - * Represents the potato item. - */ - private static final Item POTATO = new Item(1942); - - /** - * Represents the part one pie item. - */ - private static final Item PART_ONE = new Item(7192); - - /** - * Represents the part two pie item. - */ - private static final Item PART_TWO = new Item(7194); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { SALMON, TUNA, POTATO }; - } - - @Override - public Item[] getParts() { - return new Item[] { PIE_SHELL, PART_ONE, PART_TWO, UNCOOKED_PIE }; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/ApplePie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/ApplePie.java deleted file mode 100644 index e44917445..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/ApplePie.java +++ /dev/null @@ -1,34 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents the apple pie recipe. This recipe consists of cooking apples and a - * pie shell. - * @author 'Vexia - * @date 21/12/2013 - */ -public class ApplePie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(2317); - - /** - * Represents the cooking apple item. - */ - private static final Item COOKING_APPLE = new Item(1955); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { COOKING_APPLE }; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/FishPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/FishPie.java deleted file mode 100644 index 7a1dad02f..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/FishPie.java +++ /dev/null @@ -1,64 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents the garden pie recipe. This pie consists of mixing, tomato, onion, - * and cabbage together. - * @author 'Vexia - * @date 21/12/2013 - */ -public class FishPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(7186); - - /** - * Represents the trout item ingredient. - */ - private static final Item TROUT = new Item(333); - - /** - * Represents the cod item ingredient. - */ - private static final Item COD = new Item(339); - - /** - * Represents the potato item. - */ - private static final Item POTATO = new Item(1942); - - /** - * Represents the part one pie item. - */ - private static final Item PART_ONE = new Item(7182); - - /** - * Represents the part two pie item. - */ - private static final Item PART_TWO = new Item(7184); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TROUT, COD, POTATO }; - } - - @Override - public Item[] getParts() { - return new Item[] { PIE_SHELL, PART_ONE, PART_TWO, UNCOOKED_PIE }; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/GardenPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/GardenPie.java deleted file mode 100644 index 90fbe7e23..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/GardenPie.java +++ /dev/null @@ -1,64 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents the garden pie recipe. This pie consists of mixing, tomato, onion, - * and cabbage together. - * @author 'Vexia - * @date 21/12/2013 - */ -public class GardenPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(7176); - - /** - * Represents the tomato ingredient item. - */ - private static final Item TOMATO = new Item(1982); - - /** - * Represents the onion ingredient item. - */ - private static final Item ONION = new Item(1957); - - /** - * Represents the cabbage ingredient item. - */ - private static final Item CABBAGE = new Item(1965); - - /** - * Represents the part one pie item. - */ - private static final Item PART_ONE = new Item(7172); - - /** - * Represents the part two pie item. - */ - private static final Item PART_TWO = new Item(7174); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TOMATO, ONION, CABBAGE }; - } - - @Override - public Item[] getParts() { - return new Item[] { PIE_SHELL, PART_ONE, PART_TWO, UNCOOKED_PIE }; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/MeatPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/MeatPie.java deleted file mode 100644 index 1edb223fd..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/MeatPie.java +++ /dev/null @@ -1,58 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the meat pie recipe. - * @author 'Vexia - * @date 21/12/2013 - */ -public class MeatPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(2319); - - /** - * Represents the cooked meat item. - */ - private static final Item COOKED_MEAT = new Item(2142); - - /** - * Represents the cooked chicken item. - */ - private static final Item COOKED_CHICKEN = new Item(2140); - - /** - * Represents the cooked rabbit. - */ - private static final Item COOKED_RABBIT = new Item(3228); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getInventory().remove(event.getUsedItem()) && player.getInventory().remove(event.getBaseItem())) { - player.getInventory().add(getProduct()); - player.getPacketDispatch().sendMessage(getMixMessage(event)); - return; - } - } - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { COOKED_MEAT, COOKED_CHICKEN, COOKED_RABBIT }; - } - - @Override - public String getMixMessage(final NodeUsageEvent event) { - return "You fill the pie with meat."; - } -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/MudPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/MudPie.java deleted file mode 100644 index 64a542f46..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/MudPie.java +++ /dev/null @@ -1,64 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents the mud pie recipe. A mud pie consists of mixing compost, water - * and clay together. - * @author 'Vexia - * @date 21/12/2013 - */ -public class MudPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(7168); - - /** - * Represents the compost item. - */ - private static final Item COMPOST = new Item(6032); - - /** - * Represents the bucket of water item. - */ - private static final Item BUCKET_OF_WATER = new Item(1929); - - /** - * Represents the clay item. - */ - private static final Item CLAY = new Item(434); - - /** - * Represents the part one pie item. - */ - private static final Item PART_ONE = new Item(7164); - - /** - * Represents the part two pie item. - */ - private static final Item PART_TWO = new Item(7166); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { COMPOST, BUCKET_OF_WATER, CLAY }; - } - - @Override - public Item[] getParts() { - return new Item[] { PIE_SHELL, PART_ONE, PART_TWO, UNCOOKED_PIE }; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/RedberryPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/RedberryPie.java deleted file mode 100644 index 6ebbd04f6..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/RedberryPie.java +++ /dev/null @@ -1,33 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents a redberry pie recipe. - * @author 'Vexia - * @date 21/12/2013 - */ -public class RedberryPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(2321); - - /** - * Represents the redberries pie. - */ - private static final Item REDBERRIES = new Item(1951); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { REDBERRIES }; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/SummerPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/SummerPie.java deleted file mode 100644 index 14996852a..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/SummerPie.java +++ /dev/null @@ -1,64 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents the summer pie recipe. This recipe consists of mixing stawberry, - * watermelon, and an apple. - * @author 'Vexia - * @date 21/12/2013 - */ -public class SummerPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(7216); - - /** - * Represents the strawberry item. - */ - private static final Item STRAWBERRY = new Item(5504); - - /** - * Represents the watermelon item. - */ - private static final Item WATERMELON = new Item(5982); - - /** - * Represents the cooking apple item. - */ - private static final Item COOKING_APPLE = new Item(1955); - - /** - * Represents the part one pie item. - */ - private static final Item PART_ONE = new Item(7212); - - /** - * Represents the part two pie item. - */ - private static final Item PART_TWO = new Item(7214); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { STRAWBERRY, WATERMELON, COOKING_APPLE }; - } - - @Override - public Item[] getParts() { - return new Item[] { PIE_SHELL, PART_ONE, PART_TWO, UNCOOKED_PIE }; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/WildPie.java b/Server/src/main/content/global/skill/cooking/recipe/pie/impl/WildPie.java deleted file mode 100644 index 3b4decaa2..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pie/impl/WildPie.java +++ /dev/null @@ -1,64 +0,0 @@ -package content.global.skill.cooking.recipe.pie.impl; - -import content.global.skill.cooking.recipe.pie.PieRecipe; -import core.game.node.item.Item; - -/** - * Represents the wild pie recipe. This recipe consists of mixing raw beat meat, - * raw chomp, and raw rabbit into a pie shell. - * @author 'Vexia - * @date 21/12/2013 - */ -public class WildPie extends PieRecipe { - - /** - * Represents the uncooked redberry pie. - */ - private static final Item UNCOOKED_PIE = new Item(7206); - - /** - * Represents the raw bear meat item. - */ - private static final Item BEAR_MEAT = new Item(2136); - - /** - * Represents the raw chompy meat item. - */ - private static final Item CHOMPY_MEAT = new Item(2876); - - /** - * Represents the raw rabbit meat item. - */ - private static final Item RABBIT_MEAT = new Item(3226); - - /** - * Represents the part one pie item. - */ - private static final Item PART_ONE = new Item(7202); - - /** - * Represents the part two pie item. - */ - private static final Item PART_TWO = new Item(7204); - - @Override - public Item getProduct() { - return UNCOOKED_PIE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { BEAR_MEAT, CHOMPY_MEAT, RABBIT_MEAT }; - } - - @Override - public Item[] getParts() { - return new Item[] { PIE_SHELL, PART_ONE, PART_TWO, UNCOOKED_PIE }; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pizza/PizzaRecipe.java b/Server/src/main/content/global/skill/cooking/recipe/pizza/PizzaRecipe.java deleted file mode 100644 index 5a1385a35..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pizza/PizzaRecipe.java +++ /dev/null @@ -1,63 +0,0 @@ -package content.global.skill.cooking.recipe.pizza; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the generic recipe for a pizza. - * @author ceikry - */ -public abstract class PizzaRecipe extends Recipe { - - /** - * Represents the plain pizza. - */ - protected static final Item PLAIN_PIZZA = new Item(2289); - - /** - * Method used to get the experience gained from adding the final - * ingredient. - * @return the experience. - */ - public abstract double getExperience(); - - /** - * Method used to get the level required. - * @return the level required. - */ - public abstract int getLevel(); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < getLevel()) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + getLevel() + " in order to do this."); - return; - } - super.singleMix(player, event); - player.getSkills().addExperience(Skills.COOKING, getExperience(), true); - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public Item getBase() { - return PLAIN_PIZZA; - } - - @Override - public String getMixMessage(final NodeUsageEvent event) { - return "You add " + event.getBaseItem().getName().toLowerCase() + " to the pizza."; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/AnchovyPizza.java b/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/AnchovyPizza.java deleted file mode 100644 index 4a70625ff..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/AnchovyPizza.java +++ /dev/null @@ -1,44 +0,0 @@ -package content.global.skill.cooking.recipe.pizza.impl; - -import content.global.skill.cooking.recipe.pizza.PizzaRecipe; -import core.game.node.item.Item; - -/** - * Represents the anchovy pizza. This recipe consists of adding anchovies to a - * plain pizza. - * @author 'Vexia - * @date 22/12/2013 - */ -public class AnchovyPizza extends PizzaRecipe { - - /** - * Represents the anchovy pizza item. - */ - private static final Item ANCHOVY_PIZZA = new Item(2297); - - /** - * Represents the anchovies item. - */ - private static final Item ANCHOVIES = new Item(319); - - @Override - public double getExperience() { - return 39; - } - - @Override - public Item getProduct() { - return ANCHOVY_PIZZA; - } - - @Override - public Item[] getIngredients() { - return new Item[] { ANCHOVIES }; - } - - @Override - public int getLevel() { - return 55; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/MeatPizza.java b/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/MeatPizza.java deleted file mode 100644 index b79096137..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/MeatPizza.java +++ /dev/null @@ -1,49 +0,0 @@ -package content.global.skill.cooking.recipe.pizza.impl; - -import content.global.skill.cooking.recipe.pizza.PizzaRecipe; -import core.game.node.item.Item; - -/** - * Represents the meat pizza recipe. This recipe consists of adding cooked meat - * to a plain pizza. - * @author 'Vexia - * @date 22/12/2013 - */ -public class MeatPizza extends PizzaRecipe { - - /** - * Represents the meat pizza item. - */ - private static final Item MEAT_PIZZA = new Item(2293); - - /** - * Represents the cooked meat item. - */ - private static final Item COOKED_MEAT = new Item(2142); - - /** - * Represents the cooked chicken item. - */ - private static final Item COOKED_CHICKEN = new Item(2140); - - @Override - public double getExperience() { - return 26; - } - - @Override - public int getLevel() { - return 45; - } - - @Override - public Item getProduct() { - return MEAT_PIZZA; - } - - @Override - public Item[] getIngredients() { - return new Item[] { COOKED_MEAT, COOKED_CHICKEN }; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PineapplePizza.java b/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PineapplePizza.java deleted file mode 100644 index 7e4746e2f..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PineapplePizza.java +++ /dev/null @@ -1,55 +0,0 @@ -package content.global.skill.cooking.recipe.pizza.impl; - -import content.global.skill.cooking.recipe.pizza.PizzaRecipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.item.Item; - -/** - * Represents the pineapple pizza recipe. This recipe consists of mixing either - * pineapple chunks or pineapple rings. - * @author 'Vexia - * @date 22/12/2013 - */ -public class PineapplePizza extends PizzaRecipe { - - /** - * Represents the pineapple pizza item. - */ - private static final Item PINEAPPLE_PIZZA = new Item(2301); - - /** - * Represents the pineapple ring item. - */ - private static final Item PINEAPPLE_RING = new Item(2118); - - /** - * Represents the pineapple chunk item. - */ - private static final Item PINEAPPLE_CHUNKS = new Item(2116); - - @Override - public double getExperience() { - return 52; - } - - @Override - public int getLevel() { - return 65; - } - - @Override - public Item getProduct() { - return PINEAPPLE_PIZZA; - } - - @Override - public Item[] getIngredients() { - return new Item[] { PINEAPPLE_CHUNKS, PINEAPPLE_RING }; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You add the " + event.getBaseItem().getName().toLowerCase() + " to the pizza."; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PlainPizza.java b/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PlainPizza.java deleted file mode 100644 index 8d624dca3..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/pizza/impl/PlainPizza.java +++ /dev/null @@ -1,81 +0,0 @@ -package content.global.skill.cooking.recipe.pizza.impl; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the plain pizza recipe. This recipe consists of mixing tomato, and - * cheese to a pizza base. - * @author 'Vexia - * @date 22/12/2013 - */ -public class PlainPizza extends Recipe { - - /** - * Represents the pizza base. - */ - private static final Item PIZZA_BASE = new Item(2283); - - /** - * Represents the uncooked pizza. - */ - private static final Item UNCOOKED_PIZZA = new Item(2287); - - /** - * Represents the incomplete pizza. - */ - private static final Item INCOMPLETE_PIZZA = new Item(2285); - - /** - * Represents the tomato ingredient item. - */ - private static final Item TOMATO = new Item(1982); - - /** - * Represents the cheese item. - */ - private static final Item CHEESE = new Item(1985); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 35) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + 35 + " in order to do this."); - return; - } - super.mix(player, event); - } - - @Override - public Item getBase() { - return PIZZA_BASE; - } - - @Override - public Item getProduct() { - return UNCOOKED_PIZZA; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TOMATO, CHEESE }; - } - - @Override - public Item[] getParts() { - return new Item[] { PIZZA_BASE, INCOMPLETE_PIZZA, UNCOOKED_PIZZA }; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You add the " + event.getBaseItem().getName().toLowerCase() + " to the pizza."; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/potato/PotatoRecipe.java b/Server/src/main/content/global/skill/cooking/recipe/potato/PotatoRecipe.java deleted file mode 100644 index c2640a8bc..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/potato/PotatoRecipe.java +++ /dev/null @@ -1,76 +0,0 @@ -package content.global.skill.cooking.recipe.potato; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents a generic potato topping recipe. - * @author 'Vexia - * @date 22/12/2013 - */ -public abstract class PotatoRecipe extends Recipe { - - /** - * Represents the potato with butter. - */ - private static final Item POTATO_WITH_BUTTER = new Item(6703); - - /** - * Represents the bowl item. - */ - protected static final Item BOWL = new Item(1923); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < getLevel()) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + getLevel() + " in order to do this."); - return; - } - super.singleMix(player, event); - if (isTopping()) { - player.getInventory().add(BOWL); - } - player.getSkills().addExperience(Skills.COOKING, getExperience(), true); - } - - @Override - public Item getBase() { - return POTATO_WITH_BUTTER; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return null; - } - - @Override - public boolean isSingular() { - return true; - } - - /** - * Method used to check if it is a topping recipe. - * @return True if it is a topping. - */ - public abstract boolean isTopping(); - - /** - * Method used to get the level required. - * @return the level. - */ - public abstract int getLevel(); - - /** - * Method used to get the experience gained. - * @return the experience. - */ - public abstract double getExperience(); -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/ButterPotato.java b/Server/src/main/content/global/skill/cooking/recipe/potato/impl/ButterPotato.java deleted file mode 100644 index b382a5029..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/ButterPotato.java +++ /dev/null @@ -1,72 +0,0 @@ -package content.global.skill.cooking.recipe.potato.impl; - -import content.global.skill.cooking.recipe.Recipe; -import core.game.node.entity.skill.Skills; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the butter potato recipe. This recipe consists of adding a pat of - * butter to a potato. - * @author 'Vexia - * @date 22/12/2013 - */ -public class ButterPotato extends Recipe { - - /** - * Represents the baked potato. - */ - private static final Item BAKED_POTATO = new Item(6701); - - /** - * Represents the potato with butter. - */ - private static final Item POTATO_WITH_BUTTER = new Item(6703); - - /** - * Represents the pat of butter. - */ - private static final Item PAT_OF_BUTTER = new Item(6697); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 39) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + 39 + " in order to do this."); - return; - } - super.singleMix(player, event); - player.getSkills().addExperience(Skills.COOKING, 40.5, true); - } - - @Override - public Item getBase() { - return BAKED_POTATO; - } - - @Override - public Item getProduct() { - return POTATO_WITH_BUTTER; - } - - @Override - public Item[] getIngredients() { - return new Item[] { PAT_OF_BUTTER }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You add a pat of butter to the potato."; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/CheesePotato.java b/Server/src/main/content/global/skill/cooking/recipe/potato/impl/CheesePotato.java deleted file mode 100644 index f111ed950..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/CheesePotato.java +++ /dev/null @@ -1,49 +0,0 @@ -package content.global.skill.cooking.recipe.potato.impl; - -import content.global.skill.cooking.recipe.potato.PotatoRecipe; -import core.game.node.item.Item; - -/** - * Represents the cheese potato. This recipe consists of mixing cheese witha - * baked potato. - * @author 'Vexia - * @date 22/12/2013 - */ -public class CheesePotato extends PotatoRecipe { - - /** - * Represents the cheese potato. - */ - private static final Item CHEESE_POTATO = new Item(6705); - - /** - * Represents the cheese item. - */ - private static final Item CHEESE = new Item(1985); - - @Override - public Item getProduct() { - return CHEESE_POTATO; - } - - @Override - public Item[] getIngredients() { - return new Item[] { CHEESE }; - } - - @Override - public boolean isTopping() { - return false; - } - - @Override - public int getLevel() { - return 47; - } - - @Override - public double getExperience() { - return 10; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/ChilliPotato.java b/Server/src/main/content/global/skill/cooking/recipe/potato/impl/ChilliPotato.java deleted file mode 100644 index 88c5ed146..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/ChilliPotato.java +++ /dev/null @@ -1,49 +0,0 @@ -package content.global.skill.cooking.recipe.potato.impl; - -import content.global.skill.cooking.recipe.potato.PotatoRecipe; -import core.game.node.item.Item; - -/** - * Represents the chilli potato recipe. This recipe consists of adding chilli - * con carne to a baked butter potato. - * @author 'Vexia - * @date 22/12/2013 - */ -public class ChilliPotato extends PotatoRecipe { - - /** - * Represents the chilli potato item. - */ - private static final Item CHILLI_POTATO = new Item(7054); - - /** - * Represents the chilli con carne item/ - */ - private static final Item CHILLI_CON_CARNE = new Item(7062); - - @Override - public Item getProduct() { - return CHILLI_POTATO; - } - - @Override - public Item[] getIngredients() { - return new Item[] { CHILLI_CON_CARNE }; - } - - @Override - public boolean isTopping() { - return true; - } - - @Override - public int getLevel() { - return 41; - } - - @Override - public double getExperience() { - return 10; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/EggPotato.java b/Server/src/main/content/global/skill/cooking/recipe/potato/impl/EggPotato.java deleted file mode 100644 index c616591fd..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/EggPotato.java +++ /dev/null @@ -1,49 +0,0 @@ -package content.global.skill.cooking.recipe.potato.impl; - -import content.global.skill.cooking.recipe.potato.PotatoRecipe; -import core.game.node.item.Item; - -/** - * Represents the egg potato recipe. This recipe consists of mixing a egg and a - * tomato. - * @author 'Vexia - * @date 22/12/2013 - */ -public class EggPotato extends PotatoRecipe { - - /** - * Represents the egg potato. - */ - private static final Item EGG_POTATO = new Item(7056); - - /** - * Represents the topping item. - */ - private static final Item TOPPING = new Item(7064); - - @Override - public Item getProduct() { - return EGG_POTATO; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TOPPING }; - } - - @Override - public boolean isTopping() { - return true; - } - - @Override - public int getLevel() { - return 51; - } - - @Override - public double getExperience() { - return 10; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/MushroomPotato.java b/Server/src/main/content/global/skill/cooking/recipe/potato/impl/MushroomPotato.java deleted file mode 100644 index d7bfa1c2c..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/MushroomPotato.java +++ /dev/null @@ -1,49 +0,0 @@ -package content.global.skill.cooking.recipe.potato.impl; - -import content.global.skill.cooking.recipe.potato.PotatoRecipe; -import core.game.node.item.Item; - -/** - * Represents the mushrrom potato. This recipe consists of mixing a baked potato - * with mushroom and onion toppings. - * @author 'Vexia - * @date 22/12/2013 - */ -public class MushroomPotato extends PotatoRecipe { - - /** - * Represents the egg potato. - */ - private static final Item MUSHROOM_POTATO = new Item(7058); - - /** - * Represents the topping item. - */ - private static final Item TOPPING = new Item(7066); - - @Override - public Item getProduct() { - return MUSHROOM_POTATO; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TOPPING }; - } - - @Override - public boolean isTopping() { - return true; - } - - @Override - public int getLevel() { - return 64; - } - - @Override - public double getExperience() { - return 10; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/TunaPotato.java b/Server/src/main/content/global/skill/cooking/recipe/potato/impl/TunaPotato.java deleted file mode 100644 index 645d5ed2e..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/potato/impl/TunaPotato.java +++ /dev/null @@ -1,49 +0,0 @@ -package content.global.skill.cooking.recipe.potato.impl; - -import content.global.skill.cooking.recipe.potato.PotatoRecipe; -import core.game.node.item.Item; - -/** - * Represents the tuna potato recipe. This recipe consists of mixing tuna and - * corn toppings. - * @author 'Vexia - * @date 22/12/2013 - */ -public class TunaPotato extends PotatoRecipe { - - /** - * Represents the tuna potato. - */ - private static final Item TUNA_POTATO = new Item(7060); - - /** - * Represents the topping item. - */ - private static final Item TOPPING = new Item(7068); - - @Override - public Item getProduct() { - return TUNA_POTATO; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TOPPING }; - } - - @Override - public boolean isTopping() { - return true; - } - - @Override - public int getLevel() { - return 68; - } - - @Override - public double getExperience() { - return 10; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/stew/CurryRecipe.java b/Server/src/main/content/global/skill/cooking/recipe/stew/CurryRecipe.java deleted file mode 100644 index 4ea78825d..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/stew/CurryRecipe.java +++ /dev/null @@ -1,89 +0,0 @@ -package content.global.skill.cooking.recipe.stew; - -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the curry recipe. This recipe consists of mixing 3 curry leaves or - * a spice into a stew. - * @author 'Vexia - * @date 22/12/2013 - */ -public class CurryRecipe extends Recipe { - - /** - * Represents the uncooked curry item. - */ - private static final Item UNCOOKED_CURRY = new Item(2009); - - /** - * Represents the uncooked stew item. - */ - private static final Item UNCOOKED_STEW = new Item(2001); - - /** - * Represents the spice item. - */ - private static final Item SPICE = new Item(2007); - - /** - * Represents the curry leaf. - */ - private static final Item CURRY_LEAF = new Item(5970); - - @Override - public void mix(Player player, NodeUsageEvent event) { - if (event.getBaseItem().getId() == CURRY_LEAF.getId() || event.getUsedItem().getId() == CURRY_LEAF.getId()) { - Item stew = event.getBaseItem().getId() == UNCOOKED_STEW.getId() ? event.getBaseItem() : event.getUsedItem(); - if (stew.getCharge() == 1000) { - stew.setCharge(1); - } - int charge = stew.getCharge(); - if (charge < 3) { - player.getInventory().remove(CURRY_LEAF); - stew.setCharge(charge + 1); - } else { - if (player.getInventory().remove(stew) && player.getInventory().remove(CURRY_LEAF)) { - player.getInventory().add(UNCOOKED_CURRY); - } - } - return; - } - if (player.getInventory().remove(event.getBaseItem()) && player.getInventory().remove(event.getUsedItem())) { - player.getInventory().add(getProduct()); - } - } - - @Override - public Item getBase() { - return UNCOOKED_STEW; - } - - @Override - public Item getProduct() { - return UNCOOKED_CURRY; - } - - @Override - public Item[] getIngredients() { - return new Item[] { SPICE, CURRY_LEAF }; - } - - @Override - public Item[] getParts() { - return new Item[] { UNCOOKED_STEW }; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You mix the spice with the stew."; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/stew/StewRecipe.java b/Server/src/main/content/global/skill/cooking/recipe/stew/StewRecipe.java deleted file mode 100644 index 4073bcc0e..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/stew/StewRecipe.java +++ /dev/null @@ -1,92 +0,0 @@ -package content.global.skill.cooking.recipe.stew; - -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the stew recipe. This recipe consists of mixing meat and a raw - * potato in a bowl of water. - * @author 'Vexia - * @date 22/12/2013 - */ -public class StewRecipe extends Recipe { - - /** - * Represents the uncooked stew item. - */ - private static final Item UNCOOKED_STEW = new Item(2001); - - /** - * Represents the bowl of water item. - */ - private static final Item BOWL_OF_WATER = new Item(1921); - - /** - * Represents the meat item. - */ - private static final Item MEAT = new Item(2142); - - /** - * Represents the potato item. - */ - private static final Item POTATO = new Item(1942); - - /** - * Represents the incomplete stew. - */ - private static final Item INCOMPLETE_STEW = new Item(1997); - - /** - * Represents the second incomplete stew. - */ - private static final Item INCOMPLETE_STEW2 = new Item(1999); - - @Override - public void mix(Player player, NodeUsageEvent event) { - Item first = event.getUsedItem(); - Item second = event.getBaseItem(); - if(first != null && second != null) { - if (player.getInventory().remove(first) && player.getInventory().remove(second)) { - if (first.getId() == BOWL_OF_WATER.getId() || second.getId() == BOWL_OF_WATER.getId()) { - player.getInventory().add(first.getId() == POTATO.getId() ? INCOMPLETE_STEW : first.getId() == MEAT.getId() ? INCOMPLETE_STEW2 : second.getId() == POTATO.getId() ? INCOMPLETE_STEW : second.getId() == MEAT.getId() ? INCOMPLETE_STEW2 : null); - } else { - player.getInventory().add(UNCOOKED_STEW); - } - player.getPacketDispatch().sendMessage(getMixMessage(event)); - } - } - } - - @Override - public Item getBase() { - return BOWL_OF_WATER; - } - - @Override - public Item getProduct() { - return UNCOOKED_STEW; - } - - @Override - public Item[] getIngredients() { - return new Item[] { MEAT, POTATO, MEAT, POTATO }; - } - - @Override - public Item[] getParts() { - return new Item[] { BOWL_OF_WATER, BOWL_OF_WATER, INCOMPLETE_STEW, INCOMPLETE_STEW2 }; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You cut up the " + (event.getUsedItem().getName().toLowerCase().contains("incomplete") ? event.getBaseItem().getName().toLowerCase() : event.getUsedItem().getName().toLowerCase().replace("cooked", "").trim()) + " and put it into the stew."; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/ToppingRecipe.java b/Server/src/main/content/global/skill/cooking/recipe/topping/ToppingRecipe.java deleted file mode 100644 index 5c2cacb15..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/ToppingRecipe.java +++ /dev/null @@ -1,58 +0,0 @@ -package content.global.skill.cooking.recipe.topping; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents a generic topping recipe. - * @author 'Vexia - * @date 22/12/2013 - */ -public abstract class ToppingRecipe extends Recipe { - - /** - * Represents the bowl item. - */ - protected static final Item BOWL = new Item(1923); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < getLevel()) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + getLevel() + " in order to do this."); - return; - } - super.mix(player, event); - player.getSkills().addExperience(Skills.COOKING, getExperience(), true); - } - - @Override - public Item getBase() { - return BOWL; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return null; - } - - @Override - public boolean isSingular() { - return true; - } - - /** - * Method used to get the level required. - * @return the level. - */ - public abstract int getLevel(); - - /** - * Method used to get the experience gained. - * @return the experience. - */ - public abstract double getExperience(); - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChilliConCarne.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChilliConCarne.java deleted file mode 100644 index 4085d149b..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChilliConCarne.java +++ /dev/null @@ -1,81 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the chilli con carne recipe. This recipe consists of using spicy - * sauce with cooked meat. - * @author 'Vexia - * @date 22/12/2013 - */ -public class ChilliConCarne extends Recipe { - - /** - * Represents the bowl item. - */ - private static final Item SPICY_SAUCE = new Item(7072); - - /** - * Represents the chilli con carne item. - */ - private static final Item CHILLI_CON_CARNE = new Item(7062); - - /** - * Represents the cooked meat item. - */ - private static final Item COOKED_MEAT = new Item(2142); - - /** - * Represents the knife item. - */ - private static final Item KNIFE = new Item(946); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 9) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + 9 + " in order to do this."); - return; - } - if (!player.getInventory().containsItem(KNIFE)) { - player.getDialogueInterpreter().sendDialogue("You need a knife in order to cut up the meat."); - return; - } - super.mix(player, event); - player.getSkills().addExperience(Skills.COOKING, 25, true); - } - - @Override - public Item getBase() { - return SPICY_SAUCE; - } - - @Override - public Item getProduct() { - return CHILLI_CON_CARNE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { COOKED_MEAT }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return "You put the cut up meat into the bowl."; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedOnion.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedOnion.java deleted file mode 100644 index 5a30107c1..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedOnion.java +++ /dev/null @@ -1,69 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import content.global.skill.cooking.recipe.topping.ToppingRecipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the chopped onion recipe. This recipe consists of using an onion - * on a bowl with a knife. - * @author 'Vexia - * @date 22/12/2013 - */ -public class ChoppedOnion extends ToppingRecipe { - - /** - * Represents the chopped onion product item. - */ - private static final Item CHOPPED_ONION = new Item(1871); - - /** - * Represents the knife used to cut the onion. - */ - private static final Item KNIFE = new Item(946); - - /** - * Represents the onion item. - */ - private static final Item ONION = new Item(1957); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (!player.getInventory().containsItem(KNIFE)) { - player.getDialogueInterpreter().sendDialogue("You need a knife in order to slice up the onion."); - return; - } - super.mix(player, event); - } - - @Override - public int getLevel() { - return 1; - } - - @Override - public double getExperience() { - return 0; - } - - @Override - public Item getProduct() { - return CHOPPED_ONION; - } - - @Override - public Item[] getIngredients() { - return new Item[] { ONION }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public boolean isSingular() { - return true; - } -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedTuna.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedTuna.java deleted file mode 100644 index 4723c61ff..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/ChoppedTuna.java +++ /dev/null @@ -1,69 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import content.global.skill.cooking.recipe.topping.ToppingRecipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the chopped tuna recipe. This recipe consists of adding tuna to a - * bowl with a knife. - * @author 'Vexia - * @date 22/12/2013 - */ -public class ChoppedTuna extends ToppingRecipe { - - /** - * Represents the chopped tuna item. - */ - private static final Item CHOPPED_TUNA = new Item(7086); - - /** - * Represents the tuna item. - */ - private static final Item TUNA = new Item(361); - - /** - * Represents the knife item. - */ - private static final Item KNIFE = new Item(946); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (!player.getInventory().containsItem(KNIFE)) { - player.getDialogueInterpreter().sendDialogue("You need a knife in order to slice up the tuna."); - return; - } - super.mix(player, event); - } - - @Override - public int getLevel() { - return 1; - } - - @Override - public double getExperience() { - return 1; - } - - @Override - public Item getProduct() { - return CHOPPED_TUNA; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TUNA }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public boolean isSingular() { - return true; - } -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/EggAndTomato.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/EggAndTomato.java deleted file mode 100644 index dabf2db2b..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/EggAndTomato.java +++ /dev/null @@ -1,72 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import content.global.skill.cooking.recipe.Recipe; -import core.game.node.entity.skill.Skills; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the egg and tomato recipe. This recipe consists of mixing a tomato - * with a scrambled egg. - * @author 'Vexia - * @date 22/12/2013 - */ -public class EggAndTomato extends Recipe { - - /** - * Represents the egg and tomato. - */ - private static final Item EGG_AND_TOMATO = new Item(7064); - - /** - * Represents the scrambled egg item. - */ - private static final Item SCRAMBLED_EGG = new Item(7078); - - /** - * epresents the tomato item. - */ - private static final Item TOMATO = new Item(1982); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 23) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + 23 + " in order to do this."); - return; - } - super.mix(player, event); - player.getSkills().addExperience(Skills.COOKING, 50, true); - } - - @Override - public Item getBase() { - return SCRAMBLED_EGG; - } - - @Override - public Item getProduct() { - return EGG_AND_TOMATO; - } - - @Override - public Item[] getIngredients() { - return new Item[] { TOMATO }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return null; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/MushroomAndOnion.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/MushroomAndOnion.java deleted file mode 100644 index 3b99200f7..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/MushroomAndOnion.java +++ /dev/null @@ -1,72 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the mushroom and onion recipe. This recipe consists of using a - * fried mushroom with a friend onion. - * @author 'Vexia - * @date 22/12/2013 - */ -public class MushroomAndOnion extends Recipe { - - /** - * Represents the mushroom and onion item. - */ - private static final Item MUSHROOM_AND_ONION = new Item(7066); - - /** - * Represents the fried onions item. - */ - private static final Item FRIED_ONIONS = new Item(7084); - - /** - * Represents the fried mushrooms item. - */ - private static final Item FRIED_MUSHROOMS = new Item(7082); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 57) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + 57 + " in order to do this."); - return; - } - super.mix(player, event); - player.getSkills().addExperience(Skills.COOKING, 120, true); - } - - @Override - public Item getBase() { - return FRIED_MUSHROOMS; - } - - @Override - public Item getProduct() { - return MUSHROOM_AND_ONION; - } - - @Override - public Item[] getIngredients() { - return new Item[] { FRIED_ONIONS }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return null; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/SlicedMushroom.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/SlicedMushroom.java deleted file mode 100644 index 46f9d09f8..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/SlicedMushroom.java +++ /dev/null @@ -1,69 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import content.global.skill.cooking.recipe.topping.ToppingRecipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the fried mushroom recipe. This recipe consists of using a - * mushroom on a bowl. - * @author 'Vexia - * @date 22/12/2013 - */ -public final class SlicedMushroom extends ToppingRecipe { - - /** - * Represents the sliced mushrooms item. - */ - private static final Item SLICED_MUSHROOMS = new Item(7080); - - /** - * Represents the mushroom item. - */ - private static final Item MUSHROOM = new Item(6004); - - /** - * Represents the knife item. - */ - private static final Item KNIFE = new Item(946); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (!player.getInventory().containsItem(KNIFE)) { - player.getDialogueInterpreter().sendDialogue("You need a knife in order to slice up the mushrooms."); - return; - } - super.mix(player, event); - } - - @Override - public int getLevel() { - return 1; - } - - @Override - public double getExperience() { - return 0; - } - - @Override - public Item getProduct() { - return SLICED_MUSHROOMS; - } - - @Override - public Item[] getIngredients() { - return new Item[] { MUSHROOM }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public boolean isSingular() { - return true; - } -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/SpicySauce.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/SpicySauce.java deleted file mode 100644 index 2b0a7e103..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/SpicySauce.java +++ /dev/null @@ -1,84 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the spicy sauce recipe. This recipe consists of mixing gnome spice - * and garlic together. - * @author 'Vexia - * @date 22/12/2013 - */ -public class SpicySauce extends Recipe { - - /** - * Represents the spicy sauce item. - */ - private static final Item SPICY_SAUCE = new Item(7072); - - /** - * Represents the bowl item. - */ - private static final Item BOWL = new Item(1923); - - /** - * Represents the garlic item. - */ - private static final Item GARLIC = new Item(1550); - - /** - * Represents the chopped garlic item. - */ - private static final Item CHOPPED_GARLIC = new Item(7074); - - /** - * Represents the gnome spice item. - */ - private static final Item GNOME_SPICE = new Item(2169); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 9) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + 9 + " in order to do this."); - return; - } - super.mix(player, event); - if (event.getBaseItem().getId() == GNOME_SPICE.getId() || event.getUsedItem().getId() == GNOME_SPICE.getId()) { - player.getSkills().addExperience(Skills.COOKING, 25, true); - } - } - - @Override - public Item getBase() { - return BOWL; - } - - @Override - public Item getProduct() { - return SPICY_SAUCE; - } - - @Override - public Item[] getIngredients() { - return new Item[] { GARLIC, GNOME_SPICE }; - } - - @Override - public Item[] getParts() { - return new Item[] { BOWL, CHOPPED_GARLIC, SPICY_SAUCE }; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return null; - } - - @Override - public boolean isSingular() { - return false; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/TunaAndCorn.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/TunaAndCorn.java deleted file mode 100644 index 1e2c92a6f..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/TunaAndCorn.java +++ /dev/null @@ -1,72 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import core.game.node.entity.skill.Skills; -import content.global.skill.cooking.recipe.Recipe; -import core.game.interaction.NodeUsageEvent; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -/** - * Represents the tuna and corn recipe. This recipe consists of adding cooked - * sweetcorn to a bowl of chopped tuna. - * @author 'Vexia - * @date 22/12/2013 - */ -public final class TunaAndCorn extends Recipe { - - /** - * Represents the chopped tuna item. - */ - private static final Item CHOPPED_TUNA = new Item(7086); - - /** - * Represents the cooked corn item. - */ - private static final Item COOKED_CORN = new Item(5988); - - /** - * Represents the tuna and corn item. - */ - private static final Item TUNA_AND_CORN = new Item(7068); - - @Override - public void mix(final Player player, final NodeUsageEvent event) { - if (player.getSkills().getLevel(Skills.COOKING) < 67) { - player.getDialogueInterpreter().sendDialogue("You need a Cooking level of at least " + 57 + " in order to do this."); - return; - } - super.mix(player, event); - player.getSkills().addExperience(Skills.COOKING, 204, true); - } - - @Override - public Item getBase() { - return CHOPPED_TUNA; - } - - @Override - public Item getProduct() { - return TUNA_AND_CORN; - } - - @Override - public Item[] getIngredients() { - return new Item[] { COOKED_CORN }; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - - @Override - public String getMixMessage(NodeUsageEvent event) { - return null; - } - - @Override - public boolean isSingular() { - return true; - } - -} diff --git a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/UncookedEgg.java b/Server/src/main/content/global/skill/cooking/recipe/topping/impl/UncookedEgg.java deleted file mode 100644 index 61ce50394..000000000 --- a/Server/src/main/content/global/skill/cooking/recipe/topping/impl/UncookedEgg.java +++ /dev/null @@ -1,54 +0,0 @@ -package content.global.skill.cooking.recipe.topping.impl; - -import content.global.skill.cooking.recipe.topping.ToppingRecipe; -import core.game.node.item.Item; - -/** - * Represents the uncooked egg recipe. This recipe consists of adding an - * uncooked egg into a bowl. - * @author 'Vexia - * @date 22/12/2013 - */ -public final class UncookedEgg extends ToppingRecipe { - - /** - * Represents the egg item. - */ - private static final Item EGG = new Item(1944); - - /** - * Represents the uncooked egg product. - */ - private static final Item UNCOOKED_EGG = new Item(7076); - - @Override - public int getLevel() { - return 1; - } - - @Override - public double getExperience() { - return 1; - } - - @Override - public Item getProduct() { - return UNCOOKED_EGG; - } - - @Override - public Item[] getIngredients() { - return new Item[] { EGG }; - } - - @Override - public boolean isSingular() { - return true; - } - - @Override - public Item[] getParts() { - return new Item[] {}; - } - -} From 13c4358d77ef13bb7369bb924af689c6d98f9e5c Mon Sep 17 00:00:00 2001 From: Oven Bread Date: Wed, 3 Jun 2026 12:52:06 +0000 Subject: [PATCH 2/3] Cleaned up some core files --- Server/src/main/core/cache/Cache.java | 2 +- Server/src/main/core/cache/CacheFile.java | 2 +- Server/src/main/core/cache/StoreFile.java | 72 ----- .../main/core/cache/crypto/ISAACCipher.java | 271 ------------------ .../src/main/core/cache/crypto/ISAACCipher.kt | 213 ++++++++++++++ .../src/main/core/cache/crypto/ISAACPair.java | 45 --- .../src/main/core/cache/crypto/ISAACPair.kt | 9 + .../main/core/cache/crypto/XTEACryption.java | 124 -------- .../main/core/cache/crypto/XTEACryption.kt | 97 +++++++ .../src/main/core/cache/misc/Container.java | 109 ------- Server/src/main/core/cache/misc/Container.kt | 7 + .../cache/misc/ContainersInformation.java | 228 --------------- .../core/cache/misc/ContainersInformation.kt | 145 ++++++++++ .../main/core/cache/misc/FilesContainer.java | 57 ---- .../main/core/cache/misc/FilesContainer.kt | 9 + .../cache/misc/buffer/BufferInputStream.java | 39 --- .../cache/misc/buffer/BufferOutputStream.java | 57 ---- .../cache/misc/buffer/ByteBufferUtils.java | 182 ------------ .../core/cache/misc/buffer/ByteBufferUtils.kt | 142 +++++++++ .../command/sets/DevelopmentCommandSet.kt | 38 +-- 20 files changed, 644 insertions(+), 1204 deletions(-) delete mode 100644 Server/src/main/core/cache/StoreFile.java delete mode 100644 Server/src/main/core/cache/crypto/ISAACCipher.java create mode 100644 Server/src/main/core/cache/crypto/ISAACCipher.kt delete mode 100644 Server/src/main/core/cache/crypto/ISAACPair.java create mode 100644 Server/src/main/core/cache/crypto/ISAACPair.kt delete mode 100644 Server/src/main/core/cache/crypto/XTEACryption.java create mode 100644 Server/src/main/core/cache/crypto/XTEACryption.kt delete mode 100644 Server/src/main/core/cache/misc/Container.java create mode 100644 Server/src/main/core/cache/misc/Container.kt delete mode 100644 Server/src/main/core/cache/misc/ContainersInformation.java create mode 100644 Server/src/main/core/cache/misc/ContainersInformation.kt delete mode 100644 Server/src/main/core/cache/misc/FilesContainer.java create mode 100644 Server/src/main/core/cache/misc/FilesContainer.kt delete mode 100644 Server/src/main/core/cache/misc/buffer/BufferInputStream.java delete mode 100644 Server/src/main/core/cache/misc/buffer/BufferOutputStream.java delete mode 100644 Server/src/main/core/cache/misc/buffer/ByteBufferUtils.java create mode 100644 Server/src/main/core/cache/misc/buffer/ByteBufferUtils.kt diff --git a/Server/src/main/core/cache/Cache.java b/Server/src/main/core/cache/Cache.java index ce4ed3c25..3459d58b9 100644 --- a/Server/src/main/core/cache/Cache.java +++ b/Server/src/main/core/cache/Cache.java @@ -145,7 +145,7 @@ public final class Cache { buffer.putInt(0); continue; } - buffer.putInt(cacheFileManagers[index].getInformation().getInformationContainer().getCrc()); + buffer.putInt(cacheFileManagers[index].getInformation().informationContainer.getCrc()); buffer.putInt(cacheFileManagers[index].getInformation().getRevision()); } return buffer.array(); diff --git a/Server/src/main/core/cache/CacheFile.java b/Server/src/main/core/cache/CacheFile.java index a03642895..bd21a8a0d 100644 --- a/Server/src/main/core/cache/CacheFile.java +++ b/Server/src/main/core/cache/CacheFile.java @@ -66,7 +66,7 @@ public final class CacheFile { return null; } if (xteaKeys != null && (xteaKeys[0] != 0 || xteaKeys[1] != 0 || xteaKeys[2] != 0 || xteaKeys[3] != 0)) { - packedData = XTEACryption.decrypt(xteaKeys, ByteBuffer.wrap(packedData), 5, packedData.length).array(); + packedData = XTEACryption.Companion.decrypt(xteaKeys, ByteBuffer.wrap(packedData), 5, packedData.length).array(); } return ContainersInformation.unpackCacheContainer(packedData); } diff --git a/Server/src/main/core/cache/StoreFile.java b/Server/src/main/core/cache/StoreFile.java deleted file mode 100644 index 50e1728d0..000000000 --- a/Server/src/main/core/cache/StoreFile.java +++ /dev/null @@ -1,72 +0,0 @@ -package core.cache; - -import java.nio.ByteBuffer; - -/** - * Represents a file used in the server store. - * @author Emperor - */ -public final class StoreFile { - - /** - * If the data can change during server runtime. - */ - private boolean dynamic; - - /** - * The file data. - */ - private byte[] data; - - /** - * Constructs a new {@code StoreFile} {@code Object}. - */ - public StoreFile() { - /* - * empty. - */ - } - - /** - * Puts the data on the buffer. - * @param buffer The buffer. - */ - public void put(ByteBuffer buffer) { - byte[] data = new byte[buffer.remaining()]; - buffer.get(data); - this.data = data; - } - - /** - * Creates a byte buffer containing the file data. - * @return The buffer. - */ - public ByteBuffer data() { - return ByteBuffer.wrap(data); - } - - /** - * Sets the data. - * @param data The data. - */ - public void setData(byte[] data) { - this.data = data; - } - - /** - * Gets the dynamic. - * @return The dynamic. - */ - public boolean isDynamic() { - return dynamic; - } - - /** - * Sets the dynamic. - * @param dynamic The dynamic to set. - */ - public void setDynamic(boolean dynamic) { - this.dynamic = dynamic; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/cache/crypto/ISAACCipher.java b/Server/src/main/core/cache/crypto/ISAACCipher.java deleted file mode 100644 index 16cd85b18..000000000 --- a/Server/src/main/core/cache/crypto/ISAACCipher.java +++ /dev/null @@ -1,271 +0,0 @@ -package core.cache.crypto; - -/** - *

An implementation of an ISAAC cipher. See - * http://en.wikipedia.org/wiki/ISAAC_(cipher) for more information.

- *

This implementation is based on the one written by Bob Jenkins, which is - * available at - * http://www.burtleburtle.net/bob/java/rand/Rand.java.

- * @author Graham Edgecombe - */ -public class ISAACCipher { - - /** - * The golden ratio. - */ - public static final int RATIO = 0x9e3779b9; - - /** - * The log of the size of the results and memory arrays. - */ - public static final int SIZE_LOG = 8; - - /** - * The size of the results and memory arrays. - */ - public static final int SIZE = 1 << SIZE_LOG; - - /** - * For pseudorandom lookup. - */ - public static final int MASK = (SIZE - 1) << 2; - - /** - * The count through the results. - */ - private int count = 0; - - /** - * The results. - */ - private int results[] = new int[SIZE]; - - /** - * The internal memory state. - */ - private int memory[] = new int[SIZE]; - - /** - * The accumulator. - */ - private int a; - - /** - * The last result. - */ - private int b; - - /** - * The counter. - */ - private int c; - - /** - * Creates the ISAAC cipher. - * @param seed The seed. - */ - public ISAACCipher(int[] seed) { - for (int i = 0; i < seed.length; i++) { - results[i] = seed[i]; - } - init(true); - } - - /** - * Gets the next value. - * @return The next value. - */ - public int getNextValue() { - if (count-- == 0) { - isaac(); - count = SIZE - 1; - } - return 0;//results[count]; - } - - /** - * Generates 256 results. - */ - public void isaac() { - int i, j, x, y; - b += ++c; - for (i = 0, j = SIZE / 2; i < SIZE / 2;) { - x = memory[i]; - a ^= a << 13; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - - x = memory[i]; - a ^= a >>> 6; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - - x = memory[i]; - a ^= a << 2; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - - x = memory[i]; - a ^= a >>> 16; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - } - for (j = 0; j < SIZE / 2;) { - x = memory[i]; - a ^= a << 13; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - - x = memory[i]; - a ^= a >>> 6; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - - x = memory[i]; - a ^= a << 2; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - - x = memory[i]; - a ^= a >>> 16; - a += memory[j++]; - memory[i] = y = memory[(x & MASK) >> 2] + a + b; - results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; - } - } - - /** - * Initialises the ISAAC. - * @param flag Flag indicating if we should perform a second pass. - */ - public void init(boolean flag) { - int i; - int a, b, c, d, e, f, g, h; - a = b = c = d = e = f = g = h = RATIO; - for (i = 0; i < 4; ++i) { - a ^= b << 11; - d += a; - b += c; - b ^= c >>> 2; - e += b; - c += d; - c ^= d << 8; - f += c; - d += e; - d ^= e >>> 16; - g += d; - e += f; - e ^= f << 10; - h += e; - f += g; - f ^= g >>> 4; - a += f; - g += h; - g ^= h << 8; - b += g; - h += a; - h ^= a >>> 9; - c += h; - a += b; - } - for (i = 0; i < SIZE; i += 8) { - if (flag) { - a += results[i]; - b += results[i + 1]; - c += results[i + 2]; - d += results[i + 3]; - e += results[i + 4]; - f += results[i + 5]; - g += results[i + 6]; - h += results[i + 7]; - } - a ^= b << 11; - d += a; - b += c; - b ^= c >>> 2; - e += b; - c += d; - c ^= d << 8; - f += c; - d += e; - d ^= e >>> 16; - g += d; - e += f; - e ^= f << 10; - h += e; - f += g; - f ^= g >>> 4; - a += f; - g += h; - g ^= h << 8; - b += g; - h += a; - h ^= a >>> 9; - c += h; - a += b; - memory[i] = a; - memory[i + 1] = b; - memory[i + 2] = c; - memory[i + 3] = d; - memory[i + 4] = e; - memory[i + 5] = f; - memory[i + 6] = g; - memory[i + 7] = h; - } - if (flag) { - for (i = 0; i < SIZE; i += 8) { - a += memory[i]; - b += memory[i + 1]; - c += memory[i + 2]; - d += memory[i + 3]; - e += memory[i + 4]; - f += memory[i + 5]; - g += memory[i + 6]; - h += memory[i + 7]; - a ^= b << 11; - d += a; - b += c; - b ^= c >>> 2; - e += b; - c += d; - c ^= d << 8; - f += c; - d += e; - d ^= e >>> 16; - g += d; - e += f; - e ^= f << 10; - h += e; - f += g; - f ^= g >>> 4; - a += f; - g += h; - g ^= h << 8; - b += g; - h += a; - h ^= a >>> 9; - c += h; - a += b; - memory[i] = a; - memory[i + 1] = b; - memory[i + 2] = c; - memory[i + 3] = d; - memory[i + 4] = e; - memory[i + 5] = f; - memory[i + 6] = g; - memory[i + 7] = h; - } - } - isaac(); - count = SIZE; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/cache/crypto/ISAACCipher.kt b/Server/src/main/core/cache/crypto/ISAACCipher.kt new file mode 100644 index 000000000..d3fab467b --- /dev/null +++ b/Server/src/main/core/cache/crypto/ISAACCipher.kt @@ -0,0 +1,213 @@ +package core.cache.crypto + +/** + * An implementation of an ISAAC cipher. + * See [http://en.wikipedia.org/wiki/ISAAC_(cipher)](http://en.wikipedia.org/wiki/ISAAC_(cipher)) for more information. + * Based on the one written by Bob Jenkins, which is available at + * [http://www.burtleburtle.net/bob/java/rand/Rand.java](http://www.burtleburtle.net/bob/java/rand/Rand.java). + */ +class ISAACCipher(seed: IntArray) { + companion object { + /** Golden ratio in 32 bit unsigned int. */ + const val RATIO = -0x61c88647 + /** The base 2 log of the size of the results and memory arrays. */ + const val SIZE_LOG = 8 + /** The size of the results and memory arrays. */ + const val SIZE = 1 shl SIZE_LOG + /** For pseudorandom lookup. */ + const val MASK = SIZE - 1 shl 2 + } + /** The count through the results. */ + private var count = 0 + /** The results. */ + private val results = IntArray(SIZE) + /** The internal memory state. */ + private val memory = IntArray(SIZE) + /** The accumulator. */ + private var a = 0 + /** The last result. */ + private var b = 0 + /** The counter. */ + private var c = 0 + + /** + * Creates the ISAAC cipher. + * @param seed The seed. + */ + init { + for (i in seed.indices) { + results[i] = seed[i] + } + init(true) + } + + val nextValue: Int + /** + * Gets the next value. + * @return The next value. + */ + get() { + if (count-- == 0) { + isaac() + count = SIZE - 1 + } + return 0 //results[count]; + } + + /** + * Generates 256 results. + */ + fun isaac() { + var i: Int + var j: Int + var x: Int + var y: Int + b += ++c + i = 0 + j = SIZE / 2 + while (i < SIZE / 2) { + x = memory[i] + a = a xor (a shl 13) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + x = memory[i] + a = a xor (a ushr 6) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + x = memory[i] + a = a xor (a shl 2) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + x = memory[i] + a = a xor (a ushr 16) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + } + j = 0 + while (j < SIZE / 2) { + x = memory[i] + a = a xor (a shl 13) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + x = memory[i] + a = a xor (a ushr 6) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + x = memory[i] + a = a xor (a shl 2) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + x = memory[i] + a = a xor (a ushr 16) + a += memory[j++] + y = memory[x and MASK shr 2] + a + b + memory[i] = y + b = memory[y shr SIZE_LOG and MASK shr 2] + x + results[i++] = b + } + } + + /** + * Initialises the ISAAC. + * @param flag Flag indicating if we should perform a second pass. + */ + fun init(flag: Boolean) { + var a = RATIO + var b = a; var c = b; var d = c; var e = d; var f = e; var g = f; var h = g + var i = 0 + while (i < 4) { + a = a xor (b shl 11); d += a; b += c + b = b xor (c ushr 2); e += b; c += d + c = c xor (d shl 8); f += c; d += e + d = d xor (e ushr 16); g += d; e += f + e = e xor (f shl 10); h += e; f += g + f = f xor (g ushr 4); a += f; g += h + g = g xor (h shl 8); b += g; h += a + h = h xor (a ushr 9); c += h; a += b + ++i + } + i = 0 + while (i < SIZE) { + if (flag) { + a += results[i] + b += results[i + 1] + c += results[i + 2] + d += results[i + 3] + e += results[i + 4] + f += results[i + 5] + g += results[i + 6] + h += results[i + 7] + } + a = a xor (b shl 11); d += a; b += c + b = b xor (c ushr 2); e += b; c += d + c = c xor (d shl 8); f += c; d += e + d = d xor (e ushr 16); g += d; e += f + e = e xor (f shl 10); h += e; f += g + f = f xor (g ushr 4); a += f; g += h + g = g xor (h shl 8); b += g; h += a + h = h xor (a ushr 9); c += h; a += b + memory[i] = a + memory[i + 1] = b + memory[i + 2] = c + memory[i + 3] = d + memory[i + 4] = e + memory[i + 5] = f + memory[i + 6] = g + memory[i + 7] = h + i += 8 + } + if (flag) { + i = 0 + while (i < SIZE) { + a += memory[i] + b += memory[i + 1] + c += memory[i + 2] + d += memory[i + 3] + e += memory[i + 4] + f += memory[i + 5] + g += memory[i + 6] + h += memory[i + 7] + a = a xor (b shl 11); d += a; b += c + b = b xor (c ushr 2); e += b; c += d + c = c xor (d shl 8); f += c; d += e + d = d xor (e ushr 16); g += d; e += f + e = e xor (f shl 10); h += e; f += g + f = f xor (g ushr 4); a += f; g += h + g = g xor (h shl 8); b += g; h += a + h = h xor (a ushr 9); c += h; a += b + memory[i] = a + memory[i + 1] = b + memory[i + 2] = c + memory[i + 3] = d + memory[i + 4] = e + memory[i + 5] = f + memory[i + 6] = g + memory[i + 7] = h + i += 8 + } + } + isaac() + count = SIZE + } +} \ No newline at end of file diff --git a/Server/src/main/core/cache/crypto/ISAACPair.java b/Server/src/main/core/cache/crypto/ISAACPair.java deleted file mode 100644 index 83c4654b9..000000000 --- a/Server/src/main/core/cache/crypto/ISAACPair.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.cache.crypto; - -/** - * Represents a ISAAC key pair, for both input and output. - * @author `Discardedx2 - */ -public final class ISAACPair { - - /** - * The input cipher. - */ - private ISAACCipher input; - - /** - * The output cipher. - */ - private ISAACCipher output; - - /** - * Constructs a new {@code ISAACPair} {@code Object}. - * @param input The input cipher. - * @param output The output cipher. - */ - public ISAACPair(ISAACCipher input, ISAACCipher output) { - this.input = input; - this.output = output; - } - - /** - * Gets the input cipher. - * @return The input cipher. - */ - public ISAACCipher getInput() { - return input; - } - - /** - * Gets the output cipher. - * @return The output cipher. - */ - public ISAACCipher getOutput() { - return output; - } - -} diff --git a/Server/src/main/core/cache/crypto/ISAACPair.kt b/Server/src/main/core/cache/crypto/ISAACPair.kt new file mode 100644 index 000000000..9056c7a9d --- /dev/null +++ b/Server/src/main/core/cache/crypto/ISAACPair.kt @@ -0,0 +1,9 @@ +package core.cache.crypto + +/** + * Represents a ISAAC key pair, for both input and output. + */ +class ISAACPair( + val input: ISAACCipher, + val output: ISAACCipher +) diff --git a/Server/src/main/core/cache/crypto/XTEACryption.java b/Server/src/main/core/cache/crypto/XTEACryption.java deleted file mode 100644 index 7ed799e58..000000000 --- a/Server/src/main/core/cache/crypto/XTEACryption.java +++ /dev/null @@ -1,124 +0,0 @@ -package core.cache.crypto; - -import java.nio.ByteBuffer; - -/** - * Holds XTEA cryption methods. - * @author ? - * @author Emperor - */ -public final class XTEACryption { - - /** - * The delta value - */ - private static final int DELTA = -1640531527; - - /** - * The sum. - */ - private static final int SUM = -957401312; - - /** - * The amount of "cryption cycles". - */ - private static final int NUM_ROUNDS = 32; - - /** - * Constructs a new {@code XTEACryption}. - */ - private XTEACryption() { - /* - * empty. - */ - } - - /** - * Decrypts the contents of the buffer. - * @param keys The cryption keys. - * @param buffer The buffer. - */ - public static ByteBuffer decrypt(int[] keys, ByteBuffer buffer) { - return decrypt(keys, buffer, buffer.position(), buffer.limit()); - } - - /** - * Decrypts the buffer data. - * @param keys The keys. - * @param buffer The buffer to decrypt. - * @param offset The offset of the data to decrypt. - * @param length The length. - * @return The decrypted data. - */ - public static ByteBuffer decrypt(int[] keys, ByteBuffer buffer, int offset, int length) { - int numBlocks = (length - offset) / 8; - int[] block = new int[2]; - for (int i = 0; i < numBlocks; i++) { - int index = i * 8 + offset; - block[0] = buffer.getInt(index); - block[1] = buffer.getInt(index + 4); - decipher(keys, block); - buffer.putInt(index, block[0]); - buffer.putInt(index + 4, block[1]); - } - return buffer; - } - - /** - * Deciphers the values. - * @param keys The cryption key. - * @param block The values to decipher. - */ - private static void decipher(int[] keys, int[] block) { - long sum = SUM; - for (int i = 0; i < NUM_ROUNDS; i++) { - block[1] -= (keys[(int) ((sum & 0x1933) >>> 11)] + sum ^ block[0] + (block[0] << 4 ^ block[0] >>> 5)); - sum -= DELTA; - block[0] -= ((block[1] << 4 ^ block[1] >>> 5) + block[1] ^ keys[(int) (sum & 0x3)] + sum); - } - } - - /** - * Encrypts the contents of the byte buffer. - * @param keys The cryption keys. - * @param buffer The buffer to encrypt. - */ - public static void encrypt(int[] keys, ByteBuffer buffer) { - encrypt(keys, buffer, buffer.position(), buffer.limit()); - } - - /** - * Encrypts the buffer data. - * @param keys The keys. - * @param buffer The buffer to encrypt. - * @param offset The offset of the data to encrypt. - * @param length The length. - * @return The encrypted data. - */ - public static void encrypt(int[] keys, ByteBuffer buffer, int offset, int length) { - int numBlocks = (length - offset) / 8; - int[] block = new int[2]; - for (int i = 0; i < numBlocks; i++) { - int index = i * 8 + offset; - block[0] = buffer.getInt(index); - block[1] = buffer.getInt(index + 4); - encipher(keys, block); - buffer.putInt(index, block[0]); - buffer.putInt(index + 4, block[1]); - } - } - - /** - * Enciphers the values of the block. - * @param keys The cryption keys. - * @param block The block to encipher. - */ - private static void encipher(int[] keys, int[] block) { - long sum = 0; - for (int i = 0; i < NUM_ROUNDS; i++) { - block[0] += ((block[1] << 4 ^ block[1] >>> 5) + block[1] ^ keys[(int) (sum & 0x3)] + sum); - sum += DELTA; - block[1] += (keys[(int) ((sum & 0x1933) >>> 11)] + sum ^ block[0] + (block[0] << 4 ^ block[0] >>> 5)); - } - } -} \ No newline at end of file diff --git a/Server/src/main/core/cache/crypto/XTEACryption.kt b/Server/src/main/core/cache/crypto/XTEACryption.kt new file mode 100644 index 000000000..f87477008 --- /dev/null +++ b/Server/src/main/core/cache/crypto/XTEACryption.kt @@ -0,0 +1,97 @@ +package core.cache.crypto + +import java.nio.ByteBuffer + +/** Holds XTEA(eXtended Tiny Encryption Algorithm) encryption/decryption methods. Usually used for RS Map decryption. */ +class XTEACryption { + companion object { + // Purely Static Class + // XTEA consts https://scispace.com/pdf/xtea-cryptography-implementation-in-android-chatting-app-3pg6ownewx.pdf + /** Fibonacci hashing. Math.pow(2,32) * Math.sqrt(5)-1)/2 => 32 bits(int) multiply by reciprocal of golden ratio. */ + private const val DELTA = -1640531527 // Formula cast to unsigned int. + /** DELTA << 5. Essentially multiply DELTA by NUM_ROUNDS or number of rounds. */ + private const val SUM = -957401312 // 0xC6EF3720 + /** The amount of "cryption cycles". */ + private const val NUM_ROUNDS = 32 + /** Constant to manipulate the key index in decipher/encrypt. This was a magic number randomly selected by RS. */ + private const val KEY_SCRAMBLE = 0x1933 + + /** + * Decrypts the buffer data. + * @param keys The keys. + * @param buffer The buffer to decrypt. + * @param offset The offset of the data to decrypt. + * @param length The length. + * @return The decrypted data. + */ + fun decrypt(keys: IntArray, buffer: ByteBuffer, offset: Int, length: Int): ByteBuffer { + val numBlocks = (length - offset) / 8 + val block = IntArray(2) + for (i in 0 until numBlocks) { + val index = i * 8 + offset + block[0] = buffer.getInt(index) + block[1] = buffer.getInt(index + 4) + decipher(keys, block) + buffer.putInt(index, block[0]) + buffer.putInt(index + 4, block[1]) + } + return buffer + } + + /** + * Deciphers the values of the block using the Tiny Encryption Algorithm (TEA). + * This algorithm relies on a Feistel network, using bitwise operations and + * modular subtraction to remove confusion(block[0] line) and diffusion(block[1] line). + * + * @param keys 128-bit key (4x32-bit int). + * @param block 64-bit data block (2x32-bit int) to be decrypted. + */ + private fun decipher(keys: IntArray, block: IntArray) { + var sum = + SUM.toLong() // Running decreasing sum to ensure different round constants - should become 0 at the end. + for (i in 0 until NUM_ROUNDS) { + block[1] -= (keys[(sum and KEY_SCRAMBLE.toLong() ushr 11).toInt()] + sum xor (block[0] + (block[0] shl 4 xor (block[0] ushr 5))).toLong()).toInt() + sum -= DELTA.toLong() + block[0] -= (((block[1] shl 4 xor (block[1] ushr 5)) + block[1]).toLong() xor keys[(sum and 0x3L).toInt()] + sum).toInt() + } + } + /** === Encryption functions below are not used unless you are modifying the cache. === */ + /** + * Encrypts the buffer data. + * @param keys The keys. + * @param buffer The buffer to encrypt. + * @param offset The offset of the data to encrypt. + * @param length The length. + * @return The encrypted data. + */ + fun encrypt(keys: IntArray, buffer: ByteBuffer, offset: Int, length: Int) { + val numBlocks = (length - offset) / 8 + val block = IntArray(2) + for (i in 0 until numBlocks) { + val index = i * 8 + offset + block[0] = buffer.getInt(index) + block[1] = buffer.getInt(index + 4) + encipher(keys, block) + buffer.putInt(index, block[0]) + buffer.putInt(index + 4, block[1]) + } + } + + /** + * Enciphers the values of the block using the Tiny Encryption Algorithm (TEA). + * This algorithm relies on a Feistel network, using bitwise operations and + * modular addition to provide confusion(block[0] line) and diffusion(block[1] line). + * + * @param keys 128-bit key (4x32-bit int). + * @param block 64-bit data block (2x32-bit int) to be encrypted. + */ + private fun encipher(keys: IntArray, block: IntArray) { + var sum: Long = 0 // Running sum to ensure different round constants - should match SUM at the end. + for (i in 0 until NUM_ROUNDS) { + block[0] += (((block[1] shl 4 xor (block[1] ushr 5)) + block[1]).toLong() xor keys[(sum and 0x3L).toInt()] + sum).toInt() + sum += DELTA.toLong() + block[1] += (keys[(sum and KEY_SCRAMBLE.toLong() ushr 11).toInt()] + sum xor (block[0] + (block[0] shl 4 xor (block[0] ushr 5))).toLong()).toInt() + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/cache/misc/Container.java b/Server/src/main/core/cache/misc/Container.java deleted file mode 100644 index 9760845ff..000000000 --- a/Server/src/main/core/cache/misc/Container.java +++ /dev/null @@ -1,109 +0,0 @@ -package core.cache.misc; - -/** - * A container. - * @author Dragonkk - */ -public class Container { - - /** - * The version. - */ - private int version; - - /** - * The CRC. - */ - private int crc; - - /** - * The name hash. - */ - private int nameHash; - - /** - * If updated. - */ - private boolean updated; - - /** - * Construct a new container. - */ - public Container() { - nameHash = -1; - version = -1; - crc = -1; - } - - /** - * Set the version. - * @param version - */ - public void setVersion(int version) { - this.version = version; - } - - /** - * Update the version. - */ - public void updateVersion() { - version++; - updated = true; - } - - /** - * Get the version. - * @return The version. - */ - public int getVersion() { - return version; - } - - /** - * Get the next version. - * @return The next version. - */ - public int getNextVersion() { - return updated ? version : version + 1; - } - - /** - * Set the CRC. - * @param crc The cRC. - */ - public void setCrc(int crc) { - this.crc = crc; - } - - /** - * Get the CRC. - * @return The CRC. - */ - public int getCrc() { - return crc; - } - - /** - * Set the name hash. - * @param nameHash The name hash. - */ - public void setNameHash(int nameHash) { - this.nameHash = nameHash; - } - - /** - * Get the name hash. - * @return The name hash. - */ - public int getNameHash() { - return nameHash; - } - - /** - * If is updated. - * @return If is updated. - */ - public boolean isUpdated() { - return updated; - } -} diff --git a/Server/src/main/core/cache/misc/Container.kt b/Server/src/main/core/cache/misc/Container.kt new file mode 100644 index 000000000..3e1b481d6 --- /dev/null +++ b/Server/src/main/core/cache/misc/Container.kt @@ -0,0 +1,7 @@ +package core.cache.misc + +data class Container( + var version: Int = -1, + var crc: Int = -1, + var nameHash: Int = -1 +) \ No newline at end of file diff --git a/Server/src/main/core/cache/misc/ContainersInformation.java b/Server/src/main/core/cache/misc/ContainersInformation.java deleted file mode 100644 index f786c1d2f..000000000 --- a/Server/src/main/core/cache/misc/ContainersInformation.java +++ /dev/null @@ -1,228 +0,0 @@ -package core.cache.misc; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.zip.CRC32; - -import core.cache.bzip2.BZip2Decompressor; -import core.cache.gzip.GZipDecompressor; - -/** - * A class holding the containers information. - * @author Dragonkk - */ -public final class ContainersInformation { - - /** - * The information container. - */ - private Container informationContainer; - - /** - * The protocol. - */ - private int protocol; - - /** - * The revision. - */ - private int revision; - - /** - * The container indexes. - */ - private int[] containersIndexes; - - /** - * The containers. - */ - private FilesContainer[] containers; - - /** - * If files have to be named. - */ - private boolean filesNamed; - - /** - * If it has to be whirpool. - */ - private boolean whirpool; - - /** - * The data. - */ - private final byte[] data; - - /** - * Construct a new containers information. - * @param informationContainerPackedData The information container data - * packed. - */ - public ContainersInformation(byte[] informationContainerPackedData) { - this.data = Arrays.copyOf(informationContainerPackedData, informationContainerPackedData.length); - informationContainer = new Container(); - informationContainer.setVersion((informationContainerPackedData[informationContainerPackedData.length - 2] << 8 & 0xff00) + (informationContainerPackedData[-1 + informationContainerPackedData.length] & 0xff)); - CRC32 crc32 = new CRC32(); - crc32.update(informationContainerPackedData); - informationContainer.setCrc((int) crc32.getValue()); - decodeContainersInformation(unpackCacheContainer(informationContainerPackedData)); - } - - /** - * Unpacks a container. - * @param packedData The packed container data. - * @return The unpacked data. - */ - public static final byte[] unpackCacheContainer(byte[] packedData) { - ByteBuffer buffer = ByteBuffer.wrap(packedData); - int compression = buffer.get() & 0xFF; - int containerSize = buffer.getInt(); - if (containerSize < 0 || containerSize > 5000000) { - return null; - // throw new RuntimeException(); - } - if (compression == 0) { - byte unpacked[] = new byte[containerSize]; - buffer.get(unpacked, 0, containerSize); - return unpacked; - } - int decompressedSize = buffer.getInt(); - if (decompressedSize < 0 || decompressedSize > 20000000) { - return null; - // throw new RuntimeException(); - } - byte decompressedData[] = new byte[decompressedSize]; - if (compression == 1) { - BZip2Decompressor.decompress(decompressedData, packedData, containerSize, 9); - } else { - GZipDecompressor.decompress(buffer, decompressedData); - } - return decompressedData; - } - - /** - * Get the container indexes. - * @return The container indexes. - */ - public int[] getContainersIndexes() { - return containersIndexes; - } - - /** - * Get the containers. - * @return The containers. - */ - public FilesContainer[] getContainers() { - return containers; - } - - /** - * Get the information container. - * @return The information container. - */ - public Container getInformationContainer() { - return informationContainer; - } - - /** - * Get the revision. - * @return The revision. - */ - public int getRevision() { - return revision; - } - - /** - * Decode the containers information. - * @param data The data. - */ - public void decodeContainersInformation(byte[] data) { - ByteBuffer buffer = ByteBuffer.wrap(data); - protocol = buffer.get() & 0xFF; - if (protocol != 5 && protocol != 6) { - throw new RuntimeException(); - } - revision = protocol < 6 ? 0 : buffer.getInt(); - int nameHash = buffer.get() & 0xFF; - filesNamed = (0x1 & nameHash) != 0; - whirpool = (0x2 & nameHash) != 0; - containersIndexes = new int[buffer.getShort() & 0xFFFF]; - int lastIndex = -1; - for (int index = 0; index < containersIndexes.length; index++) { - containersIndexes[index] = (buffer.getShort() & 0xFFFF) + (index == 0 ? 0 : containersIndexes[index - 1]); - if (containersIndexes[index] > lastIndex) { - lastIndex = containersIndexes[index]; - } - } - containers = new FilesContainer[lastIndex + 1]; - for (int index = 0; index < containersIndexes.length; index++) { - containers[containersIndexes[index]] = new FilesContainer(); - } - if (filesNamed) { - for (int index = 0; index < containersIndexes.length; index++) { - containers[containersIndexes[index]].setNameHash(buffer.getInt()); - } - } - byte[][] filesHashes = null; - if (whirpool) { - filesHashes = new byte[containers.length][]; - for (int index = 0; index < containersIndexes.length; index++) { - filesHashes[containersIndexes[index]] = new byte[64]; - buffer.get(filesHashes[containersIndexes[index]], 0, 64); - } - } - for (int index = 0; index < containersIndexes.length; index++) { - containers[containersIndexes[index]].setCrc(buffer.getInt()); - } - for (int index = 0; index < containersIndexes.length; index++) { - containers[containersIndexes[index]].setVersion(buffer.getInt()); - } - for (int index = 0; index < containersIndexes.length; index++) { - containers[containersIndexes[index]].setFilesIndexes(new int[buffer.getShort() & 0xFFFF]); - } - for (int index = 0; index < containersIndexes.length; index++) { - int lastFileIndex = -1; - for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) { - containers[containersIndexes[index]].getFilesIndexes()[fileIndex] = (buffer.getShort() & 0xFFFF) + (fileIndex == 0 ? 0 : containers[containersIndexes[index]].getFilesIndexes()[fileIndex - 1]); - if (containers[containersIndexes[index]].getFilesIndexes()[fileIndex] > lastFileIndex) { - lastFileIndex = containers[containersIndexes[index]].getFilesIndexes()[fileIndex]; - } - } - containers[containersIndexes[index]].setFiles(new Container[lastFileIndex + 1]); - for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) { - containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]] = new Container(); - } - } - if (whirpool) { - for (int index = 0; index < containersIndexes.length; index++) { - for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) { - containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setVersion(filesHashes[containersIndexes[index]][containers[containersIndexes[index]].getFilesIndexes()[fileIndex]]); - } - } - } - if (filesNamed) { - for (int index = 0; index < containersIndexes.length; index++) { - for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) { - containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setNameHash(buffer.getInt()); - } - } - } - } - - /** - * If is whirpool. - * @return If is whirpool {@code true}. - */ - public boolean isWhirpool() { - return whirpool; - } - - /** - * Gets the data. - * @return The data. - */ - public byte[] getData() { - return data; - } - -} diff --git a/Server/src/main/core/cache/misc/ContainersInformation.kt b/Server/src/main/core/cache/misc/ContainersInformation.kt new file mode 100644 index 000000000..831eb954b --- /dev/null +++ b/Server/src/main/core/cache/misc/ContainersInformation.kt @@ -0,0 +1,145 @@ +package core.cache.misc + +import core.cache.bzip2.BZip2Decompressor +import core.cache.gzip.GZipDecompressor +import java.nio.ByteBuffer +import java.util.* +import java.util.zip.CRC32 + +class ContainersInformation(informationContainerPackedData: ByteArray) { + @JvmField + val informationContainer: Container + private var protocol = 0 + var revision = 0 + var containersIndexes: IntArray = intArrayOf() + var containers: Array = arrayOf() + private var filesNamed = false // If files has to be named + private var whirpool = false // Flag for whirpool + val data: ByteArray + + init { + data = Arrays.copyOf(informationContainerPackedData, informationContainerPackedData.size) + informationContainer = Container() + informationContainer.version = + (informationContainerPackedData[informationContainerPackedData.size - 2].toInt() shl 8 and 0xff00) + (informationContainerPackedData[-1 + informationContainerPackedData.size].toInt() and 0xff) + val crc32 = CRC32() + crc32.update(informationContainerPackedData) + informationContainer.crc = crc32.value.toInt() + decodeContainersInformation(unpackCacheContainer(informationContainerPackedData)) + } + + fun decodeContainersInformation(data: ByteArray?) { + val buffer = ByteBuffer.wrap(data) + protocol = buffer.get().toInt() and 0xFF + if (protocol != 5 && protocol != 6) { + throw RuntimeException() + } + revision = if (protocol < 6) 0 else buffer.getInt() + val nameHash = buffer.get().toInt() and 0xFF + filesNamed = 0x1 and nameHash != 0 + whirpool = 0x2 and nameHash != 0 + containersIndexes = IntArray(buffer.getShort().toInt() and 0xFFFF) + var lastIndex = -1 + for (index in containersIndexes.indices) { + val containerIndex = + (buffer.getShort().toInt() and 0xFFFF) + if (index == 0) 0 else containersIndexes[index - 1] + containersIndexes[index] = containerIndex + if (containerIndex > lastIndex) { + lastIndex = containerIndex + } + } + containers = arrayOfNulls(lastIndex + 1) + for (containerIdx in containersIndexes) { + containers[containerIdx] = FilesContainer() + } + if (filesNamed) { + for (containerIdx in containersIndexes) { + containers[containerIdx]!!.nameHash = buffer.getInt() + } + } + var filesHashes: Array? = null + if (whirpool) { + filesHashes = arrayOfNulls(containers.size) + for (containerIdx in containersIndexes) { + filesHashes[containerIdx] = ByteArray(64) + buffer[filesHashes[containerIdx], 0, 64] + } + } + for (containerIdx in containersIndexes) { + containers[containerIdx]!!.crc = buffer.getInt() + } + for (containerIdx in containersIndexes) { + containers[containerIdx]!!.version = buffer.getInt() + } + for (containerIdx in containersIndexes) { + containers[containerIdx]!!.filesIndexes = IntArray(buffer.getShort().toInt() and 0xFFFF) + } + for (containerIdx in containersIndexes) { + val container = containers[containerIdx] + val filesIndexes = container!!.filesIndexes + var lastFileIndex = -1 + for (fileIndex in filesIndexes!!.indices) { + val fileIdx = + (buffer.getShort().toInt() and 0xFFFF) + if (fileIndex == 0) 0 else filesIndexes[fileIndex - 1] + filesIndexes[fileIndex] = fileIdx + if (fileIdx > lastFileIndex) { + lastFileIndex = fileIdx + } + } + val files = arrayOfNulls(lastFileIndex + 1) + container.files = files + for (fileIdx in filesIndexes) { + files[fileIdx] = Container() + } + } + if (whirpool) { + for (containerIdx in containersIndexes) { + val container = containers[containerIdx] + val containerHashes = filesHashes!![containerIdx] + val files = container!!.files + for (fileIdx in container.filesIndexes!!) { + files!![fileIdx]!!.version = containerHashes!![fileIdx].toInt() + } + } + } + if (filesNamed) { + for (containerIdx in containersIndexes) { + val container = containers[containerIdx] + val files = container!!.files + for (fileIdx in container.filesIndexes!!) { + files!![fileIdx]!!.nameHash = buffer.getInt() + } + } + } + } + + companion object { + @JvmStatic + fun unpackCacheContainer(packedData: ByteArray?): ByteArray? { + val buffer = ByteBuffer.wrap(packedData) + val compression = buffer.get().toInt() and 0xFF + val containerSize = buffer.getInt() + if (containerSize < 0 || containerSize > 5000000) { + return null + // throw new RuntimeException(); + } + if (compression == 0) { + val unpacked = ByteArray(containerSize) + buffer[unpacked, 0, containerSize] + return unpacked + } + val decompressedSize = buffer.getInt() + if (decompressedSize < 0 || decompressedSize > 20000000) { + return null + // throw new RuntimeException(); + } + val decompressedData = ByteArray(decompressedSize) + if (compression == 1) { + BZip2Decompressor.decompress(decompressedData, packedData, containerSize, 9) + } else { + GZipDecompressor.decompress(buffer, decompressedData) + } + return decompressedData + } + } +} diff --git a/Server/src/main/core/cache/misc/FilesContainer.java b/Server/src/main/core/cache/misc/FilesContainer.java deleted file mode 100644 index 5f14e448f..000000000 --- a/Server/src/main/core/cache/misc/FilesContainer.java +++ /dev/null @@ -1,57 +0,0 @@ -package core.cache.misc; - -/** - * A class holding the file containers. - * @author Dragonkk - */ -public final class FilesContainer extends Container { - - /** - * The file indexes. - */ - private int[] filesIndexes; - - /** - * The files. - */ - private Container[] files; - - /** - * Construct a new files container. - */ - public FilesContainer() { - - } - - /** - * Set the files. - * @param containers The files. - */ - public void setFiles(Container[] containers) { - this.files = containers; - } - - /** - * Get the files. - * @return The files. - */ - public Container[] getFiles() { - return files; - } - - /** - * Set the file indexes. - * @param containersIndexes The file indexes. - */ - public void setFilesIndexes(int[] containersIndexes) { - this.filesIndexes = containersIndexes; - } - - /** - * Get the file indexes. - * @return The file indexes. - */ - public int[] getFilesIndexes() { - return filesIndexes; - } -} diff --git a/Server/src/main/core/cache/misc/FilesContainer.kt b/Server/src/main/core/cache/misc/FilesContainer.kt new file mode 100644 index 000000000..192ca3389 --- /dev/null +++ b/Server/src/main/core/cache/misc/FilesContainer.kt @@ -0,0 +1,9 @@ +package core.cache.misc + +data class FilesContainer( + var version: Int = -1, + var crc: Int = -1, + var nameHash: Int = -1, + var filesIndexes: IntArray? = null, + var files: Array? = null +) \ No newline at end of file diff --git a/Server/src/main/core/cache/misc/buffer/BufferInputStream.java b/Server/src/main/core/cache/misc/buffer/BufferInputStream.java deleted file mode 100644 index a801c870d..000000000 --- a/Server/src/main/core/cache/misc/buffer/BufferInputStream.java +++ /dev/null @@ -1,39 +0,0 @@ -package core.cache.misc.buffer; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; - -/** - * Handles the reading of data from a byte buffer. - * @author Emperor - */ -public final class BufferInputStream extends InputStream { - - /** - * The buffer to write on. - */ - private final ByteBuffer buffer; - - /** - * The buffer input stream. - * @param buffer The buffer. - */ - public BufferInputStream(ByteBuffer buffer) throws IOException { - this.buffer = buffer; - } - - @Override - public int read() throws IOException { - return buffer.get(); - } - - /** - * Gets the buffer. - * @return The buffer. - */ - public ByteBuffer getBuffer() { - return buffer; - } - -} diff --git a/Server/src/main/core/cache/misc/buffer/BufferOutputStream.java b/Server/src/main/core/cache/misc/buffer/BufferOutputStream.java deleted file mode 100644 index 88ea2ac69..000000000 --- a/Server/src/main/core/cache/misc/buffer/BufferOutputStream.java +++ /dev/null @@ -1,57 +0,0 @@ -package core.cache.misc.buffer; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; - -/** - * Handles the writing of data on a byte buffer. - * @author Emperor - */ -public final class BufferOutputStream extends OutputStream { - - /** - * The buffer to write on. - */ - private final ByteBuffer buffer; - - /** - * Constructs a new {@code BufferOutputStream} {@code Object}. - * @param buffer The buffer to write on. - * @throws IOException When an I/O exception occurs. - * @throws SecurityException If a security manager exists and its - * checkPermission method denies enabling subclassing. - */ - public BufferOutputStream(ByteBuffer buffer) throws IOException, SecurityException { - super(); - this.buffer = buffer; - } - - @Override - public void write(int b) throws IOException { - buffer.put((byte) b); - } - - @Override - public void flush() { - /* - * empty. - */ - } - - @Override - public void close() { - /* - * empty. - */ - } - - /** - * Gets the buffer. - * @return The buffer. - */ - public ByteBuffer getBuffer() { - return buffer; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/cache/misc/buffer/ByteBufferUtils.java b/Server/src/main/core/cache/misc/buffer/ByteBufferUtils.java deleted file mode 100644 index fb04ae272..000000000 --- a/Server/src/main/core/cache/misc/buffer/ByteBufferUtils.java +++ /dev/null @@ -1,182 +0,0 @@ -package core.cache.misc.buffer; - -import java.io.ObjectInputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; - -/** - * Holds utility methods for reading/writing a byte buffer. - * @author Emperor - */ -public final class ByteBufferUtils { - - /** - * Gets a string from the byte buffer. - * @param buffer The byte buffer. - * @return The string. - */ - public static String getString(ByteBuffer buffer) { - StringBuilder sb = new StringBuilder(); - byte b; - while ((b = buffer.get()) != 0) { - sb.append((char) b); - } - return sb.toString(); - } - - /** - * Puts a string on the byte buffer. - * @param s The string to put. - * @param buffer The byte buffer. - */ - public static void putString(String s, ByteBuffer buffer) { - buffer.put(s.getBytes(StandardCharsets.UTF_8)).put((byte) 0); - } - - /** - * Gets a string from the byte buffer. - * @param s The string. - * @param buffer The byte buffer. - * @return The string. - */ - public static ByteBuffer putGJ2String(String s, ByteBuffer buffer) { - byte[] packed = new byte[256]; - int length = packGJString2(0, packed, s); - return buffer.put((byte) 0).put(packed, 0, length).put((byte) 0); - } - - /** - * Decodes the XTEA encryption. - * @param keys The keys. - * @param start The start index. - * @param end The end index. - * @param buffer The byte buffer. - */ - public static void decodeXTEA(int[] keys, int start, int end, ByteBuffer buffer) { - int l = buffer.position(); - buffer.position(start); - int length = (end - start) / 8; - for (int i = 0; i < length; i++) { - int firstInt = buffer.getInt(); - int secondInt = buffer.getInt(); - int sum = 0xc6ef3720; - int delta = 0x9e3779b9; - for (int j = 32; j-- > 0;) { - secondInt -= keys[(sum & 0x1c84) >>> 11] + sum ^ (firstInt >>> 5 ^ firstInt << 4) + firstInt; - sum -= delta; - firstInt -= (secondInt >>> 5 ^ secondInt << 4) + secondInt ^ keys[sum & 3] + sum; - } - buffer.position(buffer.position() - 8); - buffer.putInt(firstInt); - buffer.putInt(secondInt); - } - buffer.position(l); - } - - /** - * Converts a String to an Integer? - * @param position The position. - * @param buffer The buffer used. - * @param string The String to convert. - * @return The Integer. - */ - public static int packGJString2(int position, byte[] buffer, String string) { - int length = string.length(); - int offset = position; - for (int i = 0; length > i; i++) { - int character = string.charAt(i); - if (character > 127) { - if (character > 2047) { - buffer[offset++] = (byte) ((character | 919275) >> 12); - buffer[offset++] = (byte) (128 | ((character >> 6) & 63)); - buffer[offset++] = (byte) (128 | (character & 63)); - } else { - buffer[offset++] = (byte) ((character | 12309) >> 6); - buffer[offset++] = (byte) (128 | (character & 63)); - } - } else - buffer[offset++] = (byte) character; - } - return offset - position; - } - - /** - * Gets a tri-byte from the buffer. - * @param buffer The buffer. - * @return The value. - */ - public static int getMedium(ByteBuffer buffer) { - return ((buffer.get() & 0xFF) << 16) + ((buffer.get() & 0xFF) << 8) + (buffer.get() & 0xFF); - } - - /** - * Gets a smart from the buffer. - * @param buffer The buffer. - * @return The value. - */ - public static int getSmart(ByteBuffer buffer) { - int peek = buffer.get() & 0xFF; - if (peek <= Byte.MAX_VALUE) { - return peek; - } - return ((peek << 8) | (buffer.get() & 0xFF)) - 32768; - } - - /** - * Gets a smart from the buffer. - * @param buffer The buffer. - * @return The value. - */ - public static int getBigSmart(ByteBuffer buffer) { - int value = 0; - int current = getSmart(buffer); - while (current == 32767) { - current = getSmart(buffer); - value += 32767; - } - value += current; - return value; - } - - /* *//** - * Writes an object on the buffer. - * @param buffer The buffer to write on. - * @param o The object. - */ - /* - * public static void putObject(ByteBuffer buffer, Object o) { ByteBuffer b; - * try (ObjectOutputStream out = new ObjectOutputStream(new - * BufferOutputStream(b = ByteBuffer.allocate(99999)))) { - * out.writeObject(o); b.flip(); } catch (Throwable e) { - * e.printStackTrace(); b = (ByteBuffer) ByteBuffer.allocate(0).flip(); } - * buffer.putInt(b.remaining()); if (b.remaining() > 0) { buffer.put(b); } } - */ - - /** - * Gets an object from the byte buffer. - * @param buffer The buffer. - * @return The object. - */ - public static Object getObject(ByteBuffer buffer) { - int length = buffer.getInt(); - if (length > 0) { - byte[] bytes = new byte[length]; - buffer.get(bytes); - try (ObjectInputStream str = new ObjectInputStream(new BufferInputStream(ByteBuffer.wrap(bytes)))) { - return (Object) str.readObject(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - return null; - } - - /** - * Constructs a new {@code ByteBufferUtils} {@code Object}. - */ - private ByteBufferUtils() { - /* - * empty. - */ - } -} \ No newline at end of file diff --git a/Server/src/main/core/cache/misc/buffer/ByteBufferUtils.kt b/Server/src/main/core/cache/misc/buffer/ByteBufferUtils.kt new file mode 100644 index 000000000..73d72df70 --- /dev/null +++ b/Server/src/main/core/cache/misc/buffer/ByteBufferUtils.kt @@ -0,0 +1,142 @@ +package core.cache.misc.buffer + +import java.nio.ByteBuffer +import java.nio.charset.StandardCharsets + +object ByteBufferUtils { + /** + * Gets a string from the byte buffer. + * @param buffer The byte buffer. + * @return The string. + */ + @JvmStatic + fun getString(buffer: ByteBuffer): String { + val sb = StringBuilder() + var b: Byte + while (buffer.get().also { b = it }.toInt() != 0) { + sb.append(Char(b.toUShort())) + } + return sb.toString() + } + + /** + * Puts a string on the byte buffer. + * @param s The string to put. + * @param buffer The byte buffer. + */ + @JvmStatic + fun putString(s: String, buffer: ByteBuffer) { + buffer.put(s.toByteArray(StandardCharsets.UTF_8)).put(0.toByte()) + } + + /** + * Gets a string from the byte buffer. + * @param s The string. + * @param buffer The byte buffer. + * @return The string. + */ + fun putGJ2String(s: String, buffer: ByteBuffer): ByteBuffer { + val packed = ByteArray(256) + val length = packGJString2(0, packed, s) + return buffer.put(0.toByte()).put(packed, 0, length).put(0.toByte()) + } + + /** + * Decodes the XTEA encryption. + * @param keys The keys. + * @param start The start index. + * @param end The end index. + * @param buffer The byte buffer. + */ + fun decodeXTEA(keys: IntArray, start: Int, end: Int, buffer: ByteBuffer) { + val l = buffer.position() + buffer.position(start) + val length = (end - start) / 8 + for (i in 0 until length) { + var firstInt = buffer.getInt() + var secondInt = buffer.getInt() + var sum = -0x3910c8e0 + val delta = -0x61c88647 + var j = 32 + while (j-- > 0) { + secondInt -= keys[sum and 0x1c84 ushr 11] + sum xor (firstInt ushr 5 xor (firstInt shl 4)) + firstInt + sum -= delta + firstInt -= (secondInt ushr 5 xor (secondInt shl 4)) + secondInt xor keys[sum and 3] + sum + } + buffer.position(buffer.position() - 8) + buffer.putInt(firstInt) + buffer.putInt(secondInt) + } + buffer.position(l) + } + + /** + * Converts a String to an Integer? + * @param position The position. + * @param buffer The buffer used. + * @param string The String to convert. + * @return The Integer. + */ + @JvmStatic + fun packGJString2(position: Int, buffer: ByteArray, string: String): Int { + val length = string.length + var offset = position + var i = 0 + while (length > i) { + val character = string[i].code + if (character > 127) { + if (character > 2047) { + buffer[offset++] = (character or 919275 shr 12).toByte() + buffer[offset++] = (128 or (character shr 6 and 63)).toByte() + buffer[offset++] = (128 or (character and 63)).toByte() + } else { + buffer[offset++] = (character or 12309 shr 6).toByte() + buffer[offset++] = (128 or (character and 63)).toByte() + } + } else buffer[offset++] = character.toByte() + i++ + } + return offset - position + } + + /** + * Gets a tri-byte from the buffer. + * @param buffer The buffer. + * @return The value. + */ + @JvmStatic + fun getMedium(buffer: ByteBuffer): Int { + return (buffer.get().toInt() and 0xFF shl 16) + (buffer.get().toInt() and 0xFF shl 8) + (buffer.get() + .toInt() and 0xFF) + } + + /** + * Gets a smart from the buffer. + * @param buffer The buffer. + * @return The value. + */ + @JvmStatic + fun getSmart(buffer: ByteBuffer): Int { + val peek = buffer.get().toInt() and 0xFF + return if (peek <= Byte.MAX_VALUE) { + peek + } else (peek shl 8 or (buffer.get().toInt() and 0xFF)) - 32768 + } + + /** + * Gets a smart from the buffer. + * @param buffer The buffer. + * @return The value. + */ + @JvmStatic + fun getBigSmart(buffer: ByteBuffer): Int { + var value = 0 + var current = getSmart(buffer) + while (current == 32767) { + current = getSmart(buffer) + value += 32767 + } + value += current + return value + } +} \ No newline at end of file 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 53004f2b9..65ffe1369 100644 --- a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt @@ -190,15 +190,16 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { val dump = File("structs.txt") val writer = BufferedWriter(FileWriter(dump)) val index = Cache.getIndexes()[2] - val containers = index.information.containers[26].filesIndexes - for(fID in containers) - { - val file = index.getFileData(26, fID) - if(file != null){ - val def = Struct.parse(fID, file) - if(def.dataStore.isEmpty()) continue //no data in struct. - writer.write(def.toString()) - writer.newLine() + val containers = index.information.containers[26]!!.filesIndexes + if (containers != null) { + for(fID in containers) { + val file = index.getFileData(26, fID) + if(file != null){ + val def = Struct.parse(fID, file) + if(def.dataStore.isEmpty()) continue //no data in struct. + writer.write(def.toString()) + writer.newLine() + } } } writer.flush() @@ -214,15 +215,16 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { for(cID in containers) { - val fileIndexes = index.information.containers[cID].filesIndexes - for(fID in fileIndexes) - { - val file = index.getFileData(cID, fID) - if(file != null){ - val def = DataMap.parse((cID shl 8) or fID, file) - if(def.keyType == '?') continue //Empty definition - only a 0 present in the cachefile data. - writer.write(def.toString()) - writer.newLine() + val fileIndexes = index.information.containers[cID]!!.filesIndexes + if (fileIndexes != null) { + for(fID in fileIndexes) { + val file = index.getFileData(cID, fID) + if(file != null){ + val def = DataMap.parse((cID shl 8) or fID, file) + if(def.keyType == '?') continue //Empty definition - only a 0 present in the cachefile data. + writer.write(def.toString()) + writer.newLine() + } } } } From aae03d85fdda44fbc619624af934ae8ead0b8139 Mon Sep 17 00:00:00 2001 From: Bishop Date: Wed, 3 Jun 2026 12:57:37 +0000 Subject: [PATCH 3/3] Fixed revenants getting stuck --- .../handlers/revenants/RevenantController.kt | 237 ++++++++++++++++-- 1 file changed, 211 insertions(+), 26 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 91a5831ba..fed2f91ec 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantController.kt @@ -9,7 +9,7 @@ import core.game.world.update.flag.context.Graphics import core.tools.RandomFunction import core.ServerConstants import core.api.* -import core.tools.SystemLogger +import core.game.node.entity.combat.InteractionType import core.game.system.command.Privilege import core.game.world.GameWorld import core.game.world.map.path.Pathfinder @@ -28,10 +28,21 @@ class RevenantController : TickListener, Commands { private var expectedRevAmount: Int = ServerConstants.REVENANT_POPULATION private var groupPatrolQueue = ArrayList() + // Movement tracking for stuck detection + private val movementStartTick = HashMap() + private val lastKnownLocation = HashMap() + private val failedAttempts = HashMap() + // Stuck detector config + private const val STUCK_CHECK_INTERVAL = 10 // ticks + private const val MAX_FAILED_ATTEMPTS = 5 + @JvmStatic fun registerRevenant(revenantNPC: RevenantNPC) { trackedRevenants.add(revenantNPC) taskTimeRemaining[revenantNPC] = 0 currentTask[revenantNPC] = RevenantTask.NONE + movementStartTick[revenantNPC] = GameWorld.ticks + lastKnownLocation[revenantNPC] = revenantNPC.location + failedAttempts[revenantNPC] = 0 Repository.RENDERABLE_NPCS.add(revenantNPC) } @@ -39,19 +50,188 @@ class RevenantController : TickListener, Commands { trackedRevenants.remove(revenantNPC) taskTimeRemaining.remove(revenantNPC) currentTask.remove(revenantNPC) + movementStartTick.remove(revenantNPC) + lastKnownLocation.remove(revenantNPC) + failedAttempts.remove(revenantNPC) + groupPatrolQueue.remove(revenantNPC) if (removeRender) Repository.RENDERABLE_NPCS.remove(revenantNPC) } + private fun route(vararg coords: Pair): Array = + Array(coords.size) { Location.create(coords[it].first, coords[it].second) } + + // All routes that revs attempt to path through val routes = listOf( - arrayOf(Location.create(3070, 3651), Location.create(3083, 3640), Location.create(3106, 3645), Location.create(3133, 3647), Location.create(3149, 3642), Location.create(3160, 3654), Location.create(3171, 3665, 0), Location.create(3189, 3663, 0), Location.create(3202, 3675, 0), Location.create(3217, 3660, 0), Location.create(3235, 3661, 0), Location.create(3235, 3661, 0), Location.create(3279, 3650, 0), Location.create(3269, 3636, 0), Location.create(3253, 3632, 0), Location.create(3236, 3638, 0), Location.create(3220, 3637, 0), Location.create(3203, 3634, 0), Location.create(3187, 3631, 0), Location.create(3166, 3633, 0), Location.create(3160, 3616, 0), Location.create(3148, 3604, 0), Location.create(3134, 3596, 0), Location.create(3118, 3590, 0), Location.create(3104, 3597, 0)), - arrayOf(Location.create(3077, 3565, 0), Location.create(3093, 3559, 0), Location.create(3110, 3566, 0), Location.create(3127, 3574, 0), Location.create(3146, 3571, 0), Location.create(3164, 3575, 0), Location.create(3183, 3573, 0), Location.create(3197, 3587, 0), Location.create(3215, 3584, 0), Location.create(3233, 3576, 0), Location.create(3251, 3573, 0), Location.create(3269, 3577, 0), Location.create(3287, 3569, 0), Location.create(3305, 3568, 0), Location.create(3321, 3576, 0), Location.create(3338, 3584, 0), Location.create(3352, 3573, 0), Location.create(3354, 3554, 0), Location.create(3342, 3541, 0), Location.create(3324, 3536, 0), Location.create(3306, 3543, 0), Location.create(3290, 3544, 0), Location.create(3272, 3545, 0), Location.create(3255, 3546, 0), Location.create(3239, 3539, 0), Location.create(3222, 3543, 0), Location.create(3206, 3548, 0), Location.create(3189, 3549, 0), Location.create(3173, 3552, 0), Location.create(3157, 3549, 0), Location.create(3140, 3548, 0), Location.create(3122, 3548, 0), Location.create(3110, 3555, 0)), - arrayOf(Location.create(3318, 3691, 0), Location.create(3307, 3700, 0), Location.create(3290, 3696, 0), Location.create(3277, 3706, 0), Location.create(3260, 3706, 0), Location.create(3250, 3707, 0), Location.create(3245, 3723, 0), Location.create(3254, 3735, 0), Location.create(3251, 3754, 0), Location.create(3243, 3768, 0), Location.create(3253, 3780, 0), Location.create(3238, 3783, 0), Location.create(3224, 3793, 0), Location.create(3206, 3786, 0), Location.create(3192, 3780, 0), Location.create(3170, 3787, 0), Location.create(3156, 3800, 0), Location.create(3148, 3814, 0), Location.create(3148, 3814, 0), Location.create(3127, 3840, 0), Location.create(3124, 3856, 0), Location.create(3124, 3872, 0), Location.create(3116, 3892, 0)), - arrayOf(Location.create(2949, 3890, 0), Location.create(2965, 3899, 0), Location.create(2984, 3900, 0), Location.create(2998, 3895, 0), Location.create(3016, 3898, 0), Location.create(3032, 3893, 0), Location.create(3048, 3897, 0), Location.create(3068, 3894, 0), Location.create(3084, 3898, 0), Location.create(3101, 3895, 0), Location.create(3118, 3897, 0), Location.create(3136, 3893, 0), Location.create(3154, 3900, 0), Location.create(3172, 3895, 0), Location.create(3189, 3892, 0), Location.create(3206, 3897, 0), Location.create(3222, 3890, 0), Location.create(3240, 3897, 0), Location.create(3259, 3892, 0), Location.create(3278, 3895, 0), Location.create(3296, 3892, 0), Location.create(3313, 3899, 0), Location.create(3331, 3888, 0), Location.create(3345, 3880, 0)), - arrayOf(Location.create(3308, 3941, 0), Location.create(3301, 3925, 0), Location.create(3287, 3915, 0), Location.create(3276, 3922, 0), Location.create(3266, 3938, 0), Location.create(3267, 3952, 0), Location.create(3250, 3949, 0), Location.create(3235, 3944, 0), Location.create(3219, 3944, 0), Location.create(3206, 3938, 0), Location.create(3194, 3929, 0), Location.create(3182, 3921, 0), Location.create(3174, 3936, 0), Location.create(3180, 3952, 0), Location.create(3167, 3960, 0), Location.create(3155, 3959, 0), Location.create(3141, 3953, 0), Location.create(3126, 3954, 0), Location.create(3110, 3961, 0), Location.create(3093, 3962, 0), Location.create(3078, 3953, 0), Location.create(3066, 3942, 0), Location.create(3059, 3929, 0), Location.create(3049, 3916, 0), Location.create(3033, 3924, 0), Location.create(3020, 3921, 0), Location.create(3010, 3913, 0), Location.create(2993, 3906, 0), Location.create(2977, 3911, 0), Location.create(2970, 3928, 0)) + route( + 3070 to 3651, 3083 to 3640, 3106 to 3645, 3133 to 3647, 3149 to 3642, + 3160 to 3654, 3171 to 3665, 3189 to 3663, 3202 to 3675, 3217 to 3660, + 3235 to 3661, 3235 to 3661, 3279 to 3650, 3269 to 3636, 3253 to 3632, + 3236 to 3638, 3220 to 3637, 3203 to 3634, 3187 to 3631, 3166 to 3633, + 3160 to 3616, 3148 to 3604, 3134 to 3596, 3118 to 3590, 3104 to 3597, + ), + route( + 3077 to 3565, 3093 to 3559, 3110 to 3566, 3127 to 3574, 3146 to 3571, + 3164 to 3575, 3183 to 3573, 3197 to 3587, 3215 to 3584, 3233 to 3576, + 3251 to 3573, 3269 to 3577, 3287 to 3569, 3305 to 3568, 3321 to 3576, + 3338 to 3584, 3352 to 3573, 3354 to 3554, 3342 to 3541, 3324 to 3536, + 3306 to 3543, 3290 to 3544, 3272 to 3545, 3255 to 3546, 3239 to 3539, + 3222 to 3543, 3206 to 3548, 3189 to 3549, 3173 to 3552, 3157 to 3549, + 3140 to 3548, 3122 to 3548, 3110 to 3555, + ), + route( + 3318 to 3691, 3307 to 3700, 3290 to 3696, 3277 to 3706, 3260 to 3706, + 3250 to 3707, 3245 to 3723, 3254 to 3735, 3251 to 3754, 3243 to 3768, + 3253 to 3780, 3238 to 3783, 3224 to 3793, 3206 to 3786, 3192 to 3780, + 3170 to 3787, 3156 to 3800, 3148 to 3814, 3148 to 3814, 3127 to 3840, + 3124 to 3856, 3124 to 3872, 3116 to 3892, + ), + route( + 2949 to 3890, 2965 to 3899, 2984 to 3900, 2998 to 3895, 3016 to 3898, + 3032 to 3893, 3048 to 3897, 3068 to 3894, 3084 to 3898, 3101 to 3895, + 3118 to 3897, 3136 to 3893, 3154 to 3900, 3172 to 3895, 3189 to 3892, + 3206 to 3897, 3222 to 3890, 3240 to 3897, 3259 to 3892, 3278 to 3895, + 3296 to 3892, 3313 to 3899, 3331 to 3888, 3345 to 3880, + ), + route( + 3308 to 3941, 3301 to 3925, 3287 to 3915, 3276 to 3922, 3266 to 3938, + 3267 to 3952, 3250 to 3949, 3235 to 3944, 3219 to 3944, 3206 to 3938, + 3194 to 3929, 3182 to 3921, 3174 to 3936, 3180 to 3952, 3167 to 3960, + 3155 to 3959, 3141 to 3953, 3126 to 3954, 3110 to 3961, 3093 to 3962, + 3078 to 3953, 3066 to 3942, 3059 to 3929, 3049 to 3916, 3033 to 3924, + 3020 to 3921, 3010 to 3913, 2993 to 3906, 2977 to 3911, 2970 to 3928, + ), + route( + 3308 to 3941, 3301 to 3925, 3297 to 3914, 3286 to 3910, 3259 to 3912, + 3267 to 3952, 3251 to 3921, 3236 to 3918, 3222 to 3922, 3209 to 3920, + 3190 to 3933, 3177 to 3939, 3175 to 3951, 3167 to 3960, 3155 to 3959, + 3135 to 3951, 3134 to 3921, 3126 to 3914, 3108 to 3907, 3087 to 3910, + 3077 to 3925, 3076 to 3937, 3066 to 3942, 3059 to 3929, 3049 to 3916, + 3033 to 3924, 3020 to 3921, 3010 to 3913, 2993 to 3906, 2977 to 3911, + 2970 to 3928, + ), ) - val spawnLocations = listOf(Location.create(3075, 3553, 0), Location.create(3077, 3563, 0), Location.create(3077, 3578, 0), Location.create(3093, 3581, 0), Location.create(3103, 3570, 0), Location.create(3101, 3564, 0), Location.create(3030, 3596, 0), Location.create(3015, 3598, 0), Location.create(3000, 3593, 0), Location.create(2986, 3588, 0), Location.create(2969, 3701, 0), Location.create(2982, 3689, 0), Location.create(2967, 3689, 0), Location.create(2953, 3711, 0), Location.create(2966, 3759, 0), Location.create(2989, 3759, 0), Location.create(2986, 3741, 0), Location.create(2961, 3763, 0), Location.create(2969, 3808, 0), Location.create(3004, 3816, 0)) + // Routes that Dark Beasts are too fat for + private val largeNpcIncompatibleRoutes = setOf(4) + + val spawnLocations = listOf( + 3075 to 3553, 3077 to 3563, 3077 to 3578, 3093 to 3581, 3103 to 3570, + 3101 to 3564, 3030 to 3596, 3015 to 3598, 3000 to 3593, 2986 to 3588, + 2969 to 3701, 2982 to 3689, 2967 to 3689, 2953 to 3713, 2966 to 3759, + 2989 to 3759, 2986 to 3741, 2961 to 3763, 2969 to 3808, 3004 to 3816, + ).map { (x, y) -> Location.create(x, y) } + + /** + * Revenant stuck detector + * Makes sure Revenants are either moving, intentionally waiting to act, or are in legitimate combat + * If they aren't, they're passed to the stuck handler + */ + private fun checkIfStuck(revenantNPC: RevenantNPC): Boolean { + val lastTick = movementStartTick[revenantNPC] ?: 0 + val lastLoc = lastKnownLocation[revenantNPC] ?: revenantNPC.location + + // Period between checks - configure above + if (lastTick == 0 || (GameWorld.ticks - lastTick) < STUCK_CHECK_INTERVAL) { + return false + } + + // Check if positioned exactly at a patrol route start location (likely intentionally inactive) + val routeStartLocations = routes.map { it[0] } + val isAtRouteStart = routeStartLocations.any { it.equals(revenantNPC.location) } + + // Check if in legitimate combat + val combatPulse = revenantNPC.properties.combatPulse + val victim = combatPulse.getVictim() + val isInLegitimateCombat = if (victim != null) { + val interactionType = combatPulse.canInteract() + interactionType == InteractionType.STILL_INTERACT // The merits of MOVE_INTERACT regarding establishing a legitimate combat state are covered by the distanceMoved check a few lines from now + } else { + false + } + + if (isAtRouteStart || isInLegitimateCombat) { //If the Revenant has a good reason to not be moving, skip the movement check + movementStartTick[revenantNPC] = GameWorld.ticks + lastKnownLocation[revenantNPC] = revenantNPC.location + failedAttempts[revenantNPC] = 0 + return false + } + + // Check if the revenant has moved + val distanceMoved = revenantNPC.location.getDistance(lastLoc) + val isStuck = distanceMoved <= 2 + + // Reset the timer to check if they are stuck, since we are checking now + movementStartTick[revenantNPC] = GameWorld.ticks + + // Clear the Revenant's demerits towards being timed out if it is not stuck + if (!isStuck) { + lastKnownLocation[revenantNPC] = revenantNPC.location + failedAttempts[revenantNPC] = 0 + } + + return isStuck + } + + /** + * Revenant stuck handler + * Tries to help the Revenant escape after giving it a demerit + * If the Revenant gets too many demerits, it will be timed out instead + * NOTE: times out Revenants in unloaded regions as they have no land to path to and thus cannot move + */ + private fun handleStuckRevenant(revenantNPC: RevenantNPC) { + val attempts = failedAttempts[revenantNPC] ?: 0 + failedAttempts[revenantNPC] = attempts + 1 + + if (attempts + 1 > MAX_FAILED_ATTEMPTS) { + poofClear(revenantNPC) + revenantNPC.setAttribute("done", true) + return + } + + // The stuck Revenant will attempt to unstick itself + val escapeLocation = getNextLocation(revenantNPC) + revenantNPC.pulseManager.run(object : MovementPulse(revenantNPC, escapeLocation, Pathfinder.SMART) { + override fun pulse(): Boolean { + return true + } + }) + } + + /** + * Finds a random location to try to move to that is within the Wilderness + */ + fun getNextLocation(revenantNPC: RevenantNPC): Location { + val rawNextX = RandomFunction.random(-revenantNPC.walkRadius, revenantNPC.walkRadius) + val nextX = maxOf(rawNextX, 2951) + val rawNextY = RandomFunction.random(-revenantNPC.walkRadius, revenantNPC.walkRadius) + val nextY = maxOf(rawNextY, 3523) + return revenantNPC.location.transform(nextX, nextY, 0) + } + + /** + * Determines how far Revenants can deviate from their path + */ + private fun getPathVariance(revenantNPC: RevenantNPC, isGroup: Boolean): Int { + return when { + isGroup -> 4 + revenantNPC.size() >= 3 -> 2 // Dark Beasts are fat, so keep them close to their safe routes + else -> 10 + } + } + + /** + * Gets a random route for patrols + * Will not assign Dark Beasts to routes they are too fat for + */ + private fun getSuitableRoute(revenantNPC: RevenantNPC): Array { + val availableRoutes = if (revenantNPC.size() >= 3) { + routes.filterIndexed { index, _ -> index !in largeNpcIncompatibleRoutes } + } else { + routes + } + return availableRoutes.random() + } } override fun tick() { @@ -113,7 +293,13 @@ class RevenantController : TickListener, Commands { private val MAX_ROAM_TICKS: Int = 250 override fun execute(revenantNPC: RevenantNPC) { - if (!canMove(revenantNPC)) return + + if (checkIfStuck(revenantNPC)) { + handleStuckRevenant(revenantNPC) + return + } + + if (!canMoveBasic(revenantNPC)) return val nextLoc = getNextLocation(revenantNPC) revenantNPC.pulseManager.run(object : MovementPulse(revenantNPC, nextLoc, Pathfinder.SMART) { @@ -123,22 +309,15 @@ class RevenantController : TickListener, Commands { } }) } - - override fun assign(revenantNPC: RevenantNPC) { - taskTimeRemaining[revenantNPC] = RandomFunction.random(MAX_ROAM_TICKS) - } - - fun canMove(revenantNPC: RevenantNPC) : Boolean { - return !revenantNPC.walkingQueue.isMoving + private fun canMoveBasic(revenantNPC: RevenantNPC): Boolean { + return !revenantNPC.walkingQueue.isMoving && !revenantNPC.pulseManager.hasPulseRunning() && !revenantNPC.properties.combatPulse.isAttacking && !revenantNPC.properties.combatPulse.isInCombat } - fun getNextLocation(revenantNPC: RevenantNPC) : Location { - val nextX = RandomFunction.random(-revenantNPC.walkRadius, revenantNPC.walkRadius) - val nextY = RandomFunction.random(-revenantNPC.walkRadius, revenantNPC.walkRadius) - return revenantNPC.location.transform(nextX, nextY, 0) + override fun assign(revenantNPC: RevenantNPC) { + taskTimeRemaining[revenantNPC] = RandomFunction.random(MAX_ROAM_TICKS) } }, PATROLLING_ROUTE { @@ -148,7 +327,7 @@ class RevenantController : TickListener, Commands { if (canGroup(revenantNPC)) { addToPatrolGroup(revenantNPC) } else { - revenantNPC.setAttribute("route", routes.random()) + revenantNPC.setAttribute("route", getSuitableRoute(revenantNPC)) revenantNPC.setAttribute("routeidx", -1) } } @@ -158,7 +337,9 @@ class RevenantController : TickListener, Commands { groupPatrolQueue.add(revenantNPC) if (groupPatrolQueue.size == 3) { - val groupRoute = routes.random() + // Gets a route suitable for the largest NPC in the group + val largestNPC = groupPatrolQueue.maxByOrNull { it.size() } ?: revenantNPC + val groupRoute = getSuitableRoute(largestNPC) for (rev in groupPatrolQueue) { rev.setAttribute("route", groupRoute) rev.setAttribute("routeidx", -1) @@ -175,7 +356,12 @@ class RevenantController : TickListener, Commands { val route = revenantNPC.getAttribute>("route", null) val routeIdx = revenantNPC.getAttribute("routeidx", -1) - if (!canMove(revenantNPC)) return + if (checkIfStuck(revenantNPC)) { + handleStuckRevenant(revenantNPC) + return + } + + if (!canMoveAdvanced(revenantNPC)) return if (isGroup && route == null) { //if this is a grouped rev and we are waiting on more revs still taskTimeRemaining[revenantNPC] = 50 //just to make sure it doesn't time out roaming... @@ -198,7 +384,7 @@ class RevenantController : TickListener, Commands { revenantNPC.setAttribute("done", true) return } - val pathVariance = if (isGroup) 4 else 10 + val pathVariance = getPathVariance(revenantNPC, isGroup) val nextLoc = route[routeIdx].transform( RandomFunction.random(-pathVariance, pathVariance), RandomFunction.random(-pathVariance, pathVariance), @@ -212,9 +398,8 @@ class RevenantController : TickListener, Commands { revenantNPC.setAttribute("routeidx", routeIdx + 1) } } - - fun canMove(revenantNPC: RevenantNPC) : Boolean { - return !revenantNPC.walkingQueue.isMoving + private fun canMoveAdvanced(revenantNPC: RevenantNPC) : Boolean { + return !revenantNPC.walkingQueue.isMoving && !revenantNPC.pulseManager.hasPulseRunning() && !revenantNPC.properties.combatPulse.isAttacking && !revenantNPC.properties.combatPulse.isInCombat