diff --git a/Server/src/main/content/global/bots/CosmicCrafter.kt b/Server/src/main/content/global/bots/CosmicCrafter.kt new file mode 100644 index 000000000..911dc2b5d --- /dev/null +++ b/Server/src/main/content/global/bots/CosmicCrafter.kt @@ -0,0 +1,181 @@ +package content.global.bots + +import content.global.skill.runecrafting.MysteriousRuin +import core.cache.def.impl.SceneryDefinition +import core.game.bots.* +import core.game.node.item.Item +import core.game.node.scenery.Scenery +import core.game.world.map.Location +import core.game.world.map.RegionManager +import core.game.world.map.zone.ZoneBorders +import core.net.packet.PacketProcessor +import org.rs09.consts.Items + + +@PlayerCompatible +@ScriptName("Cosmic Rune Crafter") +@ScriptDescription("Crafts cosmic runes. Start in Zanaris w/ cosmic tiara.") +@ScriptIdentifier("cosmic_crafter") +class CosmicCrafter : Script() { + var state = State.INIT + var runeCounter = 0 + var overlay: ScriptAPI.BottingOverlay? = null + var startLocation = Location(0,0,0) + var timer = 0 + var bank_deposit = true + var bank = Location(2384, 4457) + var squeezeZone = ZoneBorders(2413, 4400, 2416, 4406) + var endZone = ZoneBorders(2405, 4392, 2410, 4397) + var agility_part = 0 + + + var ruinsZone = ZoneBorders(2400, 4370, 2410, 4385) + var cosmicZone = ZoneBorders(2160, 4830, 2170, 4840) + + var ruinPoint = Location(2407, 4379, 0) + var agility2ExitPoint = Location(2408, 4394, 0) + var agility2EntryPoint = Location(2408, 4396, 0) + var agility1ExitPoint = Location(2415, 4401, 0) + var agility1EntryPoint = Location(2415, 4403, 0) + + override fun tick() { + if (timer-- > 0) { + return + } + if (bot.settings.runEnergy > 10.0) { + bot.settings.isRunToggled = true + } + + when(state){ + State.INIT -> { + if (!bot.equipment.containsAtLeastOneItem(Items.COSMIC_TIARA_5539)) { + bot.sendMessage("Please equip a cosmic tiara first.") + state = State.INVALID + } else { + overlay = scriptAPI.getOverlay() + overlay!!.init() + overlay!!.setTitle("Cosmic Runes") + overlay!!.setTaskLabel("Runes Crafted:") + overlay!!.setAmount(0) + startLocation = bot.location + state = State.BANKING + } + } + + State.BANKING -> { + if(bot.location != bank) { + scriptAPI.walkTo(bank) + return + } + val runes = bot.inventory.getAmount(Item(Items.COSMIC_RUNE_564)) + if (runes > 0) { + runeCounter += runes + overlay!!.setAmount(runeCounter) + bot.sendMessage("You have crafted a total of: $runeCounter runes.") + scriptAPI.bankItem(Items.COSMIC_RUNE_564) + } else { + scriptAPI.withdraw(Items.PURE_ESSENCE_7936, 28) + state = State.FIRST_AGILITY + } + } + + State.FIRST_AGILITY -> { + val squeezeWall = scriptAPI.getNearestNode(12127, true) + if (agility_part == 0) { + if (!squeezeZone.insideBorder(bot)) + scriptAPI.walkTo(agility1EntryPoint) + else { + scriptAPI.interact(bot, squeezeWall, "squeeze-past") + agility_part = 1 + timer = 6 + } + } else if (agility_part == 1) { + if (!endZone.insideBorder(bot)) + scriptAPI.walkTo(agility2EntryPoint) + else { + scriptAPI.interact(bot, squeezeWall, "squeeze-past") + state = State.RUNNING_TO_ALTER + timer = 6 + } + } + } + + State.RUNNING_TO_ALTER -> { + if (cosmicZone.insideBorder(bot)) + state = State.CRAFTING + + val ruins = scriptAPI.getNearestNode(2458,true) + if (!ruinsZone.insideBorder(bot)) { + scriptAPI.walkTo(ruinPoint) + } else if (ruins != null && ruins.location.withinDistance(bot.location, 20)) { + if (!bot.equipment.containsAtLeastOneItem(Items.COSMIC_TIARA_5539)) { + bot.sendMessage("Please equip a cosmic tiara first.") + state = State.INVALID + } else { + val ruinsChild = (ruins as Scenery).getChild(bot) + scriptAPI.interact(bot, ruinsChild, "enter") + timer = 4 + } + } + } + + State.CRAFTING -> { + val alter = scriptAPI.getNearestNode(2484,true) + scriptAPI.interact(bot, alter, "craft-rune") + if(bot.inventory.containsAtLeastOneItem(Item(Items.COSMIC_RUNE_564))) + state = State.LEAVING_ALTER + } + + State.LEAVING_ALTER -> { + var portalOut = scriptAPI.getNearestNode(2471, true) + scriptAPI.interact(bot, portalOut, "use") + if (ruinsZone.insideBorder(bot)) { + state = State.RETURN_AGILITY + timer = 2 + } + } + + State.RETURN_AGILITY -> { + val squeezeWall = scriptAPI.getNearestNode(12127, true) + if (agility_part == 1) { + if (!endZone.insideBorder(bot)) + scriptAPI.walkTo(agility2ExitPoint) + else { + scriptAPI.interact(bot, squeezeWall, "squeeze-past") + agility_part = 0 + timer = 6 + } + } else if (agility_part == 0) { + if (!squeezeZone.insideBorder(bot)) + scriptAPI.walkTo(agility1ExitPoint) + else { + scriptAPI.interact(bot, squeezeWall, "squeeze-past") + state = State.BANKING + timer = 6 + } + } + } + + State.INVALID -> { + timer = 25 + state = State.INIT + } + } + } + + override fun newInstance(): Script { + return this + } + + enum class State { + INIT, + BANKING, + FIRST_AGILITY, + RETURN_AGILITY, + RUNNING_TO_ALTER, + CRAFTING, + LEAVING_ALTER, + INVALID + } + +} diff --git a/Server/src/main/content/global/bots/LawCrafter.kt b/Server/src/main/content/global/bots/LawCrafter.kt new file mode 100644 index 000000000..16ff4a574 --- /dev/null +++ b/Server/src/main/content/global/bots/LawCrafter.kt @@ -0,0 +1,210 @@ +package content.global.bots + +import content.global.travel.ship.Ships +import core.cache.def.impl.ItemDefinition +import core.game.bots.* +import core.game.node.item.Item +import core.game.node.scenery.Scenery +import core.game.world.map.Location +import core.game.world.map.zone.ZoneBorders +import org.rs09.consts.Items + + +@PlayerCompatible +@ScriptName("Law Rune Crafter") +@ScriptDescription("Crafts law runes. Start near Draynor bank w/ law tiara.") +@ScriptIdentifier("law_crafter") +class LawCrafter : Script() { + var state = State.INIT + var runeCounter = 0 + var overlay: ScriptAPI.BottingOverlay? = null + var startLocation = Location(0,0,0) + var timer = 0 + var bank = ZoneBorders(3092, 3242, 3092, 3245) + var boatNPC = Location(3047, 3234, 0) + var ruinsZone = ZoneBorders(2850, 3375, 2860, 3382) + var ruinPoint = Location(2857, 3380, 0) + var onBoat = ZoneBorders(2824, 3328, 2840, 3333) + var offBoat = ZoneBorders(2827, 3335, 2836, 3336) + var lawLocation = Location(2464, 4830, 0) + var lawZone = ZoneBorders(2439, 4808, 2488, 4855) + var returnNPC = Location(2835, 3335, 0) + var halfBank = Location(3069, 3275, 0) + + override fun tick() { + if (timer-- > 0) { + return + } + if (bot.settings.runEnergy > 10.0) { + bot.settings.isRunToggled = true + } + + when(state){ + State.INIT -> { + if (!bot.equipment.containsAtLeastOneItem(Items.LAW_TIARA_5545) || !ItemDefinition.canEnterEntrana(bot)) { + bot.sendMessage("Please equip a law tiara first.") + bot.sendMessage("AND REMOVE ALL WEAPONS AND ARMOR.") + state = State.INVALID + } else { + overlay = scriptAPI.getOverlay() + overlay!!.init() + overlay!!.setTitle("Law Runes") + overlay!!.setTaskLabel("Runes Crafted:") + overlay!!.setAmount(0) + startLocation = bot.location + state = State.BANKING + } + } + + State.BANKING -> { + endDialogue = true + bot.interfaceManager.closeChatbox() + bot.interfaceManager.openChatbox(137) + bot.interfaceManager.closeChatbox() + bot.dialogueInterpreter.close() + if(!bank.insideBorder(bot)) { + scriptAPI.walkTo(bank.randomLoc) + return + } + val runes = bot.inventory.getAmount(Item(Items.LAW_RUNE_563)) + if (runes > 0) { + runeCounter += runes + overlay!!.setAmount(runeCounter) + bot.sendMessage("You have crafted a total of: $runeCounter runes.") + scriptAPI.bankItem(Items.LAW_RUNE_563) + } else { + scriptAPI.withdraw(Items.PURE_ESSENCE_7936, 28) + state = State.HALF_BANK + } + } + + State.TO_BOAT_GUY -> { + var boatGuy = scriptAPI.getNearestNode(2729, false) + if (boatGuy != null){ + if (boatGuy.location.withinDistance(bot.location,2)) { + if (ItemDefinition.canEnterEntrana(bot)) { + endDialogue = false + Ships.PORT_SARIM_TO_ENTRANA.sail(bot) + state = State.CROSS_GANGPLANK + } else { + state = State.INVALID + } + } else { + scriptAPI.walkTo(boatGuy.location) + } + + } else { + scriptAPI.walkTo(boatNPC) + } + } + + State.CROSS_GANGPLANK -> { + if (onBoat.insideBorder(bot)) { + var gangplank = scriptAPI.getNearestNode(2415, true) + if (gangplank != null) { + scriptAPI.interact(bot, gangplank, "cross") + } + } else if (offBoat.insideBorder(bot)) { + state = State.RUNNING_TO_ALTER + endDialogue = true + } + } + + State.RUNNING_TO_ALTER -> { + if (lawZone.insideBorder(bot)) + state = State.CRAFTING + + val ruins = scriptAPI.getNearestNode(2459,true) + if (!ruinsZone.insideBorder(bot)) { + scriptAPI.walkTo(ruinPoint) + } else if (ruins != null && ruins.location.withinDistance(bot.location, 20)) { + val ruinsChild = (ruins as Scenery).getChild(bot) + scriptAPI.interact(bot, ruinsChild, "enter") + timer = 4 + } + } + + State.CRAFTING -> { + if (!lawZone.insideBorder(bot)) { + return + } + + if (bot.location != lawLocation) { + scriptAPI.walkTo(lawLocation) + } + + val alter = scriptAPI.getNearestNode(2485,true) + scriptAPI.interact(bot, alter, "craft-rune") + if(bot.inventory.containsAtLeastOneItem(Item(Items.LAW_RUNE_563))) + state = State.LEAVING_ALTER + } + + State.LEAVING_ALTER -> { + var portalOut = scriptAPI.getNearestNode(2472, true) + scriptAPI.interact(bot, portalOut, "use") + if (ruinsZone.insideBorder(bot)) { + state = State.RETURN_TO_BOAT_GUY + timer = 2 + } + } + + State.RETURN_TO_BOAT_GUY -> { + var boatGuy = scriptAPI.getNearestNode(2730, false) + if (boatGuy != null){ + if (boatGuy.location.withinDistance(bot.location,2)) { + endDialogue = false + Ships.ENTRANA_TO_PORT_SARIM.sail(bot) + state = State.HALF_BANK + } else { + scriptAPI.walkTo(boatGuy.location) + } + + } else { + scriptAPI.walkTo(returnNPC) + } + } + + // Splits up the journey into two parts. + // This is because the dialogue can't be ended until you are safely on the + // mainland side. But new chunks won't load while dialogue is still displayed. + State.HALF_BANK -> { + if (bot.inventory.containsAtLeastOneItem(Items.PURE_ESSENCE_7936)) { + if ( (bot.location.x - 2) > halfBank.x) { + scriptAPI.walkTo(halfBank) + } else { + state = State.TO_BOAT_GUY + } + } else { + if ( (bot.location.x + 2) < halfBank.x) { + scriptAPI.walkTo(halfBank) + } else { + state = State.BANKING + } + } + } + + State.INVALID -> { + timer = 25 + state = State.INIT + } + } + } + + override fun newInstance(): Script { + return this + } + + enum class State { + INIT, + BANKING, + TO_BOAT_GUY, + CROSS_GANGPLANK, + RUNNING_TO_ALTER, + CRAFTING, + LEAVING_ALTER, + RETURN_TO_BOAT_GUY, + HALF_BANK, + INVALID + } + +} diff --git a/Server/src/main/content/global/bots/NatureCrafter.kt b/Server/src/main/content/global/bots/NatureCrafter.kt new file mode 100644 index 000000000..02f8248e1 --- /dev/null +++ b/Server/src/main/content/global/bots/NatureCrafter.kt @@ -0,0 +1,173 @@ +package content.global.bots + +import content.global.skill.runecrafting.MysteriousRuin +import core.api.teleport +import core.game.bots.* +import core.game.interaction.IntType +import core.game.interaction.InteractionListeners +import core.game.node.entity.player.link.TeleportManager +import core.game.node.item.Item +import core.game.node.scenery.Scenery +import core.game.world.map.Location +import core.game.world.map.zone.ZoneBorders +import org.rs09.consts.Items + + +@PlayerCompatible +@ScriptName("Nature Rune Crafter") +@ScriptDescription("Crafts nat runes. Start in Zanaris w/ dramen staff + Nat tiara.") +@ScriptIdentifier("nature_crafter") +class NatureCrafter : Script() { + var state = State.INIT + var runeCounter = 0 + var overlay: ScriptAPI.BottingOverlay? = null + var startLocation = Location(0,0,0) + var timer = 0 + var teleWaitTime = 16 // 18 ticks needed to rotate the clocks, 2 to teleport + var bank = Location(2384, 4457) + var ruinsZone = ZoneBorders(2866, 3017, 2873, 3022) + var faeRingDestination = Location(2412, 4435, 0) // You don't walk to the fae rings + // you can only walk next to them. so path to the nearest point that isn't in the ring. + var faeRingCenter = Location(2412, 4434, 0) + var karamjaRingDestination = Location(2801, 3002, 0) + var karamjaRingCenter = Location(2801, 3003, 0) + var natureZone = ZoneBorders(2387, 4828, 2416, 4856) + override fun tick() { + if (timer-- > 0) { + return + } + if (bot.settings.runEnergy > 10.0) { + bot.settings.isRunToggled = true + } + + when(state){ + State.INIT -> { + if (checkValid()) { + overlay = scriptAPI.getOverlay() + overlay!!.init() + overlay!!.setTitle("Nature Runes") + overlay!!.setTaskLabel("Runes Crafted:") + overlay!!.setAmount(0) + startLocation = bot.location + state = State.BANKING + } + } + + State.BANKING -> { + if(bot.location != bank) { + scriptAPI.walkTo(bank) + return + } + val runes = bot.inventory.getAmount(Item(Items.NATURE_RUNE_561)) + if (runes > 0) { + runeCounter += runes + overlay!!.setAmount(runeCounter) + bot.sendMessage("You have crafted a total of: $runeCounter runes.") + scriptAPI.bankItem(Items.NATURE_RUNE_561) + } else { + scriptAPI.withdraw(Items.PURE_ESSENCE_7936, 28) + state = State.RUNNING_TO_TELE + } + } + + State.RUNNING_TO_TELE -> { + if (bot.location != faeRingDestination) { + scriptAPI.walkTo(faeRingDestination) + } else { + if (checkValid()) { + timer = teleWaitTime + state = State.TELE_WAIT + bot.sendMessage("Entering Fairy Ring Codes. Please wait...") + } + } + } + + State.TELE_WAIT -> { + teleport(bot, karamjaRingCenter, TeleportManager.TeleportType.FAIRY_RING) + state = State.RUNNING_TO_ALTER + // tele takes 4 ticks so wait that long. + timer = 4 + } + + State.RETURN_WAIT -> { + teleport(bot, faeRingCenter, TeleportManager.TeleportType.FAIRY_RING) + state = State.BANKING + } + + State.RUNNING_TO_ALTER -> { + val ruins = scriptAPI.getNearestNode(2460,true) + if (natureZone.insideBorder(bot)) + state = State.CRAFTING + + if (!ruinsZone.insideBorder(bot)) { + scriptAPI.walkTo(ruinsZone.randomLoc) + } else if (ruins != null && ruins.location.withinDistance(bot.location, 20) && checkValid()) { + val ruinsChild = (ruins as Scenery).getChild(bot) + scriptAPI.interact(bot, ruinsChild, "enter") + timer = 4 + } + } + + State.CRAFTING -> { + val alter = scriptAPI.getNearestNode(2486,true) + scriptAPI.interact(bot, alter, "craft-rune") + if(bot.inventory.containsAtLeastOneItem(Item(Items.NATURE_RUNE_561))) + state = State.LEAVING_ALTER + } + + State.LEAVING_ALTER -> { + var portalOut = scriptAPI.getNearestNode(2473, true) + scriptAPI.interact(bot, portalOut, "use") + if (ruinsZone.insideBorder(bot)) + state = State.RETURNING_TO_TELE + } + + State.RETURNING_TO_TELE -> { + if (bot.location != karamjaRingDestination) { + scriptAPI.walkTo(karamjaRingDestination) + } else { + if (checkValid()) { + var portalOut = scriptAPI.getNearestNode(14130, true) + portalOut?.interaction?.handle(bot, portalOut.interaction[0]) + timer = 4 + state = State.RETURN_WAIT + } + } + } + + State.INVALID -> { + timer = 25 + state = State.INIT + } + } + } + + + // Terminates if you have invalid inventory to avoid cheating + private fun checkValid(): Boolean { + if (!bot.equipment.containsAtLeastOneItem(Items.DRAMEN_STAFF_772) or !bot.equipment.containsAtLeastOneItem(Items.NATURE_TIARA_5541)) { + bot.sendMessage("Please equip a dramen staff and nature tiara first.") + state = State.INVALID + return false + } + return true + } + + override fun newInstance(): Script { + return this + } + + enum class State { + INIT, + BANKING, + RUNNING_TO_TELE, + TELE_WAIT, + RUNNING_TO_ALTER, + CRAFTING, + LEAVING_ALTER, + RETURNING_TO_TELE, + RETURN_WAIT, + INVALID + } + +} diff --git a/Server/src/main/content/global/bots/VarrockEssenceMiner.kt b/Server/src/main/content/global/bots/VarrockEssenceMiner.kt index 3dafd687f..39ce02c55 100644 --- a/Server/src/main/content/global/bots/VarrockEssenceMiner.kt +++ b/Server/src/main/content/global/bots/VarrockEssenceMiner.kt @@ -2,12 +2,12 @@ package content.global.bots import core.game.bots.* import core.game.interaction.DestinationFlag +import core.game.interaction.IntType +import core.game.interaction.InteractionListeners import core.game.interaction.MovementPulse import core.game.world.map.Location import core.game.world.map.zone.ZoneBorders import org.rs09.consts.Items -import core.game.interaction.IntType -import core.game.interaction.InteractionListeners @PlayerCompatible @ScriptDescription("Start in varrock bank with rune mysteries complete and a pickaxe equipped/in inventory") @@ -18,6 +18,7 @@ class VarrockEssenceMiner : Script(){ var state = State.TO_ESSENCE val auburyZone = ZoneBorders(3252, 3398, 3254, 3402) val bankZone = ZoneBorders(3251, 3420,3254, 3422) + // Used for automatic failure prevention eg from levelup override fun tick() { when(state){ @@ -49,10 +50,13 @@ class VarrockEssenceMiner : Script(){ } State.MINING -> { - val essence = scriptAPI.getNearestNode(2491,true) - essence?.let { InteractionListeners.run(essence.id, IntType.SCENERY,"mine",bot,essence) } - if(bot.inventory.isFull) + if(bot.inventory.isFull) { state = State.TO_BANK + } + else { + val essence = scriptAPI.getNearestNode(2491,true) + essence?.let { InteractionListeners.run(essence.id, IntType.SCENERY,"mine",bot,essence) } + } } State.TO_BANK -> { @@ -114,4 +118,4 @@ class VarrockEssenceMiner : Script(){ script.bot = SkillingBotAssembler().produce(SkillingBotAssembler.Wealth.POOR,bot.startLocation) return script } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/bots/GeneralBotCreator.kt b/Server/src/main/core/game/bots/GeneralBotCreator.kt index 4f32de3d5..42378dd4c 100644 --- a/Server/src/main/core/game/bots/GeneralBotCreator.kt +++ b/Server/src/main/core/game/bots/GeneralBotCreator.kt @@ -1,12 +1,12 @@ package core.game.bots +import content.global.bots.Idler +import core.Server import core.game.node.entity.player.Player import core.game.system.task.Pulse import core.game.world.GameWorld import core.game.world.map.Location import core.tools.RandomFunction -import core.Server -import content.global.bots.Idler class GeneralBotCreator { //org/crandor/net/packet/in/InteractionPacket.java <<< This is a very useful class for learning to code bots @@ -40,6 +40,28 @@ class GeneralBotCreator { randomDelay -= 1 return false } + + /* + * Chatboxes and interfaces will cause the authentic interaction subsystem + * to pause any currently running authentically-implemented interactions. + * + * When this happens, if the interfaces are not handled by the script and closed, + * execution will remain paused as the game believes the bot is still doing something + * (because they still have an authentic interaction in the queue, that is not advancing + * because it is paused) and so the script does not execute, but the pulse is waiting on botscript input. + * + * This deadlock can be worked around by just closing these. + * + * Set endDialogue to FALSE if you want + * to avoid automatic dialogue termination (useful for, for example, boat travel) + */ + if (botScript.bot.scripts.getActiveScript() != null && botScript.bot.hasModalOpen() && botScript.endDialogue) { + botScript.bot.interfaceManager.closeChatbox() + botScript.bot.interfaceManager.openChatbox(137) + botScript.bot.interfaceManager.close() + botScript.bot.dialogueInterpreter.close() + } + if (!botScript.bot.pulseManager.hasPulseRunning() && botScript.bot.scripts.getActiveScript() == null) { /*if (ticks++ >= RandomFunction.random(90000,120000)) { diff --git a/Server/src/main/core/game/bots/Script.java b/Server/src/main/core/game/bots/Script.java index c4a580dfa..cda961420 100644 --- a/Server/src/main/core/game/bots/Script.java +++ b/Server/src/main/core/game/bots/Script.java @@ -19,6 +19,7 @@ public abstract class Script { public Player bot; public boolean running = true; + public boolean endDialogue = true; public void init(boolean isPlayer) {