diff --git a/Server/src/main/content/global/handlers/npc/SheepBehavior.kt b/Server/src/main/content/global/handlers/npc/SheepBehavior.kt new file mode 100644 index 000000000..d71d9b169 --- /dev/null +++ b/Server/src/main/content/global/handlers/npc/SheepBehavior.kt @@ -0,0 +1,119 @@ +package content.global.handlers.npc + +import content.region.misthalin.lumbridge.quest.sheepshearer.SheepShearer.Companion.ATTR_IS_PENGUIN_SHEEP_SHEARED +import core.api.* +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.combat.DeathTask +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.game.node.entity.player.link.audio.Audio +import core.game.system.task.Pulse +import core.game.world.GameWorld +import core.game.world.update.flag.context.Animation +import core.tools.RandomFunction +import org.rs09.consts.Items +import org.rs09.consts.NPCs +import org.rs09.consts.Sounds + +private val sheepIds = intArrayOf( + NPCs.SHEEP_42, + NPCs.SHEEP_43, + NPCs.GOLDEN_SHEEP_1271, + NPCs.GOLDEN_SHEEP_1272, + NPCs.SHEEP_1529, + NPCs.SHEEP_1762, + NPCs.SHEEP_1763, + NPCs.SHEEP_1764, + NPCs.SHEEP_1765, + NPCs.SICK_LOOKING_SHEEP_1_2377, + NPCs.SICK_LOOKING_SHEEP_2_2378, + NPCs.SICK_LOOKING_SHEEP_3_2379, + NPCs.SICK_LOOKING_SHEEP_4_2380, + NPCs.SHEEP_3310, + NPCs.SHEEP_3311, + NPCs.SHEEP_3579, + NPCs.SHEEP_5148, + NPCs.SHEEP_5149, + NPCs.SHEEP_5150, + NPCs.SHEEP_5151, + NPCs.SHEEP_5152, + NPCs.SHEEP_5153, + NPCs.SHEEP_5154, + NPCs.SHEEP_5155, + NPCs.SHEEP_5156, + NPCs.SHEEP_5157, + NPCs.SHEEP_5158, + NPCs.SHEEP_5159, + NPCs.SHEEP_5160, + NPCs.SHEEP_5161, + NPCs.SHEEP_5162, + NPCs.SHEEP_5163, + NPCs.SHEEP_5164, + NPCs.SHEEP_5165, + NPCs.GOLDEN_SHEEP_5172, + NPCs.GOLDEN_SHEEP_5173 +) + +class SheepBehavior : NPCBehavior(*sheepIds), InteractionListener { + override fun tick(self: NPC): Boolean { + if (self.properties.combatPulse.isAttacking || DeathTask.isDead(self)) { + return true + } + if (RandomFunction.random(35) == 5) { + sendChat(self, "Baa!") + } + + return true + } + + override fun defineListeners() { + on(IntType.NPC, "shear") { player, node -> + val sheep = node as NPC + if (sheep.id == NPCs.SHEEP_3579) { + if (player.questRepository.getQuest("Sheep Shearer").isStarted(player)) { + setAttribute(player, ATTR_IS_PENGUIN_SHEEP_SHEARED, true) + } + animate(player, Animation(893)) + playAudio(player, Audio(Sounds.PENGUINSHEEP_ESCAPE_686), false) + sendMessage(player, "The... whatever it is... manages to get away from you!") + animate(sheep, Animation(3570)) + sheep.moveStep() + return@on true + } + if (!inInventory(player, Items.SHEARS_1735)) { + sendMessage(player, "You need shears to shear a sheep.") + return@on true + } + if (hasOption(sheep, "attack")) { + sendMessage(player, "That one looks a little too violent to shear...") + return@on true + } + if (freeSlots(player) == 0) { + sendMessage(player, "You don't have enough space in your inventory to carry any wool you would shear.") + return@on true + } + lock(sheep, 3) + stopWalk(sheep) + animate(player, Animation(893)) + val random = RandomFunction.random(1, 5) + if (random != 4) { + sheep.locks.lockMovement(2) + sheep.transform(NPCs.SHEEP_5153) + playAudio(player, Audio(Sounds.SHEAR_SHEEP_761), false) + sendMessage(player, "You get some wool.") + addItem(player, Items.WOOL_1737) // 5160 + GameWorld.Pulser.submit(object : Pulse(80, sheep) { + override fun pulse(): Boolean { + sheep.reTransform() + return true + } + }) + } else { + sendMessage(player, "The sheep manages to get away from you!") + sheep.moveStep() + } + return@on true + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/handlers/npc/SheepNPC.java b/Server/src/main/content/global/handlers/npc/SheepNPC.java deleted file mode 100644 index ef9003540..000000000 --- a/Server/src/main/content/global/handlers/npc/SheepNPC.java +++ /dev/null @@ -1,59 +0,0 @@ -package content.global.handlers.npc; - -import core.game.node.entity.combat.DeathTask; -import core.game.node.entity.npc.AbstractNPC; -import core.game.world.map.Location; -import core.plugin.Initializable; -import core.tools.RandomFunction; - -/** - * Handles the sheep npc's. - * @author 'Vexia - */ -@Initializable -public class SheepNPC extends AbstractNPC { - - /** - * The NPC ids of NPCs using this plugin. - */ - private static final int[] ID = { 42, 43, 1271, 1272, 1529, 1762, 1763, 1764, 1765, 2377, 2378, 2379, 2380, 3310, 3311, 3579, 5148, 5149, 5150, 5151, 5152, 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5163, 5164, 5165, 5172, 5173 }; - - /** - * Constructs a new {@code AlKharidWarriorPlugin} {@code Object}. - */ - public SheepNPC() { - super(0, null); - } - - /** - * Constructs a new {@code AlKharidWarriorPlugin} {@code Object}. - * @param id The NPC id. - * @param location The location. - */ - private SheepNPC(int id, Location location) { - super(id, location); - } - - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new SheepNPC(id, location); - } - - @Override - public void tick() { - if (getProperties().getCombatPulse().isAttacking() || DeathTask.isDead(this)) { - super.tick(); - return; - } - if (RandomFunction.random(35) == 5) { - sendChat("Baa!"); - } - super.tick(); - } - - @Override - public int[] getIds() { - return ID; - } - -} diff --git a/Server/src/main/content/region/misthalin/lumbridge/dialogue/FredTheFarmer.java b/Server/src/main/content/region/misthalin/lumbridge/dialogue/FredTheFarmer.java deleted file mode 100644 index 890c64800..000000000 --- a/Server/src/main/content/region/misthalin/lumbridge/dialogue/FredTheFarmer.java +++ /dev/null @@ -1,374 +0,0 @@ -package content.region.misthalin.lumbridge.dialogue; - -import core.game.dialogue.DialoguePlugin; -import core.game.dialogue.FacialExpression; -import core.game.node.entity.npc.NPC; -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.quest.Quest; - -import core.plugin.Initializable; -import content.region.misthalin.lumbridge.quest.sheepshearer.SheepShearer; - -/** - * Represents the dialogue plugin used for fred the farmer npc. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class FredTheFarmer extends DialoguePlugin { - - /** - * Represents the quest instance. - */ - private Quest quest; - - /** - * Constructs a new {@code FredTheFarmer} {@code Object}. - */ - public FredTheFarmer() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code FredTheFarmer} {@code Object}. - * @param player the player. - */ - public FredTheFarmer(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new FredTheFarmer(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - quest = player.getQuestRepository().getQuest("Sheep Shearer"); - if (player.getQuestRepository().getQuest("Sheep Shearer").getStage(player) == 10 || player.getQuestRepository().getQuest("Sheep Shearer").getStage(player) == 90) { - if (SheepShearer.getWoolGiven(player) == 20 && player.getQuestRepository().getQuest("Sheep Shearer").getStage(player) == 90) { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That's the last of them."); - stage = 999; - return true; - } - if (player.getInventory().contains(1737, 1) || player.getInventory().contains(1759, 1)) { - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "What are you doing on my land?"); - stage = 5000; - return true; - } - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "How are you doing getting those balls of wool?"); - stage = 4000; - return true; - } - - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "What are you doing on my land? You're not the one", "who keeps leaving all my gates open and letting out all", "my sheep are you?"); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - quest = player.getQuestRepository().getQuest("Sheep Shearer"); - switch (stage) { - case 0: - if (!player.getQuestRepository().isComplete("Sheep Shearer")) { - interpreter.sendOptions("Select an Option", "I'm looking for a quest.", "I'm looking for something to kill.", "I'm lost."); - stage = 1; - } else { - interpreter.sendOptions("Select an Option", "I'm looking for something to kill.", "I'm lost."); - stage = 346; - } - break; - case 346: - switch (buttonId) { - case 1: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm looking for something to kill."); - stage = 20; - break; - case 2: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm lost."); - stage = 30; - break; - } - break; - case 1: - switch (buttonId) { - case 1: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm looking for a quest."); - stage = 10; - break; - case 2: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm looking for something to kill."); - stage = 20; - break; - case 3: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm lost."); - stage = 30; - break; - - } - break; - case 30: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "How can you be lost? Just follow the road east and", "south. You'll end up in Lumbridge fairly quickly."); - stage = 31; - break; - case 31: - end(); - break; - case 10: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You're after a quest, you say? Actually I could do with", "a bit of help."); - stage = 11; - break; - case 11: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "My sheep are getting mighty woolly. I'd be much", "obliged if you could shear them. And while you're at it", "spin the wool for me too."); - stage = 12; - break; - case 12: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Yes, that's it. Bring me 20 balls of wool. And I'm sure", "I could sort out somesort of payment. Of course,", "there's a small matter of The Thing."); - stage = 13; - break; - case 13: - interpreter.sendOptions("Select an Option", "Yes okay. I can do that.", "That doesn't sound a very exiting quest.", "What do you mean, The Thing?"); - stage = 14; - break; - case 14: - switch (buttonId) { - case 1: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Yes okay. I can do that."); - stage = 670; - break; - case 2: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That doesn't sound a very exiting quest."); - stage = 560; - break; - case 3: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What do you mean, The Thing?"); - stage = 456; - break; - } - break; - case 670: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Good! Now one more thing, do you actually know how", "to shear a sheep?"); - stage = 678; - break; - case 678: - interpreter.sendOptions("Select an Option", "Of course!", "No, I don't know actually."); - stage = 679; - break; - case 679: - switch (buttonId) { - case 1: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Of course!"); - stage = 954; - break; - case 2: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Err. No, I don't know actually."); - stage = 750; - break; - } - break; - case 954: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Do you know how to spin wool?"); - stage = 754; - break; - case 750: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Just use a set of shears on a sheep to shear it."); - stage = 751; - break; - case 751: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That's all I have to do?"); - stage = 752; - break; - case 752: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well once you've collected some wool you'll need to spin", "it into balls."); - stage = 753; - break; - case 753: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Do you know how to spin wool?"); - stage = 754; - break; - case 754: - interpreter.sendOptions("Select an Option", "I don't know how to spin wool, sorry.", "I'm something of an expert actually!"); - stage = 755; - break; - case 755: - switch (buttonId) { - case 1: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I don't know how to spin wool, sorry."); - stage = 756; - break; - case 2: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm something of an expert actually!"); - stage = 850; - break; - } - break; - case 850: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well you can stop grinning and get to work then."); - stage = 851; - break; - case 851: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "I'm not paying you by the hour!"); - stage = 852; - break; - case 852: - end(); - quest.start(player); - break; - case 756: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Don't worry, it's quite simple!"); - stage = 757; - break; - case 757: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "The nearest Spinning Wheel can be found on the first", "floor of Lumbridge Castle."); - stage = 758; - break; - case 758: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "To get to the Lumbridge Castle just follow the road east."); - stage = 759; - break; - case 759: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Thank you!"); - stage = 760; - break; - case 760: - end(); - quest.start(player); - break; - case 671: - end(); - break; - case 560: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well what do you expect if you ask a farmer for a", "quest?"); - stage = 21; - break; - case 456: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well now, no one has ever seen The Thing. That's", "why we call it The Thing, 'cos we don't know what it is."); - stage = 457; - break; - case 457: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Someone say it's a black hearted shapeshifter, hungering for", "the souls of hard working decent folk like me. Others", "say it's just a sheep."); - stage = 21; - break; - case 20: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "What, on my land? Leave my livestock alone you", "scoundrel!"); - stage = 21; - break; - case 21: - end(); - break; - case 4000: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "How many more do I need to give you?"); - stage = 4001; - break; - case 4001: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You need to collect " + SheepShearer.getWoolLeft(player) + " more balls of wool."); - stage = 4002; - break; - case 4002: - if (!player.getInventory().contains(1759, 1)) { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I haven't got any at the moment."); - stage = 4003; - break; - } - break; - case 4003: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well at least you haven't been eaten."); - stage = 21; - break; - case 4004: - break; - case 5000: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm back!"); - stage = 50001; - break; - case 50001: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "How are you doing getting those balls of wool?"); - stage = 50002; - break; - case 50002: - if (player.getInventory().contains(1759, 1)) { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I have some."); - stage = 50010; - break; - } - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "How many more do I need to give you?"); - stage = 50003; - break; - case 50003: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You need to collect " + SheepShearer.getWoolLeft(player) + " more balls of wool."); - stage = 50004; - break; - case 50004: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Well I've got some wool. I've not managed to make it", "into a ball though."); - stage = 50005; - break; - case 50005: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well go find a spinning wheel then. You can find one", "on the first floor of the Lumbridge Castle, just walk east on", "the road outside my house and you'll find Lumbridge."); - stage = 50006; - break; - case 50006: - end(); - break; - case 50010: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Give 'em here then."); - stage = 5011; - break; - case 5011: - int removeAmount = SheepShearer.getWoolRemove(player); - if (SheepShearer.addWool(player)) { - if (SheepShearer.getWoolGiven(player) == 20) { - player.getQuestRepository().getQuest("Sheep Shearer").setStage(player, 90); - } - interpreter.sendDialogue("You give fred " + removeAmount + " balls of wool"); - stage = 5012; - } - break; - case 5012: - if (SheepShearer.getWoolGiven(player) == 20) { - player.getQuestRepository().getQuest("Sheep Shearer").setStage(player, 90); - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That's the last of them."); - stage = 999; - break;// enough - } - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That's all I've got so far."); - stage = 5013; - break; - case 5013: - if (SheepShearer.getWoolGiven(player) == 20) { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "That's the last of them."); - stage = 999; - break;// enough - } - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "I need " + SheepShearer.getWoolCollect(player) + " before I can pay you."); - stage = 5014; - break; - case 999: - interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "I guess I'd better pay you then."); - stage = 1000; - break; - case 1000: - end(); - Quest quest11 = player.getQuestRepository().getQuest("Sheep Shearer"); - quest11.finish(player); - player.removeAttribute("sheep-shearer:wool"); - break; - case 5014: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Ok, I'll work on it."); - stage = 5015; - break; - case 5015: - end(); - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[] { 758 }; - } -} diff --git a/Server/src/main/content/region/misthalin/lumbridge/dialogue/FredTheFarmerDialogue.kt b/Server/src/main/content/region/misthalin/lumbridge/dialogue/FredTheFarmerDialogue.kt new file mode 100644 index 000000000..604b9e4fb --- /dev/null +++ b/Server/src/main/content/region/misthalin/lumbridge/dialogue/FredTheFarmerDialogue.kt @@ -0,0 +1,47 @@ +package content.region.misthalin.lumbridge.dialogue + +import content.region.misthalin.lumbridge.quest.sheepshearer.SSFredTheFarmerDialogue +import core.api.* +import core.game.dialogue.DialoguePlugin +import core.game.dialogue.FacialExpression +import core.game.dialogue.IfTopic +import core.game.dialogue.Topic +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.plugin.Initializable +import core.tools.END_DIALOGUE +import core.tools.START_DIALOGUE + +@Initializable +class FredTheFarmerDialogue(player: Player? = null) : DialoguePlugin(player) { + override fun getIds(): IntArray { + return intArrayOf(758) + } + + override fun open(vararg args: Any): Boolean { + npc = args[0] as NPC + if (questStage(player, "Sheep Shearer") in 1..99) { + openDialogue(player, SSFredTheFarmerDialogue(questStage(player, "Sheep Shearer")), npc) + } else { + npc(FacialExpression.ANGRY, "What are you doing on my land? You're not the one", "who keeps leaving all my gates open and letting out all", "my sheep are you?").also { stage = START_DIALOGUE } + } + return true + } + + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + when (stage) { + START_DIALOGUE -> showTopics( + IfTopic(FacialExpression.NEUTRAL, "I'm looking for a quest.", 1000, questStage(player!!, "Sheep Shearer") == 0), + Topic(FacialExpression.HALF_GUILTY, "I'm looking for something to kill.", 100), + Topic(FacialExpression.HALF_GUILTY, "I'm lost.", 200) + ) + + 100 -> npc(FacialExpression.HALF_GUILTY, "What, on my land? Leave my livestock alone you", "scoundrel!").also { stage = END_DIALOGUE } + + 200 -> npc(FacialExpression.HALF_GUILTY, "How can you be lost? Just follow the road east and", "south. You'll end up in Lumbridge fairly quickly.").also { stage = END_DIALOGUE } + + 1000 -> openDialogue(player, SSFredTheFarmerDialogue(questStage(player, "Sheep Shearer")), npc) + } + return true + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SSFredTheFarmerDialogue.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SSFredTheFarmerDialogue.kt new file mode 100644 index 000000000..9392a5926 --- /dev/null +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SSFredTheFarmerDialogue.kt @@ -0,0 +1,182 @@ +package content.region.misthalin.lumbridge.quest.sheepshearer + +import core.api.* +import core.game.dialogue.DialogueFile +import core.game.dialogue.FacialExpression +import core.tools.END_DIALOGUE +import core.tools.START_DIALOGUE +import org.rs09.consts.Items + +class SSFredTheFarmerDialogue(val questStage: Int) : DialogueFile() { + companion object { + const val STAGE_BEGIN_QUEST = 1000 + const val STAGE_PENGUIN_SHEEP_SHEARED = 3000 + const val STAGE_CANT_SPIN_WOOL = 20000 + const val STAGE_CAN_SPIN_WOOL = 20100 + const val STAGE_DELIVER_BALLS_OF_WOOL = 30000 + const val STAGE_FINISH_QUEST = 30301 + } + + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + START_DIALOGUE -> if (questStage == 10) { + if (getAttribute(player!!, SheepShearer.ATTR_IS_PENGUIN_SHEEP_SHEARED, false)) { + npc(FacialExpression.ANGRY, "What are you doing on my land?").also { stage = STAGE_PENGUIN_SHEEP_SHEARED } + } else { + npc(FacialExpression.NEUTRAL, "How are you doing getting those balls of wool?").also { stage = STAGE_DELIVER_BALLS_OF_WOOL } + } + } else if (questStage == 90) { + // Player delivered all balls of wool but exited the dialogue before the quest was recorded as complete + npc(FacialExpression.SAD, "I guess I'd better pay you then.").also { stage = STAGE_FINISH_QUEST } + } else { + npc(FacialExpression.NEUTRAL, "You're after a quest, you say? Actually I could do with", "a bit of help.").also { stage = STAGE_BEGIN_QUEST } + } + + STAGE_BEGIN_QUEST -> npc(FacialExpression.NEUTRAL, "My sheep are getting mighty woolly. I'd be much", "obliged if you could shear them. And while you're at it", "spin the wool for me too.").also { stage++ } + 1001 -> npc(FacialExpression.HAPPY, "Yes, that's it. Bring me 20 balls of wool. And I'm sure", "I could sort out some sort of payment. Of course,", "there's the small matter of The Thing.").also { stage++ } + 1002 -> options("Yes okay. I can do that.", "That doesn't sound a very exciting quest.", "What do you mean, The Thing?").also { stage++ } + 1003 -> when (buttonID) { + 1 -> player(FacialExpression.HAPPY, "Yes okay. I can do that.").also { stage = 2000 } + 2 -> player(FacialExpression.HALF_GUILTY, "That doesn't sound a very exciting quest.").also { stage = 1100 } + 3 -> player(FacialExpression.ASKING, "What do you mean, The Thing?").also { stage = 1200 } + } + + // TODO: There might be more dialogue here + 1100 -> npc(FacialExpression.HALF_GUILTY, "Well what do you expect if you ask a farmer for a", "quest?").also { stage = END_DIALOGUE } + + 1200 -> npc(FacialExpression.SUSPICIOUS, "Well now, no one has ever seen The Thing. That's", "why we call it The Thing, 'cos we don't know what it is.").also { stage++ } + 1201 -> npc(FacialExpression.SCARED, "Some say it's a black hearted shapeshifter, hungering for", "the souls of hard working decent folk like me. Others", "say it's just a sheep.").also { stage++ } + 1202 -> npc(FacialExpression.ANGRY, "Well I don't have all day to stand around and gossip.", "Are you going to shear my sheep or what!").also { stage++ } + 1203 -> options("Yes okay. I can do that.", "Erm I'm a bit worried about this Thing.").also { stage++ } + 1204 -> when (buttonID) { + 1 -> player(FacialExpression.HAPPY, "Yes okay. I can do that.").also { stage = 2000 } + 2 -> player(FacialExpression.HALF_GUILTY, "Erm I'm a bit worried about this Thing.").also { stage = 1300 } + } + + 1300 -> npc(FacialExpression.HALF_GUILTY, "I'm sure it's nothing to worry about. Just because", "my last shearer was seen bolting out of the field", "screaming for his life doesn't mean anything.").also { stage++ } + 1301 -> player(FacialExpression.HALF_GUILTY, "I'm not convinced.").also { stage = END_DIALOGUE } + + 2000 -> { + // NOTE: In a July 2009 video, this only happens when the dialogue ends + startQuest(player!!, "Sheep Shearer") + npc(FacialExpression.NEUTRAL, "Good! Now one more thing, do you actually know how", "to shear a sheep?").also { stage++ } + } + 2001 -> options("Of course!", "Err. No, I don't know actually.").also { stage++ } + 2002 -> when (buttonID) { + 1 -> player(FacialExpression.HAPPY, "Of course!").also { stage = 2100 } + 2 -> player(FacialExpression.NEUTRAL, "Err. No, I don't know actually.").also { stage = 2200 } + } + + 2100 -> npc(FacialExpression.NEUTRAL, "And you know how to spin wool into balls?").also { stage++ } + 2101 -> options("I'm something of an expert actually!", "I don't know how to spin wool, sorry.").also { stage++ } + 2102 -> when (buttonID) { + 1 -> player(FacialExpression.HAPPY, "I'm something of an expert actually!").also { stage = STAGE_CAN_SPIN_WOOL } + 2 -> player(FacialExpression.NEUTRAL, "I don't know how to spin wool, sorry.").also { stage = STAGE_CANT_SPIN_WOOL } + } + + 2200 -> { + if (inInventory(player!!, Items.SHEARS_1735)) { + npc(FacialExpression.HAPPY, "Well, you're halfway there already! You have a set of", "shears in your inventory. Just use those on a Sheep to", "shear it.").also { stage = 2300 } + } else { + npc(FacialExpression.NEUTRAL, "Well, first things first, you need a pair of shears, there's", "a pair in the house on the table.").also { stage = 2400 } + } + } + + 2300 -> player(FacialExpression.NEUTRAL, "That's all I have to do?").also { stage++ } + 2301 -> npc(FacialExpression.NEUTRAL, "Well once you've collected some wool you'll need to spin", "it into balls.").also { stage++ } + 2302 -> npc(FacialExpression.ASKING, "Do you know how to spin wool?").also { stage++ } + 2303 -> options("I don't know how to spin wool, sorry.", "I'm something of an expert actually!").also { stage++ } + 2304 -> when (buttonID) { + 1 -> player(FacialExpression.NEUTRAL, "I don't know how to spin wool, sorry.").also { stage = STAGE_CANT_SPIN_WOOL } + 2 -> player(FacialExpression.HAPPY, "I'm something of an expert actually!").also { stage = STAGE_CAN_SPIN_WOOL } + } + + 2400 -> npc(FacialExpression.NEUTRAL, "Or you could buy your own pair from the General", "Store in Lumbridge.").also { stage++ } + 2401 -> npc(FacialExpression.NEUTRAL, "To get to Lumbridge travel east on the road outside.").also { stage++ } + // TODO: Add "General Stores are marked on the map by this symbol." message with the general store map icon here + 2402 -> npc(FacialExpression.NEUTRAL, "Once you get some shears use them on the sheep in", "my field.").also { stage++ } + 2403 -> player(FacialExpression.HAPPY, "Sounds easy!").also { stage++ } + 2404 -> npc(FacialExpression.LAUGH, "That's what they all say!").also { stage++ } + 2405 -> npc(FacialExpression.NEUTRAL, "Some of the sheep don't like it and will run away from", "you. Persistence is the key.").also { stage++ } + 2406 -> npc(FacialExpression.NEUTRAL, "Once you've collected some wool you can spin it into", "balls.").also { stage++ } + 2407 -> npc(FacialExpression.NEUTRAL, "Do you know how to spin wool?").also { stage++ } + 2408 -> options("I don't know how to spin wool, sorry.", "I'm something of an expert actually!").also { stage++ } + 2409 -> when (buttonID) { + 1 -> player(FacialExpression.NEUTRAL, "I don't know how to spin wool, sorry.").also { stage = STAGE_CANT_SPIN_WOOL } + 2 -> player(FacialExpression.HAPPY, "I'm something of an expert actually!").also { stage = STAGE_CAN_SPIN_WOOL } + } + + STAGE_PENGUIN_SHEEP_SHEARED -> options("I'm back!", "Fred! Fred! I've seen The Thing!").also { stage++ } + 3001 -> when (buttonID) { + 1 -> player(FacialExpression.HAPPY, "I'm back!").also { stage = 3100 } + 2 -> player(FacialExpression.AMAZED, "Fred! Fred! I've seen The Thing!").also { stage = 3200 } + } + + 3100 -> npc(FacialExpression.NEUTRAL, "How are you doing getting those balls of wool?").also { stage = STAGE_DELIVER_BALLS_OF_WOOL } + + 3200 -> npc(FacialExpression.SCARED, "You ... you actually saw it?").also { stage++ } + 3201 -> npc(FacialExpression.SCARED, "Run for the hills! ${player!!.username} grab as many chickens as", "you can! We have to ...").also { stage++ } + 3202 -> player(FacialExpression.AMAZED, "Fred!").also { stage++ } + 3203 -> npc(FacialExpression.SCARED, "... flee! Oh, woe is me! The shapeshifter is coming!", "We're all ...").also { stage++ } + 3204 -> player(FacialExpression.ANGRY, "FRED!").also { stage++ } + 3205 -> npc(FacialExpression.HALF_CRYING, "... doomed. What!").also { stage++ } + 3206 -> player(FacialExpression.NEUTRAL, "It's not a shapeshifter or any other kind of monster!").also { stage++ } + 3207 -> npc(FacialExpression.ASKING, "Well then what is it boy?").also { stage++ } + 3208 -> player(FacialExpression.THINKING, "Well ... it's just two Penguins; Penguins disguised as a", "sheep.").also { stage++ } + 3209 -> npc(FacialExpression.THINKING, "...").also { stage++ } + 3210 -> npc(FacialExpression.AMAZED, "Have you been out in the sun too long?").also { stage = END_DIALOGUE } + + // Common dialogue - doesn't know how to spin wool + STAGE_CANT_SPIN_WOOL -> npc(FacialExpression.NEUTRAL, "Don't worry, it's quite simple!").also { stage++ } + 20001 -> npc(FacialExpression.NEUTRAL, "The nearest Spinning Wheel can be found on the first", "floor of Lumbridge Castle.").also { stage++ } + 20002 -> npc(FacialExpression.NEUTRAL, "To get to Lumbridge Castle just follow the road east.").also { stage++ } + // TODO: Add "This icon denotes a Spinning Wheel on the world map." message with the spinning wheel map icon here + 20003 -> player(FacialExpression.HAPPY, "Thank you!").also { stage = END_DIALOGUE } + + // Common dialogue - knows how to spin wool + STAGE_CAN_SPIN_WOOL -> npc(FacialExpression.NEUTRAL, "Well you can stop grinning and get to work then.").also { stage++ } + 20101 -> npc(FacialExpression.ANGRY, "I'm not paying you by the hour!").also { stage = END_DIALOGUE } + + // Common dialogue - deliver balls of wool + STAGE_DELIVER_BALLS_OF_WOOL -> { + if (inInventory(player!!, Items.BALL_OF_WOOL_1759)) { + player(FacialExpression.HAPPY, "I have some.").also { stage = 30100 } + } else { + player(FacialExpression.ASKING, "How many more do I need to give you?").also { stage = 31000 } + } + } + + 30100 -> npc(FacialExpression.NEUTRAL, "Give 'em here then.").also { stage++ } + 30101 -> { + val ballsOfWoolDelivered = SheepShearer.deliverBallsOfWool(player!!) + if (SheepShearer.getBallsOfWoolRequired(player!!) == 0) { + setQuestStage(player!!, "Sheep Shearer", 90) + player(FacialExpression.HAPPY, "That's the last of them.").also { stage = 30300 } + } else { + sendDialogue(player!!, "You give Fred $ballsOfWoolDelivered balls of wool").also { stage = 30200 } + } + } + + 30200 -> player(FacialExpression.NEUTRAL, "That's all I've got so far.").also { stage++ } + 30201 -> npc(FacialExpression.NEUTRAL, "I need ${SheepShearer.getBallsOfWoolRequired(player!!)} more before I can pay you.").also { stage++ } + 30202 -> player(FacialExpression.NEUTRAL, "Ok I'll work on it.").also { stage = END_DIALOGUE } + + 30300 -> npc(FacialExpression.SAD, "I guess I'd better pay you then.").also { stage++ } + STAGE_FINISH_QUEST -> finishQuest(player!!, "Sheep Shearer").also { stage = END_DIALOGUE } + + 31000 -> npc(FacialExpression.NEUTRAL, "You need to collect ${SheepShearer.getBallsOfWoolRequired(player!!)} more balls of wool.").also { stage++ } + 31001 -> { + if (inInventory(player!!, Items.WOOL_1737)) { + player(FacialExpression.NEUTRAL, "Well I've got some wool. I've not managed to make it", "into a ball though.").also { stage = 31100 } + } else { + player(FacialExpression.HALF_GUILTY, "I haven't got any at the moment.").also { stage = 31200 } + } + } + + 31100 -> npc(FacialExpression.NEUTRAL, "Well go find a spinning wheel then. You can find one", "on the first floor of Lumbridge Castle, just walk east on", "the road outside my house and you'll find Lumbridge.").also { stage = END_DIALOGUE } + + // TODO: There might be more dialogue here + 31200 -> npc(FacialExpression.HALF_GUILTY, "Ah well at least you haven't been eaten.").also { stage = END_DIALOGUE } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearPlugin.java b/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearPlugin.java deleted file mode 100644 index 428d9f97f..000000000 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearPlugin.java +++ /dev/null @@ -1,84 +0,0 @@ -package content.region.misthalin.lumbridge.quest.sheepshearer; - -import core.cache.def.impl.NPCDefinition; -import core.game.interaction.OptionHandler; -import core.game.node.Node; -import core.game.node.entity.npc.NPC; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.game.system.task.Pulse; -import core.game.world.GameWorld; -import core.game.world.update.flag.context.Animation; -import core.plugin.Plugin; -import core.plugin.Initializable; -import core.tools.RandomFunction; -import org.rs09.consts.Sounds; - -/** - * Represents the plugin used to shear a sheep. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class SheepShearPlugin extends OptionHandler { - - /** - * Represents the animation to use. - */ - private static final Animation ANIMATION = new Animation(893); - - @Override - public Plugin newInstance(Object arg) throws Throwable { - NPCDefinition.setOptionHandler("shear", this); - return this; - } - - @Override - public boolean handle(Player player, Node node, String option) { - final NPC sheep = (NPC) node; - if (sheep.getId() == 3579) { - player.animate(ANIMATION); - player.getAudioManager().send(Sounds.PENGUINSHEEP_ESCAPE_686); - player.getPacketDispatch().sendMessage("The... whatever it is... manages to get away from you!"); - sheep.animate(Animation.create(3570)); - sheep.moveStep(); - return true; - } - if (!player.getInventory().contains(1735, 1)) { - player.getPacketDispatch().sendMessage("You need shears to shear a sheep."); - return true; - } - if (sheep.getDefinition().hasAction("attack")) { - player.getPacketDispatch().sendMessage("That one looks a little too violent to shear..."); - return true; - } - if (player.getInventory().freeSlots() == 0) { - player.getPacketDispatch().sendMessage("You don't have enough space in your inventory to carry any wool you would shear."); - return true; - } - sheep.lock(3); - sheep.getWalkingQueue().reset(); - player.animate(ANIMATION); - int random = RandomFunction.random(1, 5); - if (random != 4) { - sheep.getLocks().lockMovement(2); - sheep.transform(5153); - player.getAudioManager().send(Sounds.SHEAR_SHEEP_761); - player.getPacketDispatch().sendMessage("You get some wool."); - player.getInventory().add(new Item(1737, 1));// 5160 - GameWorld.getPulser().submit(new Pulse(80, sheep) { - @Override - public boolean pulse() { - sheep.reTransform(); - return true; - } - - }); - } else { - player.getPacketDispatch().sendMessage("The sheep manages to get away from you!"); - sheep.moveStep(); - } - return true; - } - -} diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearer.java b/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearer.java deleted file mode 100644 index 793a6f623..000000000 --- a/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearer.java +++ /dev/null @@ -1,135 +0,0 @@ -package content.region.misthalin.lumbridge.quest.sheepshearer; - -import core.plugin.Initializable; -import core.game.node.entity.skill.Skills; -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.quest.Quest; -import core.game.node.item.GroundItemManager; -import core.game.node.item.Item; - -/** - * Represents the sheep shearer quest. - * @author 'Veixa - */ -@Initializable -public class SheepShearer extends Quest { - - /** - * Constructs a new {@code SheepShearer} {@code Object}. - */ - public SheepShearer() { - super("Sheep Shearer", 28, 27, 1, 179, 0, 20, 21); - } - - /** - * Represents the wool item. - */ - public static final Item WOOL = new Item(1759); - - @Override - public void finish(Player player) { - super.finish(player); - player.getPacketDispatch().sendString("1 Quest Point", 277, 8 + 2); - player.getPacketDispatch().sendString("150 Crafting XP", 277, 9 + 2); - player.getPacketDispatch().sendString("60 coins", 277, 10 + 2); - player.getPacketDispatch().sendItemZoomOnInterface(1735, 240, 277, 3 + 2); - player.getSkills().addExperience(Skills.CRAFTING, 150); - player.getInterfaceManager().closeChatbox(); - if (player.getInventory().freeSlots() == 0) { - GroundItemManager.create(new Item(995, 60), player.getLocation()); - } else { - player.getInventory().add(new Item(995, 60)); - } - } - - @Override - public void drawJournal(Player player, int stage) { - super.drawJournal(player, stage); - if (stage < 10) { - player.getPacketDispatch().sendString("I can start this quest by speaking to Farmer Fred at his", 275, 4+ 7); - player.getPacketDispatch().sendString("farm just a little way North West of Lumbridge", 275, 5+ 7); - return; - } - if (stage == 10 || stage == 90) { - player.getPacketDispatch().sendString("I can start this quest by speaking to Farmer Fred at his", 275, 4+ 7); - player.getPacketDispatch().sendString("farm just a little way North West of Lumbridge", 275, 5+ 7); - int wool = getWoolCollect(player); - if (wool == 0) { - player.getPacketDispatch().sendString("I have enough balls of wool to give Fred and get my reward", 275, 7+ 7); - player.getPacketDispatch().sendString("money!", 275, 8+ 7); - } - if (wool != 0) { - player.getPacketDispatch().sendString("I need to collect " + wool + " more balls of wool.", 275, 7+ 7); - } - } - if (stage == 100) { - player.getPacketDispatch().sendString("I brought Farmer Fred 20 balls of wool, and he paid me for", 275, 4+ 7); - player.getPacketDispatch().sendString("it!", 275, 5+ 7); - player.getPacketDispatch().sendString("QUEST COMPLETE!", 275, 7+ 7); - } - } - - /** - * Method used to get the wool given. - * @param player the player. - * @return the wool given. - */ - public static int getWoolGiven(final Player player) { - return player.getAttribute("sheep-shearer:wool", 0); - } - - /** - * Method used to get the wool left to give. - * @param player the player. - * @return the wool. - */ - public static int getWoolLeft(final Player player) { - int left = 20 - getWoolGiven(player); - return left; - } - - /** - * Method used to add wool to the current amount given. - * @param player the player. - * @return True if added. - */ - public static boolean addWool(final Player player) { - final int removeAmount = getWoolRemove(player); - if (player.getInventory().remove(new Item(1759, removeAmount))) { - player.setAttribute("sheep-shearer:wool", getWoolGiven(player) + removeAmount); - return true; - } - return false; - } - - /** - * Method used to get the wool to remove. - * @param player the player. - * @return the amount that can be removed from the inventory. - */ - public static int getWoolRemove(final Player player) { - int woolAmount = player.getInventory().getAmount(WOOL); - int remove = getWoolLeft(player) - (getWoolLeft(player) - woolAmount); - int realRemove = remove > 20 ? remove - (remove - getWoolLeft(player)) : remove; - if (realRemove > getWoolLeft(player)) { - realRemove = getWoolLeft(player); - } - return realRemove; - } - - /** - * Method used to get the wool left to collect. - * @param player the player. - * @return the wool. - */ - public static int getWoolCollect(final Player player) { - return 20 - (getWoolGiven(player) + getWoolRemove(player)); - } - - @Override - public Quest newInstance(Object object) { - // TODO Auto-generated method stub - return this; - } - -} diff --git a/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearer.kt b/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearer.kt new file mode 100644 index 000000000..a30669774 --- /dev/null +++ b/Server/src/main/content/region/misthalin/lumbridge/quest/sheepshearer/SheepShearer.kt @@ -0,0 +1,121 @@ +package content.region.misthalin.lumbridge.quest.sheepshearer + +import core.api.* +import core.game.node.entity.player.Player +import core.game.node.entity.player.link.quest.Quest +import core.game.node.entity.skill.Skills +import core.game.node.item.Item +import core.plugin.Initializable +import org.rs09.consts.Items +import kotlin.math.min + +@Initializable +class SheepShearer : Quest("Sheep Shearer", 28, 27, 1, 179, 0, 20, 21) { + companion object { + val ATTR_NUM_BALLS_OF_WOOL_DELIVERED = "/save:sheep-shearer:num-balls-of-wool-delivered" + val ATTR_IS_PENGUIN_SHEEP_SHEARED = "/save:sheep-shearer:is-penguin-sheep-sheared" + + /** + * Gets the number of balls of wool that have been delivered to Fred the Farmer. + * @param player the player to check + * @return the number of balls of wool that have been delivered + */ + fun getBallsOfWoolDelivered(player: Player): Int { + return getAttribute(player, ATTR_NUM_BALLS_OF_WOOL_DELIVERED, 0) + } + + /** + * Gets the number of balls of wool remaining to be delivered to Fred the Farmer. + * @param player the player to check + * @return the number of balls of wool remaining to be delivered + */ + fun getBallsOfWoolRequired(player: Player): Int { + return 20 - getBallsOfWoolDelivered(player) + } + + /** + * Gets the number of balls of wool that can be removed from the player's inventory, + * up to the amount still required by Fred the Farmer. + * @param player the player whose inventory should be checked + * @return the number of balls of wool that can be removed from the player's inventory + * and delivered to Fred the Farmer + */ + fun getBallsOfWoolToRemove(player: Player): Int { + return min(getBallsOfWoolRequired(player), amountInInventory(player, Items.BALL_OF_WOOL_1759)) + } + + /** + * Gets the number of balls of wool that still need to be collected by the player. + * + * This takes into account the number of balls of wool already delivered to Fred the + * Farmer, and the number of balls of wool in the player's inventory. + * @param player the player to check + * @return the number of balls of wool that still needs to be collected by the player + */ + fun getBallsOfWoolToCollect(player: Player): Int { + return getBallsOfWoolRequired(player) - getBallsOfWoolToRemove(player) + } + + /** + * Delivers all balls of wool in the player's inventory, up to the amount still required + * by Fred the Farmer. + * @param player the player delivering balls of wool to Fred the Farmer + * @return the number of balls of wool removed from the player's inventory and delivered to Fred the Farmer + */ + fun deliverBallsOfWool(player: Player): Int { + val removeAmount = getBallsOfWoolToRemove(player) + if (removeItem(player, Item(Items.BALL_OF_WOOL_1759, removeAmount))) { + setAttribute(player, ATTR_NUM_BALLS_OF_WOOL_DELIVERED, getBallsOfWoolDelivered(player) + removeAmount) + return removeAmount + } + return 0 + } + } + + override fun newInstance(`object`: Any?): Quest { + return this + } + + override fun drawJournal(player: Player, stage: Int) { + super.drawJournal(player, stage) + + var ln = 11 + + if (stage == 0) { + line(player, "I can start this quest by speaking to !!Farmer Fred?? at his", ln++) + line(player, "!!farm?? just a little way !!North West of Lumbridge??", ln++) + } else if (stage == 10 || stage == 90) { + line(player, "I asked Farmer Fred, near Lumbridge, for a quest. Fred", ln++, true) + line(player, "said he'd pay me for shearing his sheep for him!", ln++, true) + ln++ + + val ballsOfWoolToCollect = getBallsOfWoolToCollect(player) + if (ballsOfWoolToCollect == 0) { + line(player, "I have enough !!balls of wool?? to give !!Fred?? and get my !!reward??", ln++) + line(player, "!!money!??", ln++) + } else { + line(player, "I need to collect $ballsOfWoolToCollect more !!balls of wool.??", ln++) + } + } else if (stage == 100) { + line(player, "I brought Farmer Fred 20 balls of wool, and he paid me for", ln++, true) + line(player, "it!", ln++, true) + ln++ + line(player, "QUEST COMPLETE!", ln++) + } + } + + override fun finish(player: Player?) { + super.finish(player) + player ?: return + + var ln = 10 + player.packetDispatch.sendItemZoomOnInterface(Items.SHEARS_1735, 240, 277, 5) + drawReward(player, "1 Quest Point", ln++) + drawReward(player, "150 Crafting XP", ln++) + drawReward(player, "60 coins", ln++) + rewardXP(player, Skills.CRAFTING, 150.0) + addItemOrDrop(player, Items.COINS_995, 60) + removeAttribute(player, ATTR_NUM_BALLS_OF_WOOL_DELIVERED) + removeAttribute(player, ATTR_IS_PENGUIN_SHEEP_SHEARED) + } +} \ No newline at end of file