From 1d12dd741f7431b5eac781f451521da6b87f6187 Mon Sep 17 00:00:00 2001 From: zsrv Date: Wed, 14 Feb 2024 11:33:13 +0000 Subject: [PATCH] Implemented auto splitting of excessively long dialogue lines Many new farming-related player messages added, and some existing messages updated Raking animation updated Herb picking animation updated Digging up farming patch animation updated Plant cure animation updated A scarecrow can be retrieved from a flower patch by digging it up with a spade Picking fruit/berries stops when running out of inventory space The player can no longer dig up a tree they have planted before chopping it down --- .../global/skill/farming/CompostBin.kt | 6 +- .../skill/farming/CompostBinOptionHandler.kt | 15 +- .../global/skill/farming/CompostType.kt | 4 +- .../global/skill/farming/CropHarvester.kt | 64 ++-- .../skill/farming/DigUpPatchDialogue.kt | 63 ++-- .../global/skill/farming/FarmingPatch.kt | 71 +++-- .../skill/farming/FruitAndBerryPicker.kt | 32 +- .../global/skill/farming/HealthChecker.kt | 32 +- .../global/skill/farming/InspectionHandler.kt | 52 ++-- .../content/global/skill/farming/Patch.kt | 65 ++-- .../global/skill/farming/PatchRaker.kt | 34 ++- .../content/global/skill/farming/PatchType.kt | 27 +- .../content/global/skill/farming/Plantable.kt | 104 +++---- .../global/skill/farming/SeedOnPlantPot.kt | 8 +- .../skill/farming/ToolLeprechaunInterface.kt | 289 +++++++++--------- .../global/skill/farming/UseWithBinHandler.kt | 49 ++- .../skill/farming/UseWithPatchHandler.kt | 260 ++++++++++------ .../global/skill/farming/timers/CropGrowth.kt | 7 +- .../skill/magic/lunar/LunarListeners.kt | 4 +- .../skill/skillcapeperks/SkillcapePerks.kt | 3 +- .../skill/summoning/familiar/GiantEntNPC.java | 8 +- Server/src/main/core/api/ContentAPI.kt | 7 +- Server/src/main/core/api/DialUtils.kt | 44 ++- 23 files changed, 728 insertions(+), 520 deletions(-) diff --git a/Server/src/main/content/global/skill/farming/CompostBin.kt b/Server/src/main/content/global/skill/farming/CompostBin.kt index b8581d5e3..617e800db 100644 --- a/Server/src/main/content/global/skill/farming/CompostBin.kt +++ b/Server/src/main/content/global/skill/farming/CompostBin.kt @@ -2,7 +2,6 @@ package content.global.skill.farming import core.api.* import core.game.node.entity.player.Player -import core.game.node.entity.player.link.audio.Audio import core.game.node.entity.skill.Skills import core.game.node.item.Item import core.tools.RandomFunction @@ -26,14 +25,19 @@ class CompostBin(val player: Player, val bin: CompostBins) { fun close() { isClosed = true + sendMessage(player, "You close the compost bin.") + // TODO: Add animation - https://youtu.be/B50dwm8fdcQ?t=225 https://youtu.be/BHYgNDLx0s4?t=488 playAudio(player, Sounds.COMPOST_CLOSE_2428) + sendMessage(player, "The contents have begun to rot.") finishedTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(RandomFunction.random(35,50).toLong()) updateBit() } fun open(){ isClosed = false + // TODO: Add animation playAudio(player, Sounds.COMPOST_OPEN_2429) + sendMessage(player, "You open the compost bin.") updateBit() } diff --git a/Server/src/main/content/global/skill/farming/CompostBinOptionHandler.kt b/Server/src/main/content/global/skill/farming/CompostBinOptionHandler.kt index 88ff95986..a8a0b182f 100644 --- a/Server/src/main/content/global/skill/farming/CompostBinOptionHandler.kt +++ b/Server/src/main/content/global/skill/farming/CompostBinOptionHandler.kt @@ -1,5 +1,6 @@ package content.global.skill.farming +import core.api.* import core.cache.def.impl.SceneryDefinition import core.game.interaction.OptionHandler import core.game.node.Node @@ -10,7 +11,7 @@ import core.plugin.Plugin @Initializable class CompostBinOptionHandler : OptionHandler() { override fun newInstance(arg: Any?): Plugin { - for(i in 7836..7839) + for (i in 7836..7839) SceneryDefinition.forId(i).childrenIds.forEach { val def = SceneryDefinition.forId(it) def.handlers["option:open"] = this @@ -26,15 +27,15 @@ class CompostBinOptionHandler : OptionHandler() { val cBin = CompostBins.forObject(node.asScenery()) ?: return false val bin = cBin.getBinForPlayer(player) - when(option){ - "close" -> if(!bin.isFull()) player.sendMessage("This shouldn't be happening. Report this.") else bin.close() - "open" -> if(!bin.isFinished) player.sendMessage("I should probably wait until it is done to open it.") else bin.open() + when (option) { + "close" -> if (!bin.isFull()) sendMessage(player, "This shouldn't be happening. Report this.") else bin.close() + "open" -> if (!bin.isFinished) sendMessage(player, "I should probably wait until it is done to open it.") else bin.open() "take-tomato" -> { if (!bin.isTomatoes || !bin.isFinished) { - player.sendMessage("This shouldn't be happening. Report this.") + sendMessage(player, "This shouldn't be happening. Report this.") } else { - if(player.inventory.isFull){ - player.sendMessage("You don't have enough inventory space to do this.") + if (player.inventory.isFull) { + sendMessage(player, "You don't have enough inventory space to do this.") } else { val reward = bin.takeItem() if (reward != null) diff --git a/Server/src/main/content/global/skill/farming/CompostType.kt b/Server/src/main/content/global/skill/farming/CompostType.kt index 5d19c40c2..01e34dbad 100644 --- a/Server/src/main/content/global/skill/farming/CompostType.kt +++ b/Server/src/main/content/global/skill/farming/CompostType.kt @@ -2,6 +2,6 @@ package content.global.skill.farming enum class CompostType { NONE, - NORMAL, - SUPER + COMPOST, + SUPERCOMPOST } \ No newline at end of file diff --git a/Server/src/main/content/global/skill/farming/CropHarvester.kt b/Server/src/main/content/global/skill/farming/CropHarvester.kt index 4e0366e24..779609bf8 100644 --- a/Server/src/main/content/global/skill/farming/CropHarvester.kt +++ b/Server/src/main/content/global/skill/farming/CropHarvester.kt @@ -15,14 +15,14 @@ import core.plugin.Plugin import org.rs09.consts.Items import org.rs09.consts.Sounds -val livesBased = arrayOf(PatchType.HERB, PatchType.CACTUS, PatchType.BELLADONNA, PatchType.HOPS, PatchType.ALLOTMENT,PatchType.EVIL_TURNIP) +val livesBased = arrayOf(PatchType.HERB_PATCH, PatchType.CACTUS_PATCH, PatchType.BELLADONNA_PATCH, PatchType.HOPS_PATCH, PatchType.ALLOTMENT, PatchType.EVIL_TURNIP_PATCH) @Initializable class CropHarvester : OptionHandler() { override fun newInstance(arg: Any?): Plugin { - SceneryDefinition.setOptionHandler("harvest",this) - SceneryDefinition.setOptionHandler("pick",this) + SceneryDefinition.setOptionHandler("harvest", this) + SceneryDefinition.setOptionHandler("pick", this) return this } @@ -34,62 +34,71 @@ class CropHarvester : OptionHandler() { val fPatch = FarmingPatch.forObject(node.asScenery()) fPatch ?: return null val patch = fPatch.getPatchFor(player) + val patchName = patch.patch.type.displayName() val plantable = patch.plantable plantable ?: return null + var firstHarvest = true return object : Pulse(0) { override fun pulse(): Boolean { var reward = Item(crop) val familiar = player.familiarManager.familiar - if(familiar != null && familiar is GiantEntNPC) { + if (familiar != null && familiar is GiantEntNPC) { familiar.modifyFarmingReward(fPatch, reward) } - if(!player.inventory.hasSpaceFor(reward)){ - player.sendMessage("You don't have enough inventory space for that.") + if (!hasSpaceFor(player, reward)) { + sendMessage(player, "You have run out of inventory space.") return true } - var requiredItem = when(fPatch.type){ - PatchType.HERB, PatchType.TREE -> Items.SECATEURS_5329 + var requiredItem = when (fPatch.type) { + PatchType.TREE_PATCH -> Items.SECATEURS_5329 else -> Items.SPADE_952 } - if(requiredItem == Items.SECATEURS_5329){ - if(player.inventory.containsAtLeastOneItem(Items.MAGIC_SECATEURS_7409)){ + if (requiredItem == Items.SECATEURS_5329) { + if (inInventory(player, Items.MAGIC_SECATEURS_7409)) { requiredItem = Items.MAGIC_SECATEURS_7409 } } - val anim = when(requiredItem){ - Items.SPADE_952 -> Animation(830) - Items.SECATEURS_5329 -> if (fPatch.type == PatchType.TREE) Animation(2277) else Animation(7227) - Items.MAGIC_SECATEURS_7409 -> if (fPatch.type == PatchType.TREE) Animation(3340) else Animation(7228) + val anim = when (requiredItem) { + Items.SPADE_952 -> if (fPatch.type == PatchType.HERB_PATCH) Animation(2282) else Animation(830) + Items.SECATEURS_5329 -> if (fPatch.type == PatchType.TREE_PATCH) Animation(2277) else Animation(7227) + Items.MAGIC_SECATEURS_7409 -> if (fPatch.type == PatchType.TREE_PATCH) Animation(3340) else Animation(7228) else -> Animation(0) } - val sound = when(requiredItem){ + val sound = when (requiredItem) { Items.SPADE_952 -> Sounds.DIGSPADE_1470 Items.SECATEURS_5329 -> Sounds.FARMING_PICK_2437 Items.MAGIC_SECATEURS_7409 -> Sounds.FARMING_PICK_2437 else -> 0 } - if(!player.inventory.containsItem(Item(requiredItem))){ - player.sendMessage("You lack the needed tool to harvest these crops.") + if (!inInventory(player, requiredItem)) { + sendMessage(player, "You lack the needed tool to harvest these crops.") return true } - player.animator.animate(anim) + if (firstHarvest) { + sendMessage(player, "You begin to harvest the $patchName.") + firstHarvest = false + } + animate(player, anim) playAudio(player, sound) delay = 2 - player.inventory.add(reward) - player.skills.addExperience(Skills.FARMING,plantable.harvestXP) - if(patch.patch.type in livesBased){ + addItem(player, reward.id) + rewardXP(player, Skills.FARMING, plantable.harvestXP) + if (patch.patch.type in livesBased) { patch.rollLivesDecrement( getDynLevel(player, Skills.FARMING), requiredItem == Items.MAGIC_SECATEURS_7409 ) } else { patch.harvestAmt-- - if(patch.harvestAmt <= 0 && crop == plantable.harvestItem){ + if (patch.harvestAmt <= 0 && crop == plantable.harvestItem) { patch.clear() } } + if (patch.cropLives <= 0 || patch.harvestAmt <= 0) { + sendMessage(player, "The $patchName is now empty.") + } return patch.cropLives <= 0 || patch.harvestAmt <= 0 } } @@ -105,13 +114,18 @@ class CropHarvester : OptionHandler() { val plantable = patch.plantable plantable ?: return false - if(patch.isWeedy()){ - player.sendMessage("Something seems to have gone wrong here. Report this.") + if (patch.isWeedy() || patch.isEmptyAndWeeded()) { + sendMessage(player, "Something seems to have gone wrong here. Report this.") + return true + } + + if (!hasSpaceFor(player, Item(plantable.harvestItem))) { + sendMessage(player, "You don't have enough inventory space to do that.") return true } val pulse = harvestPulse(player, node, plantable.harvestItem) ?: return false - player.pulseManager.run(pulse) + submitIndividualPulse(player, pulse) return true } diff --git a/Server/src/main/content/global/skill/farming/DigUpPatchDialogue.kt b/Server/src/main/content/global/skill/farming/DigUpPatchDialogue.kt index c1f2666ff..21a773c20 100644 --- a/Server/src/main/content/global/skill/farming/DigUpPatchDialogue.kt +++ b/Server/src/main/content/global/skill/farming/DigUpPatchDialogue.kt @@ -1,13 +1,9 @@ package content.global.skill.farming -import core.api.playAudio +import core.api.* import core.game.dialogue.DialoguePlugin +import core.game.interaction.QueueStrength import core.game.node.entity.player.Player -import core.game.node.entity.player.link.audio.Audio -import core.game.node.item.GroundItemManager -import core.game.node.item.Item -import core.game.system.task.Pulse -import core.game.world.update.flag.context.Animation import core.plugin.Initializable import org.rs09.consts.Sounds @@ -21,36 +17,59 @@ class DigUpPatchDialogue(player: Player? = null) : DialoguePlugin(player) { override fun open(vararg args: Any?): Boolean { patch = args[0] as Patch - if(patch?.isWeedy() == true){ - player.dialogueInterpreter.sendDialogue("Use a rake to get rid of weeds.") + if (patch?.isWeedy() == true || patch?.isEmptyAndWeeded() == true) { + sendDialogue(player, "There aren't any crops in this patch to dig up.") stage = 1000 return true } - player.dialogueInterpreter.sendOptions("Dig up this patch?","Yes","No") + if (patch?.patch?.type == PatchType.TREE_PATCH) { + val isTreeStump = patch?.getCurrentState() == patch?.plantable!!.value + patch?.plantable!!.stages + 2 + if (!isTreeStump) { + sendMessage(player, "You need to chop this tree down first.") // this message is not authentic + stage = 1000 + return true + } + } + sendDialogueOptions(player, "Are you sure you want to dig up this patch?", "Yes, I want to clear it for new crops.", "No, I want to leave it as it is.") stage = 0 return true } override fun handle(interfaceId: Int, buttonId: Int): Boolean { - when(stage){ - 0 -> when(buttonId){ + when (stage) { + 0 -> when (buttonId) { 1 -> { end() - player.animator.animate(Animation(830)) - playAudio(player, Sounds.DIGSPADE_1470) - player.pulseManager.run(object : Pulse(){ - override fun pulse(): Boolean { - if(patch?.patch?.type == PatchType.TREE){ - if(patch?.getCurrentState() == (patch?.plantable?.value ?: 0) + (patch?.plantable?.stages ?: 0) + 2 && patch?.isWeedy() != true){ - if(!player.inventory.add(Item(patch?.plantable?.harvestItem ?: 0))){ - GroundItemManager.create(Item(patch?.plantable?.harvestItem ?: 0),player) + val anim = getAnimation(830) + sendMessage(player, "You start digging the farming patch...") + queueScript(player, 0, QueueStrength.WEAK) { stage: Int -> + when (stage) { + 0 -> { + animate(player, anim) + playAudio(player, Sounds.DIGSPADE_1470) + return@queueScript delayScript(player,anim.duration + 2) + } + 1 -> { + animate(player, anim) + playAudio(player, Sounds.DIGSPADE_1470) + return@queueScript delayScript(player, anim.duration + 1) + } + 2 -> { + if (patch?.patch?.type == PatchType.TREE_PATCH) { + if (patch?.getCurrentState() == (patch?.plantable?.value ?: 0) + (patch?.plantable?.stages ?: 0) + 2 && patch?.isWeedy() != true && patch?.isEmptyAndWeeded() != true) { + addItemOrDrop(player, patch?.plantable?.harvestItem ?: 0) } } + if (patch?.plantable == Plantable.SCARECROW) { + addItemOrDrop(player, patch?.plantable?.harvestItem ?: 0) + } + patch?.clear() + sendMessage(player, "You have successfully cleared this patch for new crops.") + return@queueScript stopExecuting(player) } - patch?.clear() - return true + else -> return@queueScript stopExecuting(player) } - }) + } } else -> end() } diff --git a/Server/src/main/content/global/skill/farming/FarmingPatch.kt b/Server/src/main/content/global/skill/farming/FarmingPatch.kt index f241b338b..c322e4de8 100644 --- a/Server/src/main/content/global/skill/farming/FarmingPatch.kt +++ b/Server/src/main/content/global/skill/farming/FarmingPatch.kt @@ -2,7 +2,6 @@ package content.global.skill.farming import core.api.* import core.cache.def.impl.SceneryDefinition -import core.cache.def.impl.VarbitDefinition import core.game.node.scenery.Scenery import core.game.node.entity.player.Player import content.global.skill.farming.timers.CropGrowth @@ -20,55 +19,55 @@ enum class FarmingPatch(val varbit: Int, val type: PatchType) { HARMONY_ISLAND_ALLOTMENT(3402,PatchType.ALLOTMENT), //Herb - CATHERBY_HERB_CE(781,PatchType.HERB), - S_FALADOR_HERB_NE(780,PatchType.HERB), - ARDOUGNE_HERB_CE(782,PatchType.HERB), - PORT_PHAS_HERB_NE(783,PatchType.HERB), - TROLL_STRONGHOLD_HERB(2788,PatchType.HERB), + CATHERBY_HERB_CE(781,PatchType.HERB_PATCH), + S_FALADOR_HERB_NE(780,PatchType.HERB_PATCH), + ARDOUGNE_HERB_CE(782,PatchType.HERB_PATCH), + PORT_PHAS_HERB_NE(783,PatchType.HERB_PATCH), + TROLL_STRONGHOLD_HERB(2788,PatchType.HERB_PATCH), //Flower - S_FALADOR_FLOWER_C(728,PatchType.FLOWER), - CATHERBY_FLOWER_C(729,PatchType.FLOWER), - ARDOUGNE_FLOWER_C(730,PatchType.FLOWER), - PORT_PHAS_FLOWER_C(731,PatchType.FLOWER), - WILDERNESS_FLOWER(5067,PatchType.FLOWER), + S_FALADOR_FLOWER_C(728,PatchType.FLOWER_PATCH), + CATHERBY_FLOWER_C(729,PatchType.FLOWER_PATCH), + ARDOUGNE_FLOWER_C(730,PatchType.FLOWER_PATCH), + PORT_PHAS_FLOWER_C(731,PatchType.FLOWER_PATCH), + WILDERNESS_FLOWER(5067,PatchType.FLOWER_PATCH), //Tree - N_FALADOR_TREE(701,PatchType.TREE), - TAVERLY_TREE(700,PatchType.TREE), - GNOME_STRONGHOLD_TREE(2953,PatchType.TREE), - LUMBRIDGE_TREE(703,PatchType.TREE), - VARROCK_TREE(702,PatchType.TREE), + N_FALADOR_TREE(701,PatchType.TREE_PATCH), + TAVERLY_TREE(700,PatchType.TREE_PATCH), + GNOME_STRONGHOLD_TREE(2953,PatchType.TREE_PATCH), + LUMBRIDGE_TREE(703,PatchType.TREE_PATCH), + VARROCK_TREE(702,PatchType.TREE_PATCH), //Fruit Tree - GNOME_STRONGHOLD_FRUIT_TREE(704,PatchType.FRUIT_TREE), - CATHERBY_FRUIT_TREE(707,PatchType.FRUIT_TREE), - TREE_GNOME_VILLAGE_FRUIT_TREE(705,PatchType.FRUIT_TREE), - BRIMHAVEN_FRUIT_TREE(706,PatchType.FRUIT_TREE), - LLETYA_FRUIT_TREE(4317,PatchType.FRUIT_TREE), + GNOME_STRONGHOLD_FRUIT_TREE(704,PatchType.FRUIT_TREE_PATCH), + CATHERBY_FRUIT_TREE(707,PatchType.FRUIT_TREE_PATCH), + TREE_GNOME_VILLAGE_FRUIT_TREE(705,PatchType.FRUIT_TREE_PATCH), + BRIMHAVEN_FRUIT_TREE(706,PatchType.FRUIT_TREE_PATCH), + LLETYA_FRUIT_TREE(4317,PatchType.FRUIT_TREE_PATCH), //Hops - ENTRANA_HOPS(717,PatchType.HOPS), - LUMBRIDGE_HOPS(718,PatchType.HOPS), - MCGRUBOR_HOPS(719,PatchType.HOPS), - YANILLE_HOPS(716,PatchType.HOPS), + ENTRANA_HOPS(717,PatchType.HOPS_PATCH), + LUMBRIDGE_HOPS(718,PatchType.HOPS_PATCH), + MCGRUBOR_HOPS(719,PatchType.HOPS_PATCH), + YANILLE_HOPS(716,PatchType.HOPS_PATCH), //Bushes - CHAMPIONS_GUILD_BUSH(732,PatchType.BUSH), - RIMMINGTON_BUSH(733,PatchType.BUSH), - ARDOUGNE_BUSH(735,PatchType.BUSH), - ETCETERIA_BUSH(734,PatchType.BUSH), + CHAMPIONS_GUILD_BUSH(732,PatchType.BUSH_PATCH), + RIMMINGTON_BUSH(733,PatchType.BUSH_PATCH), + ARDOUGNE_BUSH(735,PatchType.BUSH_PATCH), + ETCETERIA_BUSH(734,PatchType.BUSH_PATCH), //Spirit Tree - ETCETERIA_SPIRIT_TREE(722,PatchType.SPIRIT_TREE), - PORT_SARIM_SPIRIT_TREE(720,PatchType.SPIRIT_TREE), - KARAMJA_SPIRIT_TREE(724,PatchType.SPIRIT_TREE), + ETCETERIA_SPIRIT_TREE(722,PatchType.SPIRIT_TREE_PATCH), + PORT_SARIM_SPIRIT_TREE(720,PatchType.SPIRIT_TREE_PATCH), + KARAMJA_SPIRIT_TREE(724,PatchType.SPIRIT_TREE_PATCH), //Other - DRAYNOR_BELLADONNA(748, PatchType.BELLADONNA), - CANIFIS_MUSHROOM(746, PatchType.MUSHROOM), - ALKHARID_CACTUS(744, PatchType.CACTUS), - EVIL_TURNIP(4291, PatchType.EVIL_TURNIP); + DRAYNOR_BELLADONNA(748, PatchType.BELLADONNA_PATCH), + CANIFIS_MUSHROOM(746, PatchType.MUSHROOM_PATCH), + ALKHARID_CACTUS(744, PatchType.CACTUS_PATCH), + EVIL_TURNIP(4291, PatchType.EVIL_TURNIP_PATCH); companion object { diff --git a/Server/src/main/content/global/skill/farming/FruitAndBerryPicker.kt b/Server/src/main/content/global/skill/farming/FruitAndBerryPicker.kt index 5c420a348..f07689362 100644 --- a/Server/src/main/content/global/skill/farming/FruitAndBerryPicker.kt +++ b/Server/src/main/content/global/skill/farming/FruitAndBerryPicker.kt @@ -45,35 +45,47 @@ class FruitAndBerryPicker : OptionHandler() { val animation = Animation(2281) - if(patch.getFruitOrBerryCount() <= 0){ - player.sendMessage("This shouldn't be happening. Please report this.") + if (patch.getFruitOrBerryCount() <= 0) { + sendMessage(player, "This shouldn't be happening. Please report this.") return true } - if(!player.inventory.hasSpaceFor(Item(plantable.harvestItem))){ - player.sendMessage("You do not have enough inventory space for this.") + if (!hasSpaceFor(player, Item(plantable.harvestItem))) { + sendMessage(player, "You don't have enough inventory space to do that.") return true } - if(System.currentTimeMillis() - patch.nextGrowth > TimeUnit.MINUTES.toMillis(45)){ + if (System.currentTimeMillis() - patch.nextGrowth > TimeUnit.MINUTES.toMillis(45)) { patch.nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(45) } - player.pulseManager.run(object : Pulse(animation.duration){ + submitIndividualPulse(player, object : Pulse(animation.duration) { override fun pulse(): Boolean { val reward = Item(plantable.harvestItem, 1) + if (!hasSpaceFor(player, reward)) { + sendMessage(player, "You have run out of inventory space.") + return true + } + val familiar = player.familiarManager.familiar - if(familiar != null && familiar is GiantEntNPC) { + if (familiar != null && familiar is GiantEntNPC) { familiar.modifyFarmingReward(fPatch, reward) } - player.animator.animate(animation) + animate(player, animation) playAudio(player, Sounds.FARMING_PICK_2437) - addItemOrDrop(player,reward.id,reward.amount) - player.skills.addExperience(Skills.FARMING,plantable.harvestXP) + addItemOrDrop(player, reward.id, reward.amount) + rewardXP(player, Skills.FARMING, plantable.harvestXP) patch.setCurrentState(patch.getCurrentState() - 1) + if (patch.patch.type == PatchType.CACTUS_PATCH) { + sendMessage(player, "You carefully pick a spine from the cactus.") + } else { + val determiner = if (patch.patch.type == PatchType.BUSH_PATCH) "some" else "a" + sendMessage(player, "You pick $determiner ${reward.name.lowercase()}.") + } + return patch.getFruitOrBerryCount() == 0 } }) diff --git a/Server/src/main/content/global/skill/farming/HealthChecker.kt b/Server/src/main/content/global/skill/farming/HealthChecker.kt index cd4498f48..43d0e24d9 100644 --- a/Server/src/main/content/global/skill/farming/HealthChecker.kt +++ b/Server/src/main/content/global/skill/farming/HealthChecker.kt @@ -1,21 +1,20 @@ package content.global.skill.farming -import core.api.log +import core.api.* import core.cache.def.impl.SceneryDefinition import core.game.interaction.OptionHandler import core.game.node.Node import core.game.node.entity.player.Player import core.game.node.entity.skill.Skills -import core.tools.SystemLogger import core.plugin.Initializable import core.plugin.Plugin import core.tools.Log import java.util.concurrent.TimeUnit @Initializable -class HealthChecker : OptionHandler(){ +class HealthChecker : OptionHandler() { override fun newInstance(arg: Any?): Plugin { - SceneryDefinition.setOptionHandler("check-health",this) + SceneryDefinition.setOptionHandler("check-health", this) return this } @@ -27,24 +26,27 @@ class HealthChecker : OptionHandler(){ val patch = fPatch.getPatchFor(player) val type = patch.patch.type - if(type != PatchType.BUSH && type != PatchType.FRUIT_TREE && type != PatchType.TREE && type != PatchType.CACTUS){ - player.sendMessage("This shouldn't be happening. Please report this.") + if (type != PatchType.BUSH_PATCH && type != PatchType.FRUIT_TREE_PATCH && type != PatchType.TREE_PATCH && type != PatchType.CACTUS_PATCH) { + sendMessage(player, "This shouldn't be happening. Please report this.") return true } - if(!patch.isCheckHealth) return true + if (!patch.isCheckHealth) return true - player.skills.addExperience(Skills.FARMING,patch.plantable?.checkHealthXP ?: 0.0) + rewardXP(player, Skills.FARMING, patch.plantable?.checkHealthXP ?: 0.0) patch.isCheckHealth = false - when(type){ - PatchType.TREE -> patch.setCurrentState(patch.getCurrentState() + 1) - PatchType.FRUIT_TREE -> patch.setCurrentState(patch.getCurrentState() - 14) - PatchType.BUSH -> patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 4) - PatchType.CACTUS -> patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 3) - else -> log(this::class.java, Log.ERR, "Unreachable patch type from when(type) switch in HealthChecker.kt line 36") + when (type) { + PatchType.TREE_PATCH -> patch.setCurrentState(patch.getCurrentState() + 1) + PatchType.FRUIT_TREE_PATCH -> patch.setCurrentState(patch.getCurrentState() - 14) + PatchType.BUSH_PATCH -> { + sendMessage(player, "You examine the bush for signs of disease and find that it's in perfect health.") + patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 4) + } + PatchType.CACTUS_PATCH -> patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 3) + else -> log(this::class.java, Log.ERR, "Unreachable patch type from when(type) switch in HealthChecker.kt") } - if(type == PatchType.FRUIT_TREE){ + if (type == PatchType.FRUIT_TREE_PATCH) { patch.nextGrowth = TimeUnit.MINUTES.toMillis(45) } diff --git a/Server/src/main/content/global/skill/farming/InspectionHandler.kt b/Server/src/main/content/global/skill/farming/InspectionHandler.kt index 661cd23cf..00a30a5d2 100644 --- a/Server/src/main/content/global/skill/farming/InspectionHandler.kt +++ b/Server/src/main/content/global/skill/farming/InspectionHandler.kt @@ -1,16 +1,18 @@ package content.global.skill.farming +import core.api.* import core.cache.def.impl.SceneryDefinition import core.game.interaction.OptionHandler import core.game.node.Node import core.game.node.entity.player.Player import core.plugin.Initializable import core.plugin.Plugin +import core.tools.prependArticle @Initializable class InspectionHandler : OptionHandler() { override fun newInstance(arg: Any?): Plugin { - SceneryDefinition.setOptionHandler("inspect",this) + SceneryDefinition.setOptionHandler("inspect", this) return this } @@ -18,27 +20,35 @@ class InspectionHandler : OptionHandler() { node ?: return false player ?: return false val patch = FarmingPatch.forObject(node.asScenery()) - if(patch == null){ - player.sendMessage("This is an improperly handled inspect option. Report this please.") - } else { - val p = patch.getPatchFor(player) - val status1 = if(p.getCurrentState() <= 2) "This patch needs weeding." else if(p.getCurrentState() == 3) "This patch is weed-free." else { - if(p.isDiseased && !p.isDead) "This patch has become diseased." - else if(p.isDead) "The crops in this patch are dead." - else if(p.plantable == Plantable.SCARECROW) "There is a scarecrow in this patch." - else "This patch has something growing in it." - } - val status2 = if(patch.type == PatchType.ALLOTMENT || patch.type == PatchType.FLOWER || patch.type == PatchType.HOPS){ - if(p.isWatered) { - "This patch has been watered." - } else if(p.getCurrentState() > 3 && !p.isGrown() && !p.isDead && !p.isDiseased) { - "This patch could use some water." - } else "" - } else "" - val status3 = if(p.compost == CompostType.NONE) "This patch has not been treated." else "This patch has been treated with ${p.compost.name.toLowerCase()} compost." - player.sendMessage("$status1 $status2") - player.sendMessage(status3) + if (patch == null) { + sendMessage(player, "This is an improperly handled inspect option. Report this please.") + return true } + + val p = patch.getPatchFor(player) + val patchName = p.patch.type.displayName() + + val statusPatchType = if (patch == FarmingPatch.TROLL_STRONGHOLD_HERB) "This is a very special herb patch." + else "This is ${prependArticle(patchName)}." + + val statusCompost = if (p.compost == CompostType.NONE) "The soil has not been treated." + else "The soil has been treated with ${p.compost.name.lowercase()}." + + val statusStage = if (p.plantable == Plantable.SCARECROW) "" + else if (p.isWeedy()) "The patch needs weeding." + else if (p.isEmptyAndWeeded()) "The patch is empty and weeded." + else if (p.isDiseased && !p.isDead) "The patch is diseased and needs attending to before it dies." + else if (p.isDead) "The patch has become infected by disease and has died." + else if (p.isGrown()) "The patch is fully grown." + else "The patch has something growing in it." + + val statusGardener = if (patch == FarmingPatch.TROLL_STRONGHOLD_HERB) "My Arm will look after this patch for you." + else if (p.protectionPaid) "A nearby gardener is looking after this patch for you." + else "" + + sendMessage(player, "$statusPatchType $statusCompost $statusStage".trim()) + if (statusGardener != "") sendMessage(player, statusGardener) + return true } diff --git a/Server/src/main/content/global/skill/farming/Patch.kt b/Server/src/main/content/global/skill/farming/Patch.kt index 6b03a2017..486f1d5bf 100644 --- a/Server/src/main/content/global/skill/farming/Patch.kt +++ b/Server/src/main/content/global/skill/farming/Patch.kt @@ -5,7 +5,6 @@ import core.game.node.entity.player.Player import core.tools.Log import core.tools.RandomFunction import org.rs09.consts.Items -import core.tools.SystemLogger import java.util.concurrent.TimeUnit import kotlin.math.ceil import kotlin.math.min @@ -21,8 +20,8 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl fun setNewHarvestAmount() { val compostMod = when(compost) { CompostType.NONE -> 0 - CompostType.NORMAL -> 1 - CompostType.SUPER -> 2 + CompostType.COMPOST -> 1 + CompostType.SUPERCOMPOST -> 2 } harvestAmt = when (plantable) { Plantable.LIMPWURT_SEED, Plantable.WOAD_SEED -> 3 @@ -30,14 +29,14 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl Plantable.WILLOW_SAPLING -> 0 else -> 1 } - if(plantable != null && plantable?.applicablePatch != PatchType.FLOWER) { + if(plantable != null && plantable?.applicablePatch != PatchType.FLOWER_PATCH) { harvestAmt += compostMod } cropLives = 3 + compostMod } fun rollLivesDecrement(farmingLevel: Int, magicSecateurs: Boolean){ - if(patch.type == PatchType.HERB){ + if(patch.type == PatchType.HERB_PATCH){ //authentic formula thanks to released data. var herbSaveLow = when(plantable){ Plantable.GUAM_SEED -> min(24 + farmingLevel, 80) @@ -70,10 +69,10 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl //inauthentic formulae based on reported averages due to lack of formula var chance = when(patch.type){ PatchType.ALLOTMENT -> 8 //average of 8 per life times 3 lives = average 24 - PatchType.HOPS -> 6 //average of 6 per life times 3 lives = 18 - PatchType.BELLADONNA -> 2 //average of 2 per life times 3 lives = 6 - PatchType.EVIL_TURNIP -> 2 //average 2 per, same as BELLADONNA - PatchType.CACTUS -> 3 //average of 3 per life times 3 lives = 9 + PatchType.HOPS_PATCH -> 6 //average of 6 per life times 3 lives = 18 + PatchType.BELLADONNA_PATCH -> 2 //average of 2 per life times 3 lives = 6 + PatchType.EVIL_TURNIP_PATCH -> 2 //average 2 per, same as BELLADONNA + PatchType.CACTUS_PATCH -> 3 //average of 3 per life times 3 lives = 9 else -> 0 // nothing should go here, but if it does, do not give extra crops amd decrement cropLives } @@ -86,7 +85,11 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl } fun isWeedy(): Boolean { - return getCurrentState() in 0..3 + return getCurrentState() in 0..2 + } + + fun isEmptyAndWeeded(): Boolean { + return getCurrentState() == 3 } fun getCurrentState(): Int{ @@ -138,14 +141,14 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl fun updateBit(){ if(isCheckHealth){ when(patch.type){ - PatchType.FRUIT_TREE -> setVarbit(player, patch.varbit, plantable!!.value + plantable!!.stages + 20) - PatchType.BUSH -> setVarbit(player, patch.varbit, 250 + (plantable!!.ordinal - Plantable.REDBERRY_SEED.ordinal)) - PatchType.CACTUS -> setVarbit(player, patch.varbit, 31) + PatchType.FRUIT_TREE_PATCH -> setVarbit(player, patch.varbit, plantable!!.value + plantable!!.stages + 20) + PatchType.BUSH_PATCH -> setVarbit(player, patch.varbit, 250 + (plantable!!.ordinal - Plantable.REDBERRY_SEED.ordinal)) + PatchType.CACTUS_PATCH -> setVarbit(player, patch.varbit, 31) else -> log(this::class.java, Log.WARN, "Invalid setting of isCheckHealth for patch type: " + patch.type.name) } } else { when(patch.type){ - PatchType.ALLOTMENT,PatchType.FLOWER,PatchType.HOPS -> { + PatchType.ALLOTMENT,PatchType.FLOWER_PATCH,PatchType.HOPS_PATCH -> { var state = getUnmodifiedValue() if (isWatered || isDead) state = state or 0x40 if (isDiseased) state = state or 0x80 @@ -153,11 +156,11 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl if (state != getVarbit(player, patch.varbit)) setVisualState(state) } - PatchType.BUSH -> { + PatchType.BUSH_PATCH -> { if(isDead) setVisualState(getBushDeathValue()) else if(isDiseased && !isDead) setVisualState(getBushDiseaseValue()) } - PatchType.TREE -> { + PatchType.TREE_PATCH -> { var state = getVarbit(player, patch.varbit) if (isDead) state = state or 0x80 @@ -166,20 +169,20 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl if (state != getVarbit(player, patch.varbit)) setVisualState(state) } - PatchType.FRUIT_TREE -> { + PatchType.FRUIT_TREE_PATCH -> { if(isDead) setVisualState(getFruitTreeDeathValue()) else if(isDiseased && !isDead) setVisualState(getFruitTreeDiseaseValue()) } - PatchType.BELLADONNA -> { + PatchType.BELLADONNA_PATCH -> { if(isDead) setVisualState(getBelladonnaDeathValue()) else if(isDiseased && !isDead) setVisualState(getBelladonnaDiseaseValue()) else setVisualState((plantable?.value ?: 0) + currentGrowthStage) } - PatchType.CACTUS -> { + PatchType.CACTUS_PATCH -> { if(isDead) setVisualState(getCactusDeathValue()) else if(isDiseased && !isDead) setVisualState(getCactusDiseaseValue()) } - PatchType.HERB -> { + PatchType.HERB_PATCH -> { if(isDead) setVisualState(getHerbDeathValue()) else if(isDiseased && !isDead) setVisualState(getHerbDiseaseValue()) else setVisualState((plantable?.value ?: 0) + currentGrowthStage) @@ -261,7 +264,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl } private fun grow(){ - if(isWeedy() && getCurrentState() > 0) { + if((isWeedy() || isEmptyAndWeeded()) && getCurrentState() > 0) { nextGrowth = System.currentTimeMillis() + 60000 setCurrentState(getCurrentState() - 1) currentGrowthStage-- @@ -275,28 +278,28 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl diseaseMod = when(compost){ CompostType.NONE -> 0 - CompostType.NORMAL -> 8 - CompostType.SUPER -> 13 + CompostType.COMPOST -> 8 + CompostType.SUPERCOMPOST -> 13 } - if(patch != FarmingPatch.TROLL_STRONGHOLD_HERB && RandomFunction.random(128) <= (17 - diseaseMod) && !isWatered && !isGrown() && !protectionPaid && !isFlowerProtected() && patch.type != PatchType.EVIL_TURNIP ){ + if(patch != FarmingPatch.TROLL_STRONGHOLD_HERB && RandomFunction.random(128) <= (17 - diseaseMod) && !isWatered && !isGrown() && !protectionPaid && !isFlowerProtected() && patch.type != PatchType.EVIL_TURNIP_PATCH ){ //bush, tree, fruit tree, herb and cactus can not disease on stage 1(0) of growth. - if(!((patch.type == PatchType.BUSH || patch.type == PatchType.TREE || patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.CACTUS || patch.type == PatchType.HERB) && currentGrowthStage == 0)) { + if(!((patch.type == PatchType.BUSH_PATCH || patch.type == PatchType.TREE_PATCH || patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.CACTUS_PATCH || patch.type == PatchType.HERB_PATCH) && currentGrowthStage == 0)) { isDiseased = true return } } - if((patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.TREE || patch.type == PatchType.BUSH || patch.type == PatchType.CACTUS) && plantable != null && plantable?.stages == currentGrowthStage + 1){ + if((patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.TREE_PATCH || patch.type == PatchType.BUSH_PATCH || patch.type == PatchType.CACTUS_PATCH) && plantable != null && plantable?.stages == currentGrowthStage + 1){ isCheckHealth = true } - if((patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.BUSH || patch.type == PatchType.CACTUS) && plantable?.stages == currentGrowthStage){ - if((patch.type == PatchType.BUSH && getFruitOrBerryCount() < 4) || (patch.type == PatchType.FRUIT_TREE && getFruitOrBerryCount() < 6) || (patch.type == PatchType.CACTUS && getFruitOrBerryCount() < 3)){ + if((patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.BUSH_PATCH || patch.type == PatchType.CACTUS_PATCH) && plantable?.stages == currentGrowthStage){ + if((patch.type == PatchType.BUSH_PATCH && getFruitOrBerryCount() < 4) || (patch.type == PatchType.FRUIT_TREE_PATCH && getFruitOrBerryCount() < 6) || (patch.type == PatchType.CACTUS_PATCH && getFruitOrBerryCount() < 3)){ setCurrentState(getCurrentState() + 1) } } - if(patch.type == PatchType.TREE) { + if(patch.type == PatchType.TREE_PATCH) { // Willow branches if(harvestAmt < 6) { harvestAmt++ @@ -313,7 +316,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl } fun regrowIfTreeStump() { - if(patch.type == PatchType.TREE && plantable != null) { + if(patch.type == PatchType.TREE_PATCH && plantable != null) { // plantable.value + plantable.stages is the check-health stage, so +1 is the choppable tree, and +2 is the stump if(getCurrentState() == plantable!!.value + plantable!!.stages + 2) { setCurrentState(getCurrentState() - 1) @@ -356,7 +359,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl fun getStageGrowthMinutes() : Int { var minutes = patch.type.stageGrowthTime - if(patch.type == PatchType.FRUIT_TREE && isGrown()) { + if(patch.type == PatchType.FRUIT_TREE_PATCH && isGrown()) { // Fruit trees take 160 minutes per stage to grow, but // restocking their fruit should take 40 minutes per fruit minutes = 40 diff --git a/Server/src/main/content/global/skill/farming/PatchRaker.kt b/Server/src/main/content/global/skill/farming/PatchRaker.kt index 6569ac495..27bc3d8fa 100644 --- a/Server/src/main/content/global/skill/farming/PatchRaker.kt +++ b/Server/src/main/content/global/skill/farming/PatchRaker.kt @@ -1,33 +1,45 @@ package content.global.skill.farming -import core.api.playAudio +import core.api.* import core.game.node.entity.player.Player import core.game.node.entity.skill.Skills -import core.game.node.item.Item import core.game.system.task.Pulse -import core.game.world.update.flag.context.Animation import org.rs09.consts.Items import org.rs09.consts.Sounds object PatchRaker { - val RAKE_ANIM = Animation(2273) + val RAKE_ANIM = getAnimation(2273) @JvmStatic - fun rake(player: Player, patch: FarmingPatch){ - player.pulseManager.run(object : Pulse(){ + fun rake(player: Player, patch: FarmingPatch) { + val p = patch.getPatchFor(player) + val patchName = p.patch.type.displayName() + var firstRake = true + if (p.isEmptyAndWeeded()) { + sendMessage(player, "This $patchName doesn't need weeding right now.") + return + } + submitIndividualPulse(player, object : Pulse() { override fun pulse(): Boolean { var patchStage = patch.getPatchFor(player).getCurrentState() - if(patchStage <= 2){ - player.animator.animate(RAKE_ANIM) + if (firstRake || patchStage < 2) { + // don't play the animation when on patchStage 2 as it has already + // played three times at this point and the patch will be weed-free + // after the third play + animate(player, RAKE_ANIM) playAudio(player, Sounds.FARMING_RAKING_2442) + firstRake = false } - if(delay < 5) { + if (delay < 5) { delay = 5 } else { patch.getPatchFor(player).currentGrowthStage++ patch.getPatchFor(player).setCurrentState(++patchStage) - player.inventory.add(Item(Items.WEEDS_6055)) - player.skills.addExperience(Skills.FARMING,4.0) + addItem(player, Items.WEEDS_6055) + rewardXP(player, Skills.FARMING, 4.0) + } + if (patchStage >= 3) { + resetAnimator(player) } return patchStage >= 3 } diff --git a/Server/src/main/content/global/skill/farming/PatchType.kt b/Server/src/main/content/global/skill/farming/PatchType.kt index 97c42fdf7..0cbe40129 100644 --- a/Server/src/main/content/global/skill/farming/PatchType.kt +++ b/Server/src/main/content/global/skill/farming/PatchType.kt @@ -2,15 +2,20 @@ package content.global.skill.farming enum class PatchType(val stageGrowthTime: Int) { ALLOTMENT(10), - HOPS(10), - TREE(40), - FRUIT_TREE(160), - BUSH(20), - FLOWER(5), - HERB(20), - SPIRIT_TREE(295), - MUSHROOM(30), - BELLADONNA(80), - CACTUS(60), - EVIL_TURNIP(5) + HOPS_PATCH(10), + TREE_PATCH(40), + FRUIT_TREE_PATCH(160), + BUSH_PATCH(20), + FLOWER_PATCH(5), + HERB_PATCH(20), + SPIRIT_TREE_PATCH(295), + MUSHROOM_PATCH(30), + BELLADONNA_PATCH(80), + CACTUS_PATCH(60), + EVIL_TURNIP_PATCH(5); + + /** + * Returns the display name of this PatchType. + */ + fun displayName(): String = name.lowercase().replace("_", " ") } diff --git a/Server/src/main/content/global/skill/farming/Plantable.kt b/Server/src/main/content/global/skill/farming/Plantable.kt index 8c006e9ea..c77d22b6e 100644 --- a/Server/src/main/content/global/skill/farming/Plantable.kt +++ b/Server/src/main/content/global/skill/farming/Plantable.kt @@ -6,15 +6,15 @@ import org.rs09.consts.Items enum class Plantable(val itemID: Int, val value: Int, val stages: Int, val plantingXP: Double, val harvestXP: Double, val checkHealthXP: Double, val requiredLevel: Int, val applicablePatch: PatchType, val harvestItem: Int, val protectionItem: Item? = null,val protectionFlower: Plantable? = null) { //Flowers - MARIGOLD_SEED(5096,8,4,8.5,47.0,0.0,2,PatchType.FLOWER,Items.MARIGOLDS_6010), - ROSEMARY_SEED(5097,13,4,12.0,66.5,0.0,11,PatchType.FLOWER, Items.ROSEMARY_6014), - NASTURTIUM_SEED(5098,18,4,19.5,111.0,0.0,24,PatchType.FLOWER,Items.NASTURTIUMS_6012), - WOAD_SEED(5099,23,4,20.5,115.5,0.0,25,PatchType.FLOWER,Items.WOAD_LEAF_1793), - LIMPWURT_SEED(5100,28,4,21.5,120.0,0.0,26,PatchType.FLOWER,Items.LIMPWURT_ROOT_225), - WHITE_LILY_SEED(14589,37,4,42.0,250.0,0.0,52,PatchType.FLOWER,Items.WHITE_LILY_14583), + MARIGOLD_SEED(5096,8,4,8.5,47.0,0.0,2,PatchType.FLOWER_PATCH,Items.MARIGOLDS_6010), + ROSEMARY_SEED(5097,13,4,12.0,66.5,0.0,11,PatchType.FLOWER_PATCH, Items.ROSEMARY_6014), + NASTURTIUM_SEED(5098,18,4,19.5,111.0,0.0,24,PatchType.FLOWER_PATCH,Items.NASTURTIUMS_6012), + WOAD_SEED(5099,23,4,20.5,115.5,0.0,25,PatchType.FLOWER_PATCH,Items.WOAD_LEAF_1793), + LIMPWURT_SEED(5100,28,4,21.5,120.0,0.0,26,PatchType.FLOWER_PATCH,Items.LIMPWURT_ROOT_225), + WHITE_LILY_SEED(14589,37,4,42.0,250.0,0.0,52,PatchType.FLOWER_PATCH,Items.WHITE_LILY_14583), //Flower(Technically) - SCARECROW(6059,33,3,0.0,0.0,0.0,23,PatchType.FLOWER,Items.SCARECROW_6059), + SCARECROW(6059,33,3,0.0,0.0,0.0,23,PatchType.FLOWER_PATCH,Items.SCARECROW_6059), //Allotments POTATO_SEED(5318, 6, 4, 8.0, 9.0, 0.0, 1, PatchType.ALLOTMENT, Items.POTATO_1942,Item(Items.COMPOST_6032,2),MARIGOLD_SEED), @@ -26,61 +26,61 @@ enum class Plantable(val itemID: Int, val value: Int, val stages: Int, val plant WATERMELON_SEED(5321,52,8,48.5,54.5,0.0,47,PatchType.ALLOTMENT,Items.WATERMELON_5982,Item(Items.CURRY_LEAF_5970,10),NASTURTIUM_SEED), //Hops - BARLEY_SEED(5305,49,4,8.5,9.5,0.0,3,PatchType.HOPS,Items.BARLEY_6006,Item(Items.COMPOST_6032,3)), - HAMMERSTONE_SEED(5307,4,4,9.0,10.0,0.0,4,PatchType.HOPS,Items.HAMMERSTONE_HOPS_5994,Item(Items.MARIGOLDS_6010)), - ASGARNIAN_SEED(5308,11,5,10.9,12.0,0.0,8,PatchType.HOPS,Items.ASGARNIAN_HOPS_5996,Item(Items.ONIONS10_5458)), - JUTE_SEED(5306,56,5,13.0,14.5,0.0,13,PatchType.HOPS,Items.JUTE_FIBRE_5931,Item(Items.BARLEY_MALT_6008,6)), - YANILLIAN_SEED(5309,19,6,14.5,16.0,0.0,16,PatchType.HOPS,Items.YANILLIAN_HOPS_5998,Item(Items.TOMATOES5_5968)), - KRANDORIAN_SEED(5310,28,7,17.5,19.5,0.0,21,PatchType.HOPS,Items.KRANDORIAN_HOPS_6000,Item(Items.CABBAGES10_5478,3)), - WILDBLOOD_SEED(5311,38,8,23.0,26.0,0.0,28,PatchType.HOPS,Items.WILDBLOOD_HOPS_6002,Item(Items.NASTURTIUMS_6012)), + BARLEY_SEED(5305,49,4,8.5,9.5,0.0,3,PatchType.HOPS_PATCH,Items.BARLEY_6006,Item(Items.COMPOST_6032,3)), + HAMMERSTONE_SEED(5307,4,4,9.0,10.0,0.0,4,PatchType.HOPS_PATCH,Items.HAMMERSTONE_HOPS_5994,Item(Items.MARIGOLDS_6010)), + ASGARNIAN_SEED(5308,11,5,10.9,12.0,0.0,8,PatchType.HOPS_PATCH,Items.ASGARNIAN_HOPS_5996,Item(Items.ONIONS10_5458)), + JUTE_SEED(5306,56,5,13.0,14.5,0.0,13,PatchType.HOPS_PATCH,Items.JUTE_FIBRE_5931,Item(Items.BARLEY_MALT_6008,6)), + YANILLIAN_SEED(5309,19,6,14.5,16.0,0.0,16,PatchType.HOPS_PATCH,Items.YANILLIAN_HOPS_5998,Item(Items.TOMATOES5_5968)), + KRANDORIAN_SEED(5310,28,7,17.5,19.5,0.0,21,PatchType.HOPS_PATCH,Items.KRANDORIAN_HOPS_6000,Item(Items.CABBAGES10_5478,3)), + WILDBLOOD_SEED(5311,38,8,23.0,26.0,0.0,28,PatchType.HOPS_PATCH,Items.WILDBLOOD_HOPS_6002,Item(Items.NASTURTIUMS_6012)), //Trees - OAK_SAPLING(5370,8,4,14.0,0.0,467.3,15,PatchType.TREE,Items.OAK_ROOTS_6043,Item(Items.TOMATOES5_5968)), - WILLOW_SAPLING(5371,15,6,25.0,0.0,1456.5,30,PatchType.TREE,Items.WILLOW_ROOTS_6045,Item(Items.APPLES5_5386)), - MAPLE_SAPLING(5372,24,8,45.0,0.0,3403.4,45,PatchType.TREE,Items.MAPLE_ROOTS_6047,Item(Items.ORANGES5_5396)), - YEW_SAPLING(5373,35,10,81.0,0.0,7069.9,60,PatchType.TREE,Items.YEW_ROOTS_6049,Item(Items.CACTUS_SPINE_6016,10)), - MAGIC_SAPLING(5374,48,12,145.5,0.0,13768.3,75,PatchType.TREE,Items.MAGIC_ROOTS_6051,Item(Items.COCONUT_5974,25)), + OAK_SAPLING(5370,8,4,14.0,0.0,467.3,15,PatchType.TREE_PATCH,Items.OAK_ROOTS_6043,Item(Items.TOMATOES5_5968)), + WILLOW_SAPLING(5371,15,6,25.0,0.0,1456.5,30,PatchType.TREE_PATCH,Items.WILLOW_ROOTS_6045,Item(Items.APPLES5_5386)), + MAPLE_SAPLING(5372,24,8,45.0,0.0,3403.4,45,PatchType.TREE_PATCH,Items.MAPLE_ROOTS_6047,Item(Items.ORANGES5_5396)), + YEW_SAPLING(5373,35,10,81.0,0.0,7069.9,60,PatchType.TREE_PATCH,Items.YEW_ROOTS_6049,Item(Items.CACTUS_SPINE_6016,10)), + MAGIC_SAPLING(5374,48,12,145.5,0.0,13768.3,75,PatchType.TREE_PATCH,Items.MAGIC_ROOTS_6051,Item(Items.COCONUT_5974,25)), //Fruit Trees - APPLE_SAPLING(5496,8,6,22.0,8.5,1199.5,27,PatchType.FRUIT_TREE,Items.COOKING_APPLE_1955,Item(Items.SWEETCORN_5986,9)), - BANANA_SAPLING(5497,35,6,28.0,10.5,1750.5,33,PatchType.FRUIT_TREE,Items.BANANA_1963,Item(Items.APPLES5_5386,4)), - ORANGE_SAPLING(5498,72,6,35.5,13.5,2470.2,39,PatchType.FRUIT_TREE,Items.ORANGE_2108,Item(Items.STRAWBERRIES5_5406,3)), - CURRY_SAPLING(5499,99,6,40.0,15.0,2906.9,42,PatchType.FRUIT_TREE,Items.CURRY_LEAF_5970,Item(Items.BANANAS5_5416,5)), - PINEAPPLE_SAPLING(5500,136,6,57.0,21.5,4605.7,51,PatchType.FRUIT_TREE,Items.PINEAPPLE_2114,Item(Items.WATERMELON_5982,10)), - PAPAYA_SAPLING(5501,163,6,72.0,27.0,6146.4,57,PatchType.FRUIT_TREE,Items.PAPAYA_FRUIT_5972,Item(Items.PINEAPPLE_2114,10)), - PALM_SAPLING(5502,200,6,110.5,41.5,10150.1,68,PatchType.FRUIT_TREE,Items.COCONUT_5974,Item(Items.PAPAYA_FRUIT_5972,15)), + APPLE_SAPLING(5496,8,6,22.0,8.5,1199.5,27,PatchType.FRUIT_TREE_PATCH,Items.COOKING_APPLE_1955,Item(Items.SWEETCORN_5986,9)), + BANANA_SAPLING(5497,35,6,28.0,10.5,1750.5,33,PatchType.FRUIT_TREE_PATCH,Items.BANANA_1963,Item(Items.APPLES5_5386,4)), + ORANGE_SAPLING(5498,72,6,35.5,13.5,2470.2,39,PatchType.FRUIT_TREE_PATCH,Items.ORANGE_2108,Item(Items.STRAWBERRIES5_5406,3)), + CURRY_SAPLING(5499,99,6,40.0,15.0,2906.9,42,PatchType.FRUIT_TREE_PATCH,Items.CURRY_LEAF_5970,Item(Items.BANANAS5_5416,5)), + PINEAPPLE_SAPLING(5500,136,6,57.0,21.5,4605.7,51,PatchType.FRUIT_TREE_PATCH,Items.PINEAPPLE_2114,Item(Items.WATERMELON_5982,10)), + PAPAYA_SAPLING(5501,163,6,72.0,27.0,6146.4,57,PatchType.FRUIT_TREE_PATCH,Items.PAPAYA_FRUIT_5972,Item(Items.PINEAPPLE_2114,10)), + PALM_SAPLING(5502,200,6,110.5,41.5,10150.1,68,PatchType.FRUIT_TREE_PATCH,Items.COCONUT_5974,Item(Items.PAPAYA_FRUIT_5972,15)), //Bushes - REDBERRY_SEED(5101,5,5,11.5,4.5,64.0,10,PatchType.BUSH,Items.REDBERRIES_1951,Item(Items.CABBAGES10_5478,4)), - CADAVABERRY_SEED(5102,15,6,18.0,7.0,102.5,22,PatchType.BUSH,Items.CADAVA_BERRIES_753,Item(Items.TOMATOES5_5968,3)), - DWELLBERRY_SEED(5103,26,27,31.5,12.0,177.5,36,PatchType.BUSH,Items.DWELLBERRIES_2126,Item(Items.STRAWBERRIES5_5406,3)), - JANGERBERRY_SEED(5104,38,8,50.5,19.0,284.5,48,PatchType.BUSH,Items.JANGERBERRIES_247,Item(Items.WATERMELON_5982,6)), - WHITEBERRY_SEED(5105,51,8,78.0,29.0,437.5,59,PatchType.BUSH,Items.WHITE_BERRIES_239,null), - POISON_IVY_SEED(5106,197,8,120.0,45.0,675.0,70,PatchType.BUSH,Items.POISON_IVY_BERRIES_6018,null), + REDBERRY_SEED(5101,5,5,11.5,4.5,64.0,10,PatchType.BUSH_PATCH,Items.REDBERRIES_1951,Item(Items.CABBAGES10_5478,4)), + CADAVABERRY_SEED(5102,15,6,18.0,7.0,102.5,22,PatchType.BUSH_PATCH,Items.CADAVA_BERRIES_753,Item(Items.TOMATOES5_5968,3)), + DWELLBERRY_SEED(5103,26,27,31.5,12.0,177.5,36,PatchType.BUSH_PATCH,Items.DWELLBERRIES_2126,Item(Items.STRAWBERRIES5_5406,3)), + JANGERBERRY_SEED(5104,38,8,50.5,19.0,284.5,48,PatchType.BUSH_PATCH,Items.JANGERBERRIES_247,Item(Items.WATERMELON_5982,6)), + WHITEBERRY_SEED(5105,51,8,78.0,29.0,437.5,59,PatchType.BUSH_PATCH,Items.WHITE_BERRIES_239,null), + POISON_IVY_SEED(5106,197,8,120.0,45.0,675.0,70,PatchType.BUSH_PATCH,Items.POISON_IVY_BERRIES_6018,null), //Herbs - GUAM_SEED(5291,4,4,11.0,12.5,0.0,9,PatchType.HERB,Items.GRIMY_GUAM_199), - MARRENTILL_SEED(5292,11,4,13.5,15.0,0.0,14,PatchType.HERB,Items.GRIMY_MARRENTILL_201), - TARROMIN_SEED(5293,18,4,16.0,18.0,0.0,19,PatchType.HERB,Items.GRIMY_TARROMIN_203), - HARRALANDER_SEED(5294,25,4,21.5,24.0,0.0,26,PatchType.HERB,Items.GRIMY_HARRALANDER_205), - RANARR_SEED(5295,32,4,27.0,30.5,0.0,32,PatchType.HERB,Items.GRIMY_RANARR_207), - AVANTOE_SEED(5298,39,4,54.5,61.5,0.0,50,PatchType.HERB,Items.GRIMY_AVANTOE_211), - TOADFLAX_SEED(5296,46,4,34.0,38.5,0.0,38,PatchType.HERB,Items.GRIMY_TOADFLAX_3049), - IRIT_SEED(5297,53,4,43.0,48.5,0.0,44,PatchType.HERB,Items.GRIMY_IRIT_209), - KWUARM_SEED(5299,68,4,69.0,78.0,0.0,56,PatchType.HERB,Items.GRIMY_KWUARM_213), - SNAPDRAGON_SEED(5300,75,4,87.5,98.5,0.0,62,PatchType.HERB,Items.GRIMY_SNAPDRAGON_3051), - CADANTINE_SEED(5301,82,4,106.5,120.0,0.0,67,PatchType.HERB,Items.GRIMY_CADANTINE_215), - LANTADYME_SEED(5302,89,4,134.5,151.5,0.0,73,PatchType.HERB,Items.GRIMY_LANTADYME_2485), - DWARF_WEED_SEED(5303,96,4,170.5,192.0,0.0,79,PatchType.HERB,Items.GRIMY_DWARF_WEED_217), - TORSTOL_SEED(5304,103,4,199.5,224.5,0.0,85,PatchType.HERB,Items.GRIMY_TORSTOL_219), - GOUT_TUBER(6311,192,4,105.0,45.0,0.0,29,PatchType.HERB,Items.GOUTWEED_3261), - SPIRIT_WEED_SEED(12176, 204, 4, 32.0, 36.0, 0.0, 36, PatchType.HERB, Items.GRIMY_SPIRIT_WEED_12174), + GUAM_SEED(5291,4,4,11.0,12.5,0.0,9,PatchType.HERB_PATCH,Items.GRIMY_GUAM_199), + MARRENTILL_SEED(5292,11,4,13.5,15.0,0.0,14,PatchType.HERB_PATCH,Items.GRIMY_MARRENTILL_201), + TARROMIN_SEED(5293,18,4,16.0,18.0,0.0,19,PatchType.HERB_PATCH,Items.GRIMY_TARROMIN_203), + HARRALANDER_SEED(5294,25,4,21.5,24.0,0.0,26,PatchType.HERB_PATCH,Items.GRIMY_HARRALANDER_205), + RANARR_SEED(5295,32,4,27.0,30.5,0.0,32,PatchType.HERB_PATCH,Items.GRIMY_RANARR_207), + AVANTOE_SEED(5298,39,4,54.5,61.5,0.0,50,PatchType.HERB_PATCH,Items.GRIMY_AVANTOE_211), + TOADFLAX_SEED(5296,46,4,34.0,38.5,0.0,38,PatchType.HERB_PATCH,Items.GRIMY_TOADFLAX_3049), + IRIT_SEED(5297,53,4,43.0,48.5,0.0,44,PatchType.HERB_PATCH,Items.GRIMY_IRIT_209), + KWUARM_SEED(5299,68,4,69.0,78.0,0.0,56,PatchType.HERB_PATCH,Items.GRIMY_KWUARM_213), + SNAPDRAGON_SEED(5300,75,4,87.5,98.5,0.0,62,PatchType.HERB_PATCH,Items.GRIMY_SNAPDRAGON_3051), + CADANTINE_SEED(5301,82,4,106.5,120.0,0.0,67,PatchType.HERB_PATCH,Items.GRIMY_CADANTINE_215), + LANTADYME_SEED(5302,89,4,134.5,151.5,0.0,73,PatchType.HERB_PATCH,Items.GRIMY_LANTADYME_2485), + DWARF_WEED_SEED(5303,96,4,170.5,192.0,0.0,79,PatchType.HERB_PATCH,Items.GRIMY_DWARF_WEED_217), + TORSTOL_SEED(5304,103,4,199.5,224.5,0.0,85,PatchType.HERB_PATCH,Items.GRIMY_TORSTOL_219), + GOUT_TUBER(6311,192,4,105.0,45.0,0.0,29,PatchType.HERB_PATCH,Items.GOUTWEED_3261), + SPIRIT_WEED_SEED(12176, 204, 4, 32.0, 36.0, 0.0, 36, PatchType.HERB_PATCH, Items.GRIMY_SPIRIT_WEED_12174), //Other - BELLADONNA_SEED(5281, 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA, Items.CAVE_NIGHTSHADE_2398), - MUSHROOM_SPORE(Items.MUSHROOM_SPORE_5282, 6, 7, 61.5, 57.7, 0.0, 53, PatchType.MUSHROOM, Items.MUSHROOM_6004), - CACTUS_SEED(Items.CACTUS_SEED_5280, 8, 7, 66.5, 25.0, 374.0, 55, PatchType.CACTUS, Items.CACTUS_SPINE_6016), - EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP, Items.EVIL_TURNIP_12134) + BELLADONNA_SEED(5281, 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA_PATCH, Items.CAVE_NIGHTSHADE_2398), + MUSHROOM_SPORE(Items.MUSHROOM_SPORE_5282, 6, 7, 61.5, 57.7, 0.0, 53, PatchType.MUSHROOM_PATCH, Items.MUSHROOM_6004), + CACTUS_SEED(Items.CACTUS_SEED_5280, 8, 7, 66.5, 25.0, 374.0, 55, PatchType.CACTUS_PATCH, Items.CACTUS_SPINE_6016), + EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP_PATCH, Items.EVIL_TURNIP_12134) ; constructor(itemID: Int, value: Int, stages: Int, plantingXP: Double, harvestXP: Double, checkHealthXP: Double, requiredLevel: Int, applicablePatch: PatchType, harvestItem: Int, protectionFlower: Plantable) diff --git a/Server/src/main/content/global/skill/farming/SeedOnPlantPot.kt b/Server/src/main/content/global/skill/farming/SeedOnPlantPot.kt index 170c986c2..39c83483e 100644 --- a/Server/src/main/content/global/skill/farming/SeedOnPlantPot.kt +++ b/Server/src/main/content/global/skill/farming/SeedOnPlantPot.kt @@ -7,6 +7,7 @@ import core.game.interaction.IntType import core.game.node.entity.player.Player import content.global.skill.farming.timers.* import core.game.interaction.InteractionListener +import core.tools.prependArticle class SeedlingListener : InteractionListener { override fun defineListeners() { @@ -18,7 +19,7 @@ class SeedlingListener : InteractionListener { val seed = used.asItem() ?: return false val pot = with.asItem() ?: return false - if(!inInventory(player, Items.GARDENING_TROWEL_5325)){ + if (!inInventory(player, Items.GARDENING_TROWEL_5325)) { sendDialogue(player, "You need a gardening trowel on you to do this.") return false } @@ -27,6 +28,8 @@ class SeedlingListener : InteractionListener { if (seedling == -1) return false if (!removeItem(player, seed.id) || !removeItem(player, pot)) return true addItem(player, seedling) + sendMessage(player, "You sow ${prependArticle(seed.name.lowercase())} in the plantpot.") + sendMessage(player, "It needs watering before it will grow.") return true } @@ -46,11 +49,12 @@ class SeedlingListener : InteractionListener { return true } - private fun Int.getNext(): Int{ + private fun Int.getNext(): Int { val index = WATERING_CANS.indexOf(this) if (index == -1) return Items.WATERING_CAN_5331 return if (index != WATERING_CANS.size -1) WATERING_CANS[index + 1] else Items.WATERING_CAN_5331 } + fun getSeedling(id: Int) : Int { return when (id) { Items.ACORN_5312 -> Items.OAK_SEEDLING_5358 diff --git a/Server/src/main/content/global/skill/farming/ToolLeprechaunInterface.kt b/Server/src/main/content/global/skill/farming/ToolLeprechaunInterface.kt index 9ef9aa7a7..980d20b07 100644 --- a/Server/src/main/content/global/skill/farming/ToolLeprechaunInterface.kt +++ b/Server/src/main/content/global/skill/farming/ToolLeprechaunInterface.kt @@ -1,7 +1,6 @@ package content.global.skill.farming import core.api.* -import core.game.component.Component import core.game.node.entity.player.Player import core.game.node.item.Item import org.rs09.consts.Components @@ -14,207 +13,211 @@ class ToolLeprechaunInterface : InterfaceListener { override fun defineInterfaceListeners() { - onOpen(FARMING_TOOLS){player, component -> - player.interfaceManager.openSingleTab(Component(TOOLS_SIDE)) + onOpen(FARMING_TOOLS) { player, component -> + openSingleTab(player, TOOLS_SIDE) return@onOpen true } - onClose(FARMING_TOOLS){player, _ -> - player.interfaceManager.closeSingleTab() + onClose(FARMING_TOOLS) { player, _ -> + closeTabInterface(player) + return@onClose true } - on(FARMING_TOOLS){player, _, opcode, buttonID, _, _ -> - when(buttonID){ - 33 -> doWithdrawal(player, Items.RAKE_5341,::setHasRake,::hasRake) - 34 -> doWithdrawal(player,Items.SEED_DIBBER_5343,::setHasDibber,::hasDibber) - 35 -> doWithdrawal(player,Items.SPADE_952,::setHasSpade,::hasSpade) + on(FARMING_TOOLS) { player, _, opcode, buttonID, _, _ -> + when (buttonID) { + 33 -> doWithdrawal(player, Items.RAKE_5341, ::setHasRake, ::hasRake) + 34 -> doWithdrawal(player, Items.SEED_DIBBER_5343, ::setHasDibber, ::hasDibber) + 35 -> doWithdrawal(player, Items.SPADE_952, ::setHasSpade, ::hasSpade) 36 -> { - val sec = if(hasMagicSecateurs(player)) Items.MAGIC_SECATEURS_7409 else Items.SECATEURS_5329 - doWithdrawal(player,sec,::setHasSecateurs,::hasSecateurs) + val sec = if (hasMagicSecateurs(player)) Items.MAGIC_SECATEURS_7409 else Items.SECATEURS_5329 + doWithdrawal(player, sec, ::setHasSecateurs, ::hasSecateurs) } 37 -> { - if(!hasWateringCan(player)){ - player.dialogueInterpreter.sendDialogue("You don't have any of those stored.") + if (!hasWateringCan(player)) { + sendMessage(player, "You haven't got a watering can stored in here!") } else { - player.inventory.add(Item(getWateringCan(player))) - setNoWateringCan(player) + if (freeSlots(player) == 0) { + sendMessage(player, "You don't have enough space for that.") + } + if (addItem(player, getWateringCan(player))) setNoWateringCan(player) } } - 38 -> doWithdrawal(player,Items.GARDENING_TROWEL_5325,::setHasGardeningTrowel,::hasGardeningTrowel) - 39 -> doStackedWithdrawal(player,Items.BUCKET_1925,getAmount(opcode),::updateBuckets,::getNumBuckets) - 40 -> doStackedWithdrawal(player,Items.COMPOST_6032,getAmount(opcode),::updateCompost,::getNumCompost) - 41 -> doStackedWithdrawal(player,Items.SUPERCOMPOST_6034,getAmount(opcode),::updateSuperCompost,::getNumSuperCompost) + 38 -> doWithdrawal(player, Items.GARDENING_TROWEL_5325, ::setHasGardeningTrowel, ::hasGardeningTrowel) + 39 -> doStackedWithdrawal(player, Items.BUCKET_1925, getAmount(opcode), ::updateBuckets, ::getNumBuckets) + 40 -> doStackedWithdrawal(player, Items.COMPOST_6032, getAmount(opcode), ::updateCompost, ::getNumCompost) + 41 -> doStackedWithdrawal(player, Items.SUPERCOMPOST_6034, getAmount(opcode), ::updateSuperCompost, ::getNumSuperCompost) } return@on true } - on(TOOLS_SIDE){player, _, opcode, buttonID, _, _ -> - when(buttonID){ - 18 -> doDeposit(player,Items.RAKE_5341,::setHasRake,::hasRake) - 19 -> doDeposit(player,Items.SEED_DIBBER_5343,::setHasDibber,::hasDibber) - 20 -> doDeposit(player,Items.SPADE_952,::setHasSpade,::hasSpade) + on(TOOLS_SIDE) { player, _, opcode, buttonID, _, _ -> + when (buttonID) { + 18 -> doDeposit(player, Items.RAKE_5341, ::setHasRake, ::hasRake) + 19 -> doDeposit(player, Items.SEED_DIBBER_5343, ::setHasDibber, ::hasDibber) + 20 -> doDeposit(player, Items.SPADE_952, ::setHasSpade, ::hasSpade) 21 -> { - if(!player.inventory.contains(Items.SECATEURS_5329,1) && !player.inventory.contains(Items.MAGIC_SECATEURS_7409,1)){ - player.dialogueInterpreter.sendDialogue("You don't have any of those to store.") - } else if (!hasSecateurs(player)){ - if(player.inventory.contains(Items.MAGIC_SECATEURS_7409,1)){ - player.inventory.remove(Item(Items.MAGIC_SECATEURS_7409)) + if (!inInventory(player, Items.SECATEURS_5329) && !inInventory(player, Items.MAGIC_SECATEURS_7409)) { + sendMessage(player, "You haven't got any secateurs to store.") + } else if (!hasSecateurs(player)) { + if (inInventory(player, Items.MAGIC_SECATEURS_7409)) { + removeItem(player, Items.MAGIC_SECATEURS_7409) setHasSecateurs(player,true) setHasMagicSecateurs(player,true) } else { - player.inventory.remove(Item(Items.SECATEURS_5329)) + removeItem(player, Items.SECATEURS_5329) setHasSecateurs(player,true) setHasMagicSecateurs(player,false) } } else { - player.dialogueInterpreter.sendDialogue("You already have one of those stored.") + sendMessage(player, "You already have one of those stored.") } } 22 -> { val can = getHighestCan(player) - if(can == null){ - player.dialogueInterpreter.sendDialogue("You don't have any of those to store.") - } else if(!hasWateringCan(player)){ - player.inventory.remove(can) + if (can == null) { + sendMessage(player, "You haven't got a watering can to store.") + } else if (!hasWateringCan(player)) { + removeItem(player, can) setWateringCan(player,can) } else { - player.dialogueInterpreter.sendDialogue("You already have one of those stored.") + sendMessage(player, "You already have one of those stored.") } } - 23 -> doDeposit(player,Items.GARDENING_TROWEL_5325,::setHasGardeningTrowel,::hasGardeningTrowel) - 24 -> doStackedDeposit(player,Items.BUCKET_1925,getAmount(opcode),::updateBuckets,::getNumBuckets) - 25 -> doStackedDeposit(player,Items.COMPOST_6032,getAmount(opcode),::updateCompost,::getNumCompost) - 26 -> doStackedDeposit(player,Items.SUPERCOMPOST_6034,getAmount(opcode),::updateSuperCompost,::getNumSuperCompost) + 23 -> doDeposit(player, Items.GARDENING_TROWEL_5325, ::setHasGardeningTrowel, ::hasGardeningTrowel) + 24 -> doStackedDeposit(player, Items.BUCKET_1925, getAmount(opcode), ::updateBuckets, ::getNumBuckets) + 25 -> doStackedDeposit(player, Items.COMPOST_6032, getAmount(opcode), ::updateCompost, ::getNumCompost) + 26 -> doStackedDeposit(player, Items.SUPERCOMPOST_6034, getAmount(opcode), ::updateSuperCompost, ::getNumSuperCompost) } return@on true } } - private fun doWithdrawal(player: Player?, item: Int, withdrawMethod: (Player?,Boolean) -> Unit, checkMethod: (Player?) -> Boolean){ + private fun doWithdrawal(player: Player?, item: Int, withdrawMethod: (Player?, Boolean) -> Unit, checkMethod: (Player?) -> Boolean) { player ?: return - if(!checkMethod.invoke(player)){ - player.dialogueInterpreter.sendDialogue("You don't have any of those stored.") + if (!checkMethod.invoke(player)) { + val determiner = if (getItemName(item).lowercase().endsWith("s")) "any" else "a" + sendMessage(player, "You haven't got $determiner ${getItemName(item).lowercase()} stored in here!") } else { - if(!player.inventory.hasSpaceFor(Item(item))){ - player.dialogueInterpreter.sendDialogue("You don't have enough space for that.") + if (!hasSpaceFor(player, Item(item))) { + sendMessage(player, "You don't have enough space for that.") return } - withdrawMethod.invoke(player,false) - player.inventory.add(Item(item)) + withdrawMethod.invoke(player, false) + addItem(player, item) } } - private fun doDeposit(player: Player?, item: Int, depositMethod: (Player?,Boolean) -> Unit, checkMethod: (Player?) -> Boolean){ + private fun doDeposit(player: Player?, item: Int, depositMethod: (Player?, Boolean) -> Unit, checkMethod: (Player?) -> Boolean) { player ?: return - if(!player.inventory.contains(item,1)){ - player.dialogueInterpreter.sendDialogue("You don't have any of those to store.") + if (!inInventory(player, item)) { + val determiner = if (getItemName(item).lowercase().endsWith("s")) "any" else "a" + sendMessage(player, "You haven't got $determiner ${getItemName(item).lowercase()} to store.") + return } - if(!checkMethod.invoke(player)){ - depositMethod.invoke(player,true) - player.inventory.remove(Item(item)) + if (!checkMethod.invoke(player)) { + depositMethod.invoke(player, true) + removeItem(player, item) } else { - player.dialogueInterpreter.sendDialogue("You already have one of those stored.") + sendMessage(player, "You already have one of those stored.") } } - private fun doStackedDeposit(player: Player?, item: Int, amount: Int, updateQuantityMethod: (Player?, Int) -> Unit, quantityCheckMethod: (Player?) -> Int){ + private fun doStackedDeposit(player: Player?, item: Int, amount: Int, updateQuantityMethod: (Player?, Int) -> Unit, quantityCheckMethod: (Player?) -> Int) { player ?: return - val hasAmount = player.inventory.getAmount(item) + val hasAmount = amountInInventory(player, item) var finalAmount = amount - val spaceLeft = (if(item == Items.BUCKET_1925) 31 else 255) - quantityCheckMethod.invoke(player) + val spaceLeft = (if (item == Items.BUCKET_1925) 31 else 255) - quantityCheckMethod.invoke(player) - if(hasAmount == 0){ - player.dialogueInterpreter.sendDialogue("You don't have any of those to store.") + if (hasAmount == 0) { + val itemName = if (item == Items.BUCKET_1925) "buckets" else getItemName(item).lowercase() + sendMessage(player, "You haven't got any $itemName to store.") return } - if(amount == -2){ - sendInputDialogue(player, true, "Enter the amount:"){value -> + if (amount == -2) { + sendInputDialogue(player, true, "Enter the amount:") { value -> var amt = value as Int - if(amt > hasAmount){ + if (amt > hasAmount) { amt = hasAmount } - if(amt > spaceLeft){ + if (amt > spaceLeft) { amt = spaceLeft } - if(amt == 0){ - player.dialogueInterpreter.sendDialogue("You don't have any of those to store.") - return@sendInputDialogue - } - player.inventory.remove(Item(item,amt)) - updateQuantityMethod.invoke(player,amt) + if (removeItem(player, Item(item, amt))) updateQuantityMethod.invoke(player, amt) } return } - if(amount == -1){ + + if (amount == -1) { finalAmount = hasAmount - if(finalAmount > spaceLeft){ + if (finalAmount > spaceLeft) { finalAmount = spaceLeft } } - if(finalAmount > hasAmount){ + if (finalAmount > hasAmount) { finalAmount = hasAmount } - if(finalAmount > spaceLeft) finalAmount = spaceLeft - if(!player.inventory.contains(item,finalAmount)){ - player.dialogueInterpreter.sendDialogue("You don't have any of those to store.") + if (finalAmount > spaceLeft) { + if (item == Items.BUCKET_1925) { + sendMessage(player, "You can't store that many buckets in here.") + } else { + sendMessage(player, "You can't store that much ${getItemName(item).lowercase()} in here.") + } return } - if(finalAmount > spaceLeft){ - player.dialogueInterpreter.sendDialogue("You can't store any more of those.") - return - } - - player.inventory.remove(Item(item,finalAmount)) + removeItem(player, Item(item, finalAmount)) updateQuantityMethod.invoke(player,finalAmount) } - private fun doStackedWithdrawal(player: Player?,item: Int, amount: Int,updateQuantityMethod: (Player?,Int) -> Unit, quantityCheckMethod: (Player?) -> Int){ + private fun doStackedWithdrawal(player: Player?, item: Int, amount: Int, updateQuantityMethod: (Player?, Int) -> Unit, quantityCheckMethod: (Player?) -> Int) { player ?: return val hasAmount = quantityCheckMethod.invoke(player) var finalAmount = amount - if(hasAmount == 0){ - player.dialogueInterpreter.sendDialogue("You don't have any of those stored.") - } else { - if(amount == -2){ - sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:"){value -> - var amt = value as Int - if(amt > hasAmount){ - amt = hasAmount - } - if(amt > player.inventory.freeSlots()){ - amt = player.inventory.freeSlots() - } - if(amt <= 0){ - player.dialogueInterpreter.sendDialogue("You don't have enough inventory space for that.") - } else { - player.inventory.add(Item(item, amt)) - updateQuantityMethod.invoke(player, -amt) - } - } - return - } - if(amount == -1){ - finalAmount = player.inventory.freeSlots() - } - if(finalAmount > hasAmount){ - finalAmount = hasAmount - } - if(!player.inventory.hasSpaceFor(Item(item,finalAmount)) || finalAmount == 0){ - player.dialogueInterpreter.sendDialogue("You don't have enough inventory space for that.") - return - } - player.inventory.add(Item(item,finalAmount)) - updateQuantityMethod.invoke(player,-finalAmount) + + if (hasAmount == 0) { + val itemName = if (item == Items.BUCKET_1925) "buckets" else getItemName(item).lowercase() + sendMessage(player, "You haven't got any $itemName stored in here!") + return } + + if (amount == -2) { + sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:") { value -> + var amt = value as Int + if (amt > hasAmount) { + amt = hasAmount + } + if (amt > freeSlots(player)) { + amt = freeSlots(player) + } + if (amt <= 0) { + sendMessage(player, "You don't have enough inventory space for that.") + } else { + addItem(player, item, amt) + updateQuantityMethod.invoke(player, -amt) + } + } + return + } + if (amount == -1) { + finalAmount = freeSlots(player) + } + if (finalAmount > hasAmount) { + finalAmount = hasAmount + } + if (!hasSpaceFor(player, Item(item, finalAmount)) || finalAmount == 0) { + sendMessage(player, "You don't have enough inventory space for that.") + return + } + addItem(player, item, finalAmount) + updateQuantityMethod.invoke(player, -finalAmount) } - fun getAmount(opcode: Int): Int{ - return when(opcode) { + fun getAmount(opcode: Int): Int { + return when (opcode) { 155 -> 1 196 -> 5 124 -> -1 @@ -223,50 +226,50 @@ class ToolLeprechaunInterface : InterfaceListener { } } - private fun hasRake(player: Player?): Boolean{ + private fun hasRake(player: Player?): Boolean { return getVarbit(player!!, 1435) == 1 } - private fun setHasRake(player: Player?,hasRake: Boolean){ + private fun setHasRake(player: Player?, hasRake: Boolean) { setVarbit(player!!, 1435, if (hasRake) 1 else 0, true) } - private fun hasDibber(player: Player?): Boolean{ + private fun hasDibber(player: Player?): Boolean { return getVarbit(player!!, 1436) == 1 } - private fun setHasDibber(player: Player?,hasDibber: Boolean){ + private fun setHasDibber(player: Player?, hasDibber: Boolean) { setVarbit(player!!, 1436, if (hasDibber) 1 else 0, true) } - private fun hasSpade(player: Player?): Boolean{ + private fun hasSpade(player: Player?): Boolean { return getVarbit(player!!, 1437) == 1 } - private fun setHasSpade(player: Player?,hasSpade: Boolean){ + private fun setHasSpade(player: Player?, hasSpade: Boolean) { setVarbit(player!!, 1437, if (hasSpade) 1 else 0, true) } - private fun hasSecateurs(player: Player?): Boolean{ + private fun hasSecateurs(player: Player?): Boolean { return getVarbit(player!!, 1438) == 1 } - private fun setHasSecateurs(player: Player?,hasSecateurs: Boolean){ + private fun setHasSecateurs(player: Player?, hasSecateurs: Boolean) { setVarbit(player!!, 1438, if (hasSecateurs) 1 else 0, true) } - private fun hasWateringCan(player: Player?): Boolean{ + private fun hasWateringCan(player: Player?): Boolean { return getVarbit(player!!, 1439) > 0 } - private fun getWateringCan(player: Player?): Int{ + private fun getWateringCan(player: Player?): Int { var can = getVarbit(player!!, 1439) //Watering cans are stored in the Varp as a number between 1 and 9. Watering Can(0) is 1 and Watering Can(8) is 9 - if(can == 1) can = 0 + if (can == 1) can = 0 return Items.WATERING_CAN_5331 + can } - private fun setWateringCan(player: Player?, item: Item){ - val can = when(item.id){ + private fun setWateringCan(player: Player?, item: Item) { + val can = when (item.id) { Items.WATERING_CAN_5331 -> 1 Items.WATERING_CAN1_5333 -> 2 Items.WATERING_CAN2_5334 -> 3 @@ -281,7 +284,7 @@ class ToolLeprechaunInterface : InterfaceListener { setVarbit(player!!, 1439, can, true) } - private fun setNoWateringCan(player: Player?){ + private fun setNoWateringCan(player: Player?) { setVarbit(player!!, 1439, 0, true) } @@ -289,7 +292,7 @@ class ToolLeprechaunInterface : InterfaceListener { return getVarbit(player!!, 1440) == 1 } - private fun setHasGardeningTrowel(player: Player?,hasTrowel: Boolean){ + private fun setHasGardeningTrowel(player: Player?, hasTrowel: Boolean) { setVarbit(player!!, 1440, if (hasTrowel) 1 else 0, true) } @@ -297,7 +300,7 @@ class ToolLeprechaunInterface : InterfaceListener { return getVarbit(player!!, 1441) } - private fun updateBuckets(player: Player?,amount: Int){ + private fun updateBuckets(player: Player?, amount: Int) { setVarbit(player!!, 1441, getNumBuckets(player) + amount, true) } @@ -305,7 +308,7 @@ class ToolLeprechaunInterface : InterfaceListener { return getVarbit(player!!, 1442) } - private fun updateCompost(player: Player?,amount: Int){ + private fun updateCompost(player: Player?, amount: Int) { setVarbit(player!!, 1442, getNumCompost(player) + amount, true) } @@ -313,7 +316,7 @@ class ToolLeprechaunInterface : InterfaceListener { return getVarbit(player!!, 1443) } - private fun updateSuperCompost(player: Player?,amount: Int){ + private fun updateSuperCompost(player: Player?, amount: Int) { setVarbit(player!!, 1443, getNumSuperCompost(player) + amount, true) } @@ -321,20 +324,20 @@ class ToolLeprechaunInterface : InterfaceListener { return getVarbit(player!!, 1848) == 1 } - private fun setHasMagicSecateurs(player: Player?,hasMagic: Boolean){ + private fun setHasMagicSecateurs(player: Player?, hasMagic: Boolean) { setVarbit(player!!, 1848, if (hasMagic) 1 else 0, true) } - private fun getHighestCan(player: Player?): Item?{ + private fun getHighestCan(player: Player?): Item? { player ?: return null var highestCan = Item(0) - for(item in player.inventory.toArray()){ - if(item == null) continue - if(item.name.contains("Watering")){ - if(item.id > highestCan.id) highestCan = item + for (item in player.inventory.toArray()) { + if (item == null) continue + if (item.name.contains("Watering")) { + if (item.id > highestCan.id) highestCan = item } } - return if(highestCan.id == 0) null else highestCan + return if (highestCan.id == 0) null else highestCan } } diff --git a/Server/src/main/content/global/skill/farming/UseWithBinHandler.kt b/Server/src/main/content/global/skill/farming/UseWithBinHandler.kt index 50f53434f..8d557e9b6 100644 --- a/Server/src/main/content/global/skill/farming/UseWithBinHandler.kt +++ b/Server/src/main/content/global/skill/farming/UseWithBinHandler.kt @@ -1,7 +1,6 @@ package content.global.skill.farming import core.api.* -import core.game.node.item.Item import core.game.system.task.Pulse import core.game.world.update.flag.context.Animation import org.rs09.consts.Items @@ -25,58 +24,58 @@ class UseWithBinHandler : InteractionListener { val used = usedNode.id - when(used){ - Items.COMPOST_POTION1_6476,Items.COMPOST_POTION2_6474, Items.COMPOST_POTION3_6472,Items.COMPOST_POTION4_6470 -> { - if(!bin.isSuperCompost && bin.isFinished && !bin.isClosed){ - player.animator.animate(compostPotionAnimation) - player.pulseManager.run(object : Pulse(compostPotionAnimation.duration){ + when (used) { + Items.COMPOST_POTION1_6476, Items.COMPOST_POTION2_6474, Items.COMPOST_POTION3_6472, Items.COMPOST_POTION4_6470 -> { + if (!bin.isSuperCompost && bin.isFinished && !bin.isClosed) { + animate(player, compostPotionAnimation) + submitIndividualPulse(player, object : Pulse(compostPotionAnimation.duration) { override fun pulse(): Boolean { - if(player.inventory.remove(usedNode.asItem())) { + if (removeItem(player, usedNode.asItem())) { bin.convert() - player.inventory.add(Item(used.getNext())) + addItem(player, used.getNext()) } return true } }) } else { - player.dialogueInterpreter.sendDialogue("You can only do this with an open bin of","finished regular compost.") + sendDialogue(player, "You can only do this with an open bin of finished regular compost.") } } Items.BUCKET_1925 -> { - if(bin.isFinished && !bin.isClosed){ - player.pulseManager.run(object : Pulse(scoopAnimation.duration){ + if (bin.isFinished && !bin.isClosed) { + submitIndividualPulse(player, object : Pulse(scoopAnimation.duration) { override fun pulse(): Boolean { - if(!player.inventory.containsItem(usedNode.asItem())) return true - player.animator.animate(scoopAnimation) + if (!player.inventory.containsItem(usedNode.asItem())) return true + animate(player, scoopAnimation) val item = bin.takeItem() - if(item != null && player.inventory.remove(usedNode.asItem())){ + if (item != null && removeItem(player, usedNode.asItem())) { player.inventory.add(item) } return item == null || !player.inventory.containsItem(usedNode.asItem()) } }) } else { - player.dialogueInterpreter.sendDialogue("You can only scoop an opened bin of finished compost.") + sendDialogue(player, "You can only scoop an opened bin of finished compost.") } } else -> - if(bin.isFull()){ - player.sendMessage("This compost bin is already full.") + if (bin.isFull()) { + sendMessage(player, "This compost bin is already full.") return@onUseWith true } else if (!bin.isFinished) { - player.pulseManager.run(object : Pulse(fillAnim.duration){ + submitIndividualPulse(player, object : Pulse(fillAnim.duration) { override fun pulse(): Boolean { - player.animator.animate(fillAnim) - if(player.inventory.remove(usedNode.asItem())){ + animate(player, fillAnim) + if (removeItem(player, usedNode.asItem())) { bin.addItem(usedNode.asItem()) } return bin.isFull() || player.inventory.getAmount(usedNode.asItem()) == 0 } }) } else { - sendMessage (player, "You should empty the remaining compost first.") + sendDialogue(player, "The compost bin must be empty of compost before you can put new items in it.") } } return@onUseWith true @@ -84,8 +83,8 @@ class UseWithBinHandler : InteractionListener { } fun loadNodes() { - for(p in Plantable.values()){ - if(p.harvestItem != Items.SCARECROW_6059) { + for (p in Plantable.values()) { + if (p.harvestItem != Items.SCARECROW_6059) { allowedNodes.add(p.harvestItem) } } @@ -98,8 +97,8 @@ class UseWithBinHandler : InteractionListener { allowedNodes.add(Items.BUCKET_1925) } - private fun Int.getNext(): Int{ - if(this != 6476) return this + 2 + private fun Int.getNext(): Int { + if (this != 6476) return this + 2 else return Items.VIAL_229 } } diff --git a/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt b/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt index a263f9812..d71a7c409 100644 --- a/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt +++ b/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt @@ -9,6 +9,9 @@ import core.game.world.update.flag.context.Animation import org.rs09.consts.Items import core.game.interaction.IntType import core.game.interaction.InteractionListener +import core.game.interaction.QueueStrength +import core.tools.StringUtils +import core.tools.prependArticle import org.rs09.consts.Sounds class UseWithPatchHandler : InteractionListener { @@ -39,55 +42,83 @@ class UseWithPatchHandler : InteractionListener { } player.faceLocation(with.location) - when(usedItem.id){ + when (usedItem.id) { RAKE -> PatchRaker.rake(player,patch) - SEED_DIBBER -> player.sendMessage("I should plant a seed, not the seed dibber.") - SPADE -> player.dialogueInterpreter.open(67984003,patch.getPatchFor(player)) //DigUpPatchDialogue.kt + SEED_DIBBER -> sendMessage(player, "I should plant a seed, not the seed dibber.") + SPADE -> { + val anim = getAnimation(830) + val p = patch.getPatchFor(player) + if (p.isDead) { + sendMessage(player, "You start digging the farming patch...") + queueScript(player, 0, QueueStrength.WEAK) { stage: Int -> + when (stage) { + 0 -> { + animate(player, anim) + playAudio(player, Sounds.DIGSPADE_1470) + return@queueScript delayScript(player,anim.duration + 2) + } + 1 -> { + animate(player, anim) + playAudio(player, Sounds.DIGSPADE_1470) + return@queueScript delayScript(player, anim.duration + 1) + } + 2 -> { + p.clear() + sendMessage(player, "You have successfully cleared this patch for new crops.") + return@queueScript stopExecuting(player) + } + else -> return@queueScript stopExecuting(player) + } + } + } else { + openDialogue(player, 67984003, patch.getPatchFor(player)) // DigUpPatchDialogue.kt + } + } SECATEURS, MAGIC_SECATEURS -> { val p = patch.getPatchFor(player) - if(patch.type == PatchType.TREE) { - if(p.isDiseased && !p.isDead) { - player.pulseManager.run(object: Pulse(){ + if (patch.type == PatchType.TREE_PATCH) { + if (p.isDiseased && !p.isDead) { + submitIndividualPulse(player, object: Pulse() { override fun pulse(): Boolean { - if (usedItem.id == SECATEURS ) player.animator.animate(secateursTreeAnim) else player.animator.animate(magicSecateursTreeAnim) + if (usedItem.id == SECATEURS) animate(player, secateursTreeAnim) else animate(player, magicSecateursTreeAnim) p.cureDisease() return true } }) - } else if(p.plantable == Plantable.WILLOW_SAPLING && p.harvestAmt > 0) { + } else if (p.plantable == Plantable.WILLOW_SAPLING && p.harvestAmt > 0) { val pulse = CropHarvester.harvestPulse(player, with, Items.WILLOW_BRANCH_5933) ?: return@onUseWith false - player.pulseManager.run(pulse) + submitIndividualPulse(player, pulse) } } } TROWEL, Items.PLANT_POT_5350 -> { - if(!player.inventory.containsAtLeastOneItem(TROWEL)) { - player.sendMessage("You need a trowel to fill plant pots with dirt.") + if (!inInventory(player, TROWEL)) { + sendMessage(player, "You need a trowel to fill plant pots with dirt.") return@onUseWith true } val p = patch.getPatchFor(player) - if(!p.isWeedy()){ - player.sendMessage("This patch has something growing in it.") + if (!p.isWeedy() && !p.isEmptyAndWeeded()) { + sendMessage(player, "This patch has something growing in it.") return@onUseWith true - } else if (p.currentGrowthStage != 3){ - player.sendMessage("I should clear this of weeds before trying to take some dirt.") + } else if (p.currentGrowthStage != 3) { + sendMessage(player, "I should clear this of weeds before trying to take some dirt.") return@onUseWith true } - val potAmount = player.inventory.getAmount(Items.PLANT_POT_5350) + val potAmount = amountInInventory(player, Items.PLANT_POT_5350) - if(potAmount == 0){ - player.sendMessage("You have no plant pots to fill.") + if (potAmount == 0) { + sendMessage(player, "You have no plant pots to fill.") return@onUseWith true } val anim = Animation(2272) - player.pulseManager.run(object : Pulse(anim.duration){ + submitIndividualPulse(player, object : Pulse(anim.duration) { override fun pulse(): Boolean { - if(player.inventory.remove(Item(Items.PLANT_POT_5350))){ - player.animator.animate(anim) - player.inventory.add(Item(Items.PLANT_POT_5354)) + if (removeItem(player, Items.PLANT_POT_5350)) { + animate(player, anim) + addItem(player, Items.PLANT_POT_5354) } else return true return false } @@ -96,37 +127,52 @@ class UseWithPatchHandler : InteractionListener { Items.PLANT_CURE_6036 -> { val p = patch.getPatchFor(player) - if(p.isDiseased && !p.isDead){ - player.pulseManager.run(object: Pulse(){ - override fun pulse(): Boolean { - player.animator.animate(plantCureAnim) - playAudio(player, Sounds.FARMING_PLANTCURE_2438) - if(player.inventory.remove(usedItem)){ - player.inventory.add(Item(Items.VIAL_229)) - p.cureDisease() + val patchName = p.patch.type.displayName() + if (p.isDiseased && !p.isDead) { + sendMessage(player, "You treat the $patchName with the plant cure.") + queueScript(player, 0, QueueStrength.WEAK) { stage: Int -> + when (stage) { + 0 -> { + animate(player, plantCureAnim) + playAudio(player, Sounds.FARMING_PLANTCURE_2438) + return@queueScript delayScript(player, plantCureAnim.duration / 2) } - return true + 1 -> { + if (removeItem(player, usedItem)) { + addItem(player, Items.VIAL_229) + p.cureDisease() + sendMessage(player, "It is restored to health.") + } + return@queueScript stopExecuting(player) + } + else -> return@queueScript stopExecuting(player) } - }) + } } else { - player.sendMessage("I have no reason to do this right now.") + sendMessage(player, "I have no reason to do this right now.") } } - Items.WATERING_CAN1_5333,Items.WATERING_CAN2_5334,Items.WATERING_CAN3_5335,Items.WATERING_CAN4_5336,Items.WATERING_CAN5_5337,Items.WATERING_CAN6_5338,Items.WATERING_CAN7_5339,Items.WATERING_CAN8_5340 -> { + Items.WATERING_CAN_5331,Items.WATERING_CAN1_5333,Items.WATERING_CAN2_5334,Items.WATERING_CAN3_5335,Items.WATERING_CAN4_5336,Items.WATERING_CAN5_5337,Items.WATERING_CAN6_5338,Items.WATERING_CAN7_5339,Items.WATERING_CAN8_5340 -> { val p = patch.getPatchFor(player) val t = p.patch.type - if(!p.isWatered && p.plantable != Plantable.SCARECROW && (t == PatchType.ALLOTMENT || t == PatchType.FLOWER || t == PatchType.HOPS) && !p.isGrown()){ - player.pulseManager.run(object : Pulse(){ + if (p.isWatered || p.isEmptyAndWeeded() || p.isGrown() || p.plantable == Plantable.SCARECROW) { + sendMessage(player, "This patch doesn't need watering.") + } else if (t == PatchType.ALLOTMENT || t == PatchType.FLOWER_PATCH || t == PatchType.HOPS_PATCH) { + submitIndividualPulse(player, object : Pulse() { override fun pulse(): Boolean { - if(p.isWeedy()){ - player.sendMessage("You should grow something first.") + if (p.isWeedy()) { + sendMessage(player, "You should grow something first.") return true } - player.animator.animate(wateringCanAnim) + if (usedItem.id == Items.WATERING_CAN_5331) { + sendMessage(player, "You need to fill the watering can first.") + return true + } + animate(player, wateringCanAnim) playAudio(player, Sounds.FARMING_WATERING_2446) - if(player.inventory.remove(usedItem)){ - player.inventory.add(Item(usedItem.id.getNext())) + if (removeItem(player, usedItem)) { + addItem(player, usedItem.id.getNext()) p.water() } return true @@ -137,89 +183,107 @@ class UseWithPatchHandler : InteractionListener { Items.SUPERCOMPOST_6034, Items.COMPOST_6032 -> { val p = patch.getPatchFor(player) - if(p.compost == CompostType.NONE) { - player.animator.animate(pourBucketAnim) + val patchName = p.patch.type.displayName() + + if (!p.isEmptyAndWeeded()) { + sendMessage(player, "This patch needs to be empty and weeded to do that.") + } else if (p.compost == CompostType.NONE) { + animate(player, pourBucketAnim) playAudio(player, Sounds.FARMING_COMPOST_2427) - player.pulseManager.run(object : Pulse(){ - override fun pulse(): Boolean { - if(player.inventory.remove(usedItem,false)){ - p.compost = if(usedItem.id == Items.SUPERCOMPOST_6034) CompostType.SUPER else CompostType.NORMAL - if(p.compost == CompostType.SUPER) rewardXP(player, Skills.FARMING, 26.0) else rewardXP(player, Skills.FARMING, 18.5) - if(p.plantable != null && p.plantable?.applicablePatch != PatchType.FLOWER) { - p.harvestAmt += if(p.compost == CompostType.NORMAL) 1 else if(p.compost == CompostType.SUPER) 2 else 0 - } - p.cropLives += if(p.compost == CompostType.SUPER) 2 else 1 - player.inventory.add(Item(Items.BUCKET_1925)) + runTask(player) { + if (player.inventory.remove(usedItem,false)) { + sendMessage(player, "You treat the $patchName with ${usedItem.name.lowercase()}.") + p.compost = if (usedItem.id == Items.SUPERCOMPOST_6034) CompostType.SUPERCOMPOST else CompostType.COMPOST + if (p.compost == CompostType.SUPERCOMPOST) rewardXP(player, Skills.FARMING, 26.0) else rewardXP(player, Skills.FARMING, 18.5) + if (p.plantable != null && p.plantable?.applicablePatch != PatchType.FLOWER_PATCH) { + p.harvestAmt += if (p.compost == CompostType.COMPOST) 1 else if (p.compost == CompostType.SUPERCOMPOST) 2 else 0 } - return true + p.cropLives += if (p.compost == CompostType.SUPERCOMPOST) 2 else 1 + addItem(player, Items.BUCKET_1925) } - }) + return@runTask + } } else { - player.sendMessage("This patch has already been treated with compost.") + sendMessage(player, "This $patchName has already been treated with ${p.compost.name.lowercase()}.") } } else -> { val plantable = Plantable.forItemID(usedItem.id) ?: return@onUseWith false - if(plantable.applicablePatch != patch.type){ - player.sendMessage("You can't plant that seed in this patch.") + if (plantable.applicablePatch != patch.type) { + val seedNamePlural = StringUtils.plusS(plantable.name.replace("_", " ").lowercase()) + val patchType = if (plantable.applicablePatch == PatchType.ALLOTMENT) "a vegetable patch" else prependArticle(plantable.applicablePatch.displayName()) + sendMessage(player, "You can only plant $seedNamePlural in $patchType.") return@onUseWith true } - if(plantable.requiredLevel > player.skills.getLevel(Skills.FARMING)){ - player.sendMessage("You need a Farming level of ${plantable.requiredLevel} to plant this.") + if (!hasLevelDyn(player, Skills.FARMING, plantable.requiredLevel)) { + sendMessage(player, "You need a Farming level of ${plantable.requiredLevel} to plant this.") return@onUseWith true } val p = patch.getPatchFor(player) - if(p.getCurrentState() < 3 && p.isWeedy()){ - player.sendMessage("You must weed your patch before you can plant a seed in it.") + if (p.getCurrentState() < 3 && p.isWeedy() && plantable != Plantable.SCARECROW) { + sendMessage(player, "This patch needs weeding first.") return@onUseWith true - } else if(p.getCurrentState() > 3){ - player.sendMessage("There is already something growing in this patch.") + } else if (p.getCurrentState() > 3) { + sendMessage(player, "There is already something growing in this patch.") return@onUseWith true } val plantItem = - if(patch.type == PatchType.ALLOTMENT) Item(plantable.itemID,3) else if(patch.type == PatchType.HOPS){ - if(plantable == Plantable.JUTE_SEED) Item(plantable.itemID,3) else Item(plantable.itemID,4) + if (patch.type == PatchType.ALLOTMENT) Item(plantable.itemID,3) else if (patch.type == PatchType.HOPS_PATCH) { + if (plantable == Plantable.JUTE_SEED) Item(plantable.itemID,3) else Item(plantable.itemID,4) } else { Item(plantable.itemID,1) } - if(patch.type == PatchType.ALLOTMENT){ - if(!player.inventory.containsItem(plantItem)){ - player.sendMessage("You need 3 seeds to plant an allotment patch.") + if (patch.type == PatchType.ALLOTMENT) { + if (!player.inventory.containsItem(plantItem)) { + sendMessage(player, "You need 3 seeds to plant an allotment patch.") return@onUseWith true } } - if(patch.type != PatchType.FRUIT_TREE && patch.type != PatchType.TREE){ - if(!player.inventory.contains(Items.SEED_DIBBER_5343,1)){ - player.sendMessage("You need a seed dibber to plant that.") + if (patch.type != PatchType.FRUIT_TREE_PATCH && patch.type != PatchType.TREE_PATCH) { + if (!inInventory(player, Items.SEED_DIBBER_5343)) { + sendMessage(player, "You need a seed dibber to plant that.") return@onUseWith true } } else { - if(!player.inventory.contains(Items.SPADE_952,1)){ - player.sendMessage("You need a spade to plant that.") + if (!inInventory(player, Items.SPADE_952) && plantable != Plantable.SCARECROW) { + sendMessage(player, "You need a spade to plant that.") return@onUseWith true } } player.lock() - if(player.inventory.remove(plantItem)) { - player.animator.animate(Animation(2291)) - playAudio(player, Sounds.FARMING_DIBBING_2432) - player.pulseManager.run(object : Pulse(3) { + if (removeItem(player, plantItem)) { + if (plantable != Plantable.SCARECROW) { + animate(player, 2291) + playAudio(player, Sounds.FARMING_DIBBING_2432) + } + val delay = if (plantable == Plantable.SCARECROW) 0 else 3 + submitIndividualPulse(player, object : Pulse(delay) { override fun pulse(): Boolean { - if(plantable == Plantable.JUTE_SEED && patch == FarmingPatch.MCGRUBOR_HOPS && !player.achievementDiaryManager.hasCompletedTask(DiaryType.SEERS_VILLAGE,0,7)){ - player.achievementDiaryManager.finishTask(player,DiaryType.SEERS_VILLAGE,0,7) + if (plantable == Plantable.JUTE_SEED && patch == FarmingPatch.MCGRUBOR_HOPS && !player.achievementDiaryManager.hasCompletedTask(DiaryType.SEERS_VILLAGE, 0, 7)) { + player.achievementDiaryManager.finishTask(player, DiaryType.SEERS_VILLAGE, 0, 7) } p.plant(plantable) - player.skills.addExperience(Skills.FARMING, plantable.plantingXP) + rewardXP(player, Skills.FARMING, plantable.plantingXP) p.setNewHarvestAmount() - if(p.patch.type == PatchType.TREE || p.patch.type == PatchType.FRUIT_TREE){ - player.inventory.add(Item(Items.PLANT_POT_5350)) + if (p.patch.type == PatchType.TREE_PATCH || p.patch.type == PatchType.FRUIT_TREE_PATCH) { + addItem(player, Items.PLANT_POT_5350) } + + val itemAmount = if (plantItem.amount == 1) "a" else plantItem.amount + val itemName = if (plantItem.amount == 1) getItemName(plantItem.id).lowercase() else StringUtils.plusS(getItemName(plantItem.id).lowercase()) + val patchName = p.patch.type.displayName() + if (plantable == Plantable.SCARECROW) { + sendMessage(player, "You place the scarecrow in the $patchName.") + } else { + sendMessage(player, "You plant $itemAmount $itemName in the $patchName.") + } + player.unlock() return true } @@ -232,15 +296,37 @@ class UseWithPatchHandler : InteractionListener { } } - fun loadNodes(){ - for(p in Plantable.values()){ + fun loadNodes() { + for (p in Plantable.values()) { allowedNodes.add(p.itemID) } - allowedNodes.addAll(arrayListOf(RAKE,SEED_DIBBER,SPADE,SECATEURS,MAGIC_SECATEURS,TROWEL,Items.SUPERCOMPOST_6034,Items.COMPOST_6032,Items.PLANT_CURE_6036,Items.WATERING_CAN1_5333,Items.WATERING_CAN2_5334,Items.WATERING_CAN3_5335,Items.WATERING_CAN4_5336,Items.WATERING_CAN5_5337,Items.WATERING_CAN6_5338,Items.WATERING_CAN7_5339,Items.WATERING_CAN8_5340, Items.PLANT_POT_5350)) + allowedNodes.addAll( + arrayListOf( + RAKE, + SEED_DIBBER, + SPADE, + SECATEURS, + MAGIC_SECATEURS, + TROWEL, + Items.SUPERCOMPOST_6034, + Items.COMPOST_6032, + Items.PLANT_CURE_6036, + Items.WATERING_CAN_5331, + Items.WATERING_CAN1_5333, + Items.WATERING_CAN2_5334, + Items.WATERING_CAN3_5335, + Items.WATERING_CAN4_5336, + Items.WATERING_CAN5_5337, + Items.WATERING_CAN6_5338, + Items.WATERING_CAN7_5339, + Items.WATERING_CAN8_5340, + Items.PLANT_POT_5350 + ) + ) } private fun Int.getNext(): Int { - if(this == Items.WATERING_CAN1_5333) return Items.WATERING_CAN_5331 + if (this == Items.WATERING_CAN1_5333) return Items.WATERING_CAN_5331 else return this - 1 } } diff --git a/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt b/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt index a64559511..ae3765a99 100644 --- a/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt +++ b/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt @@ -1,6 +1,5 @@ package content.global.skill.farming.timers -import core.api.* import core.tools.* import core.game.system.timer.* import org.json.simple.* @@ -58,12 +57,12 @@ class CropGrowth : PersistTimer (500, "farming:crops", isSoft = true) { private fun runOfflineCatchupLogic() { for ((_, patch) in patchMap) { val type = patch.patch.type - val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE && patch.getFruitOrBerryCount() < 6) + val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH_PATCH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE_PATCH && patch.getFruitOrBerryCount() < 6) if(shouldPlayCatchup && patch.plantable != null && !patch.isDead){ var stagesToSimulate = if (!patch.isGrown()) patch.plantable!!.stages - patch.currentGrowthStage else 0 - if (type == PatchType.BUSH) + if (type == PatchType.BUSH_PATCH) stagesToSimulate += Math.min(4, 4 - patch.getFruitOrBerryCount()) - if (type == PatchType.FRUIT_TREE) + if (type == PatchType.FRUIT_TREE_PATCH) stagesToSimulate += Math.min(6, 6 - patch.getFruitOrBerryCount()) val nowTime = System.currentTimeMillis() diff --git a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt index d6da6f78b..6ed1cfebc 100644 --- a/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt +++ b/Server/src/main/content/global/skill/magic/lunar/LunarListeners.kt @@ -328,7 +328,7 @@ class LunarListeners : SpellListener("lunar"), Commands { return } val patch = fPatch.getPatchFor(player) - if(!patch.isDiseased && !patch.isWeedy()){ + if(!patch.isDiseased && !patch.isWeedy() && !patch.isEmptyAndWeeded()){ sendMessage(player, "It is growing just fine.") return } @@ -642,7 +642,7 @@ class LunarListeners : SpellListener("lunar"), Commands { animate(player, Animations.LUNAR_SPELLBOOK_FERTILE_SOIL_4413) sendGraphics(Graphics.LUNAR_SPELLBOOK_FERTILE_SOIL_724, target.location) playGlobalAudio(target.location, Sounds.LUNAR_FERTILIZE_2891) - patch.compost = CompostType.SUPER + patch.compost = CompostType.SUPERCOMPOST sendMessage(player, "You fertilize the soil.") addXP(player, 87.0) } diff --git a/Server/src/main/content/global/skill/skillcapeperks/SkillcapePerks.kt b/Server/src/main/content/global/skill/skillcapeperks/SkillcapePerks.kt index cedd5e78b..7ee273098 100644 --- a/Server/src/main/content/global/skill/skillcapeperks/SkillcapePerks.kt +++ b/Server/src/main/content/global/skill/skillcapeperks/SkillcapePerks.kt @@ -16,7 +16,6 @@ import core.ServerStore.Companion.getInt import core.api.* import core.cache.def.impl.ItemDefinition import org.rs09.consts.Items -import org.rs09.consts.Sounds enum class SkillcapePerks(val attribute: String, val effect: ((Player) -> Unit)? = null) { BAREFISTED_SMITHING("cape_perks:barefisted-smithing"), @@ -59,7 +58,7 @@ enum class SkillcapePerks(val attribute: String, val effect: ((Player) -> Unit)? val possibleSeeds = Plantable.values() for(i in 0 until 10){ var seed = possibleSeeds.random() - while(seed == Plantable.SCARECROW || seed.applicablePatch == PatchType.FRUIT_TREE || seed.applicablePatch == PatchType.TREE || seed.applicablePatch == PatchType.SPIRIT_TREE){ + while(seed == Plantable.SCARECROW || seed.applicablePatch == PatchType.FRUIT_TREE_PATCH || seed.applicablePatch == PatchType.TREE_PATCH || seed.applicablePatch == PatchType.SPIRIT_TREE_PATCH){ seed = possibleSeeds.random() } val reward = core.game.node.item.Item(seed.itemID) diff --git a/Server/src/main/content/global/skill/summoning/familiar/GiantEntNPC.java b/Server/src/main/content/global/skill/summoning/familiar/GiantEntNPC.java index a55bd3fa5..5ed4db98e 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/GiantEntNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/GiantEntNPC.java @@ -77,10 +77,10 @@ public class GiantEntNPC extends Forager { public void modifyFarmingReward(FarmingPatch fPatch, Item reward) { PatchType patchType = fPatch.getType(); - if(patchType == PatchType.FRUIT_TREE || - patchType == PatchType.BUSH || - patchType == PatchType.BELLADONNA || - patchType == PatchType.CACTUS) { + if(patchType == PatchType.FRUIT_TREE_PATCH || + patchType == PatchType.BUSH_PATCH || + patchType == PatchType.BELLADONNA_PATCH || + patchType == PatchType.CACTUS_PATCH) { if(RandomFunction.roll(2)) { reward.setAmount(2 * reward.getAmount()); } diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 78122a7da..f79e89ba7 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -767,10 +767,15 @@ fun emote(entity: Entity, emote: Emotes) { /** * Sends a message to the given player. + * + * The message will be split on word boundaries into multiple lines so + * that none of the lines will overflow the player's message box. + * * @param player the player to send the message to. + * @param message the message to send. */ fun sendMessage(player: Player, message: String) { - player.sendMessage(message) + player.sendMessages(*splitLines(message, 86)) } /** diff --git a/Server/src/main/core/api/DialUtils.kt b/Server/src/main/core/api/DialUtils.kt index cc59185be..1149906cd 100644 --- a/Server/src/main/core/api/DialUtils.kt +++ b/Server/src/main/core/api/DialUtils.kt @@ -2,12 +2,20 @@ package core.api import java.util.* import kotlin.math.ceil +object DialUtils { + val tagRegex = "<([A-Za-z0-9=/]+)>".toRegex() + + fun removeMatches(message: String, regex: Regex): String { + return regex.replace(message, "") + } +} + /** * Automatically split a single continuous string into multiple comma-separated lines. * Should this not work out for any reason, you should fallback to standard npc and player methods for dialogue. */ -fun splitLines(message: String, perLineLimit: Int = 54) : Array { - var lines = Array(ceil(message.length / perLineLimit.toFloat()).toInt()) {""} +fun splitLines(message: String, perLineLimit: Int = 54): Array { + var lines = Array(ceil(DialUtils.removeMatches(message, DialUtils.tagRegex).length / perLineLimit.toFloat()).toInt()) { "" } //short circuit when possible because it's cheaper. if (lines.size == 1) { @@ -20,8 +28,28 @@ fun splitLines(message: String, perLineLimit: Int = 54) : Array { val line = StringBuilder() var accumulator = 0 + val openTags = LinkedList() + fun pushLine() { if (line.isEmpty()) return + + // find all tags that were opened or closed in the line + for (lineTag in DialUtils.tagRegex.findAll(line)) { + if (lineTag.value.get(1) == '/') { + // closing tag encountered; remove it from the list of open tags + for (openTag in openTags.descendingIterator()) { + val lineTagName = lineTag.value.substring(2, lineTag.value.length - 1) + val openTagName = openTag.substring(1, lineTag.value.length - 2) + if (lineTagName == openTagName) { + openTags.remove(openTag) + break + } + } + } else { + openTags.add(lineTag.value) + } + } + //allow array to be resized - there are specific edgecases where it becomes necessary. (Check the unit test for example) if (lines.size == index) lines = lines.plus(line.toString()) @@ -30,11 +58,15 @@ fun splitLines(message: String, perLineLimit: Int = 54) : Array { index++ line.clear() accumulator = 0 + + // if any unclosed tags remain, add them to the beginning of the new line + for (tag in openTags) line.append(tag) + openTags.clear() } while (!tokenQueue.isEmpty()) { - val shouldSpace = line.isNotEmpty() - accumulator += tokenQueue.peek().length + val shouldSpace = DialUtils.removeMatches(line.toString(), DialUtils.tagRegex).isNotEmpty() + accumulator += DialUtils.removeMatches(tokenQueue.peek(), DialUtils.tagRegex).length if (shouldSpace) accumulator += 1 if (accumulator > perLineLimit) { @@ -49,10 +81,10 @@ fun splitLines(message: String, perLineLimit: Int = 54) : Array { pushLine() // If there's 5 lines, merge lines 4 and 5 into line 4. - if (lines.size > 4){ + if (lines.size > 4) { lines[3] = lines[3] + "
" + lines[4] lines = lines.sliceArray(0..3) } return lines -} \ No newline at end of file +}