package content.global.skill.cooking; import content.global.skill.skillcapeperks.SkillcapePerks; import core.game.event.ResourceProducedEvent; import core.game.node.entity.impl.Animator; import core.game.node.entity.player.Player; import core.game.node.entity.player.info.LogType; import core.game.node.entity.player.info.PlayerMonitor; import core.game.node.entity.player.link.audio.Audio; import core.game.node.entity.skill.Skills; import core.game.node.item.GroundItemManager; import core.game.node.item.Item; import core.game.node.scenery.Scenery; import core.game.system.task.Pulse; import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; import org.rs09.consts.Items; import org.rs09.consts.Sounds; import static core.api.ContentAPIKt.*; import content.data.Quests; public class StandardCookingPulse extends Pulse { //range animation private static final Animation RANGE_ANIMATION = new Animation(883, Animator.Priority.HIGH); //fire animation private static final Animation FIRE_ANIMATION = new Animation(897, Animator.Priority.HIGH); //Cooking sound public static final Audio SOUND = new Audio(2577, 1, 1); private static final int LUMBRIDGE_RANGE = 114; private final int initial; private final int product; private int amount; private final Scenery object; private final Player player; private double experience; private boolean burned = false; public CookableItems properties; private int initialAmount; private int processedAmount; public StandardCookingPulse(Player player, Scenery object, int initial, int product, int amount) { this.player = player; this.object = object; this.initial = initial; this.product = product; this.amount = amount; this.initialAmount = amountInInventory(player, initial); this.processedAmount = 0; } @Override public void start() { properties = CookableItems.forId(initial); if (checkRequirements()) { super.start(); cook(player, object, properties != null && burned, initial, product); amount--; } } @Override public boolean pulse() { if (amount < 1 || !checkRequirements()) { return true; } return reward(); } public void animate() { player.animate(getAnimation(object)); } public boolean checkRequirements() { this.experience = 0; if (properties != null) { // Handle Cook's Assistant range if (object.getId() == LUMBRIDGE_RANGE && !player.getQuestRepository().isComplete(Quests.COOKS_ASSISTANT)) { player.getPacketDispatch().sendMessage("You need to have completed the Cook's Assistant quest in order to use that range."); return false; } //check level if (player.getSkills().getLevel(Skills.COOKING) < properties.level) { player.getDialogueInterpreter().sendDialogue("You need a cooking level of " + properties.level + " to cook this."); return false; } this.experience = properties.experience; this.burned = isBurned(player, object, initial); } if (amount < 1) { return false; } return object.isActive(); } public boolean reward() { if (getDelay() == 1) { int delay = object.getName().toLowerCase().contains("range") ? 5 : 4; if (SkillcapePerks.isActive(SkillcapePerks.HASTY_COOKING, player)) { delay -= 1; } setDelay(delay); return false; } if (cook(player, object, burned, initial, product)) { amount--; } else { return true; } return amount < 1; } public boolean isBurned(final Player player, final Scenery object, int food) { boolean hasGauntlets = player.getEquipment().containsItem(new Item(Items.COOKING_GAUNTLETS_775)); int effectiveCookingLevel = player.getSkills().getLevel(Skills.COOKING); if (SkillcapePerks.isActive(SkillcapePerks.HASTY_COOKING, player)) { effectiveCookingLevel -= 5; } CookableItems item = CookableItems.forId(food); int low; int high; if (hasGauntlets && CookableItems.gauntletValues.containsKey(food)) { int[] successValues = CookableItems.gauntletValues.get(food); low = successValues[0]; high = successValues[1]; } else if (object.getId() == LUMBRIDGE_RANGE) { int[] successValues = CookableItems.lumbridgeRangeValues.getOrDefault(food, new int[]{item.lowRange, item.highRange}); low = successValues[0]; high = successValues[1]; } else { boolean isFire = object.getName().toLowerCase().contains("fire"); low = isFire ? item.low : item.lowRange; high = isFire ? item.high : item.highRange; } double host_ratio = RandomFunction.randomDouble(100.0); double client_ratio = RandomFunction.getSkillSuccessChance(low, high, effectiveCookingLevel); return host_ratio > client_ratio; } public boolean cook(final Player player, final Scenery object, final boolean burned, final int initial, final int product) { Item initialItem = new Item(initial); Item productItem = new Item(product); animate(); //handle special cooking results (spits, cake, etc) that don't justify separate plugin switch (initial) { case Items.SKEWERED_CHOMPY_7230: case Items.SKEWERED_RABBIT_7224: case Items.SKEWERED_BIRD_MEAT_9984: case Items.SKEWERED_BEAST_9992: case Items.IRON_SPIT_7225: if (RandomFunction.random(15) == 5) { player.getPacketDispatch().sendMessage("Your iron spit seems to have broken in the process."); } else { if (!player.getInventory().add(new Item(Items.IRON_SPIT_7225))) { GroundItemManager.create(new Item(Items.IRON_SPIT_7225), player.getLocation(), player); } } break; case Items.UNCOOKED_CAKE_1889: //cake if (!player.getInventory().add(new Item(Items.CAKE_TIN_1887))) { GroundItemManager.create(new Item(Items.CAKE_TIN_1887), player); } break; } if (player.getInventory().remove(initialItem)) { if (!burned) { player.getInventory().add(productItem); player.dispatch(new ResourceProducedEvent(productItem.getId(), 1, object, initialItem.getId())); player.getSkills().addExperience(Skills.COOKING, experience, true); processedAmount++; if (processedAmount > initialAmount) { PlayerMonitor.log(player, LogType.DUPE_ALERT, "cooked item (" + player.getName() + ", " + initialItem.getName() + "): initialAmount " + initialAmount + ", processedAmount " + processedAmount); } player.incrementAttribute("/save:stats_manager:food_cooked", 1); } else { player.dispatch(new ResourceProducedEvent(CookableItems.getBurnt(initial).getId(), 1, object, initialItem.getId())); player.getInventory().add(CookableItems.getBurnt(initial)); } player.getPacketDispatch().sendMessage(getMessage(initialItem, productItem, burned)); playAudio(player, Sounds.FRY_2577); return true; } return false; } public String getMessage(Item food, Item product, boolean burned) { if (food.getId() == Items.RAW_OOMLIE_2337) { return "The meat is far too delicate to cook like this. Perhaps you should wrap something around it to protect it from the heat."; } if (product.getId() == Items.SODA_ASH_1781) { return "You burn the seaweed into soda ash."; } if (product.getId() == Items.BARLEY_MALT_6008) { return null; // Both live branches of Jagexscape lack a message for this and I can't find period evidence of a message } if (CookableItems.intentionalBurn(food.getId())) { return "You deliberately burn the perfectly good piece of meat."; } if (!burned && food.getName().startsWith("Raw")) { return "You manage to cook some " + food.getName().replace("Raw ", "") + "."; } else if (burned && food.getName().startsWith("Raw")) { return "You accidentally burn some " + food.getName().replace("Raw ", "") + "."; } if (!burned && food.getName().startsWith(("Uncooked"))) { return "You manage to cook some " + food.getName().replace("Uncooked ", "") + "."; } else if (burned && food.getName().startsWith(("Uncooked"))) { return "You accidentally burn some " + food.getName().replace("Uncooked ", "") + "."; } return null; } private Animation getAnimation(final Scenery object) { return !object.getName().equalsIgnoreCase("fire") ? RANGE_ANIMATION : FIRE_ANIMATION; } }