Merge branch 2009scape:master into master

This commit is contained in:
Tooze 2026-06-03 16:44:46 +00:00
commit 86c8216ffa
83 changed files with 1643 additions and 4159 deletions

View file

@ -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",

View file

@ -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))),

View file

@ -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
}
}
}

View file

@ -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<Object> 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;
}
}

View file

@ -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
}
}
}

View file

@ -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<Object> 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;
}
}

View file

@ -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<Object> 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<Integer> 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;
}
}

View file

@ -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<Object> 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;
}
}

View file

@ -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
}
}
}

View file

@ -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<Object> 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;
}
}
}

View file

@ -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
}
}
}

View file

@ -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<Object> 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;
}
}

View file

@ -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
}
}
}

View file

@ -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<Object> 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;
}
}

View file

@ -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
)
}
}
}

View file

@ -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
)
}
}
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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;
}
}

View file

@ -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
)
}
}
}

View file

@ -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<Int, PieProduct>()
init {
for (pie in PieProduct.values()) {
productMap[pie.base] = pie
}
}
}
}
}

View file

@ -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
)
}
}
}

View file

@ -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<Int, PizzaProduct>()
init {
for (pizza in PizzaProduct.values()) {
productMap[pizza.base] = pizza
}
}
}
}
}

View file

@ -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<Int, PotatoProduct>()
init {
for (topping in PotatoProduct.values()) {
productMap[topping.added] = topping
}
}
}
}
}

View file

@ -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 <code>True</code> 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);
}
}
}
}
}

View file

@ -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<Int, StewProduct>()
init {
for (stew in StewProduct.values()) {
productMap[stew.base] = stew
}
}
}
}
}

View file

@ -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<Int, ToppingProduct>()
init {
for (topping in ToppingProduct.values()) {
productMap[topping.base] = topping
}
}
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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 };
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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.";
}
}

View file

@ -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;
}
}

View file

@ -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 };
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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 };
}
}

View file

@ -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.";
}
}

View file

@ -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;
}
}

View file

@ -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 <code>True</code> 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();
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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[] {};
}
}

View file

@ -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<RevenantNPC>()
// Movement tracking for stuck detection
private val movementStartTick = HashMap<RevenantNPC, Int>()
private val lastKnownLocation = HashMap<RevenantNPC, Location>()
private val failedAttempts = HashMap<RevenantNPC, Int>()
// 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<Int, Int>): Array<Location> =
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<Location> {
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<Array<Location>>("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

View file

@ -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();

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -1,271 +0,0 @@
package core.cache.crypto;
/**
* <p> An implementation of an ISAAC cipher. See <a
* href="http://en.wikipedia.org/wiki/ISAAC_(cipher)">
* http://en.wikipedia.org/wiki/ISAAC_(cipher)</a> for more information. </p>
* <p> This implementation is based on the one written by Bob Jenkins, which is
* available at <a href="http://www.burtleburtle.net/bob/java/rand/Rand.java">
* http://www.burtleburtle.net/bob/java/rand/Rand.java</a>. </p>
* @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;
}
}

View file

@ -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
}
}

View file

@ -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;
}
}

View file

@ -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
)

View file

@ -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));
}
}
}

View file

@ -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()
}
}
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,7 @@
package core.cache.misc
data class Container(
var version: Int = -1,
var crc: Int = -1,
var nameHash: Int = -1
)

View file

@ -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;
}
}

View file

@ -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<FilesContainer?> = 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<ByteArray?>? = 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<Container>(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
}
}
}

View file

@ -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;
}
}

View file

@ -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<Container?>? = null
)

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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.
*/
}
}

View file

@ -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
}
}

View file

@ -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()
}
}
}
}