Files
2009scape/Server/src/main/content/global/bots/GenericSlayerBot.kt
T
bushtail 1b4e0aafaa Code cleanup
Reorganised imports
Removed redundant qualifiers
2023-08-19 15:07:23 +00:00

255 lines
9.3 KiB
Kotlin

package content.global.bots
import core.game.interaction.DestinationFlag
import core.game.interaction.MovementPulse
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.tools.RandomFunction
import org.rs09.consts.Items
import core.game.bots.AIRepository
import core.game.bots.Script
/**
* A bot that does various random slayer tasks throughout the game and sells the loot on the GE.
* @author Ceikry
*/
class GenericSlayerBot : Script() {
var state = State.GETTING_TASK
var task = Task.CAVE_CRAWLER //default value to ensure non-nullability
var assignment = Assignment("",0) //same as above
var teleportFlag = false //have we teleported?
val FOOD_ID = Items.LOBSTER_379
val varrockBankBorders = ZoneBorders(3184, 3435,3187, 3441)
/**
* Per-tick actions (they don't run if the bot already has a pulse running, such as moving or combat.)
*/
override fun tick() {
scriptAPI.eat(FOOD_ID) //try to eat every tick (does nothing if health isn't low enough)
when(state){
/**
* State that handles getting a new task
*/
State.GETTING_TASK -> {
populateTaskAndAssignment()
state = State.GOING_TO_HUB //switch states
}
/**
* State that handles going to the "hub" for the task. Such as fremmy slayer cave or slayer tower.
*/
State.GOING_TO_HUB -> {
when(task.hub){
TaskHub.FREMENNIK_CAVE -> {
if(!teleportFlag) {
scriptAPI.teleport(Location.create(2781, 3615, 0)) //tele -> fremennik fairy ring
teleportFlag = !teleportFlag //teleportFlag -> true
}
else {
val entrance = scriptAPI.getNearestNode(4499,true) //returns the object if within render distance, null if not.
if(entrance == null || !entrance.location.withinDistance(bot.location,2)) {
scriptAPI.walkTo(Location.create(2796, 3615, 0))
} else {
entrance.interaction.handle(bot,entrance.interaction[0]) //bot -> use interaction [0] of cave object
teleportFlag = !teleportFlag //teleportFlag -> false
state = State.KILLING_ENEMY //switch states
}
}
}
else -> {}
}
}
/**
* State used for combat. Handles moving the bot back into the zone for the monster and looting as well.
*/
State.KILLING_ENEMY -> {
val items = AIRepository.groundItems.get(bot) //retrieve drops that belong to this bot
if(items != null && items.isNotEmpty()){ //if we have loot...
if(bot.inventory.freeSlots() == 0){
if(bot.inventory.contains(FOOD_ID,1)){
scriptAPI.forceEat(FOOD_ID)
return
}
}
scriptAPI.takeNearestGroundItem(items.get(0).id)
if(bot.inventory.getAmount(Item(FOOD_ID)) == 0){
state = State.GOING_TO_BANK
}
return
}
if(assignment.amount > 0) {
if (task.borders.insideBorder(bot)) { //make sure bot is within the borders of the task's zone.
scriptAPI.attackNpcInRadius(bot, task.npc_name, 20) //attack nearest NPC with given task name within radius.
assignment.amount--
} else {
scriptAPI.walkTo(task.borders.randomLoc)
}
} else {
state = State.GOING_TO_BANK //switch states and bank.
}
}
/**
* State used to handle traveling to a bank. Due to the dynamic nature of where these bots might be
* in this state, they simply teleport to Varrock and then walk to the west bank to bank.
*/
State.GOING_TO_BANK -> {
if(!teleportFlag){
scriptAPI.teleport(Location.create(3213, 3426, 0))
teleportFlag = !teleportFlag
} else {
if(!varrockBankBorders.insideBorder(bot)) {
scriptAPI.walkTo(varrockBankBorders.randomLoc)
} else {
val bank = scriptAPI.getNearestNode("Bank Booth",true)
bank ?: return
/**
* Run a pulse that moves the bot to the bank booth and then faces it, and then swaps to the actual banking state
*/
bot.pulseManager.run(object: MovementPulse(bot,bank, DestinationFlag.OBJECT){
override fun pulse(): Boolean {
bot.faceLocation(bank.location)
state = State.BANKING
teleportFlag = !teleportFlag
return true
}
})
}
}
}
/**
* State used to handle banking itself. Runs a pulse with a delay of 10 (to make it look like the bot is idling at the bank booth a bit.)
* the pulse adds every item in the bot's inventory to its bank and then clears the bot's inventory. Re-adds lobsters to the inventory afterwords.
*/
State.BANKING -> {
bot.pulseManager.run(object: Pulse(10){
override fun pulse(): Boolean {
for(item in bot.inventory.toArray()){
item ?: continue
if(item.checkIgnored()) continue
bot.bank.add(item)
}
bot.inventory.clear()
for(item in inventory)
bot.inventory.add(item)
scriptAPI.withdraw(Items.LOBSTER_379,10)
bot.fullRestore()
if(assignment.amount <= 0){
state = State.GOING_TO_GE
} else {
state = State.GOING_TO_HUB
}
return true
}
})
}
/**
* State used to handle travelling to the GE.
*/
State.GOING_TO_GE -> {
if(bot.location != Location.create(3165, 3487, 0)) {
scriptAPI.walkTo(Location.create(3165, 3487, 0))
} else {
state = State.SELLING
}
}
/**
* State used to handle selling items on the GE
*/
State.SELLING -> {
scriptAPI.sellAllOnGe()
state = State.GETTING_TASK
}
}
}
/**
* Called when a bot needs to be regenerated, like when a bot dies.
*/
override fun newInstance(): Script {
TODO("Not yet implemented")
}
/**
* Populate task and assignment vars
*/
fun populateTaskAndAssignment() {
task = Task.values().random() //get a new random task from the enum
assignment = Assignment(task.npc_name, RandomFunction.random(task.minAmt, task.maxAmt + 1)) //produce a new Assignment class with values from our Task.
}
/**
* Item extension function to check for ignored items when banking.
*/
fun Item.checkIgnored(): Boolean {
if(name.toLowerCase().contains("charm")) return true
if(name.toLowerCase().contains("lobster")) return true
if(name.toLowerCase().contains("clue")) return true
if(!definition.isTradeable) return true
return when(id){
Items.BONES_2530 -> true
995 -> true
else -> false
}
}
/**
* The state enums
*/
enum class State {
GETTING_TASK,
GOING_TO_HUB,
KILLING_ENEMY,
GOING_TO_BANK,
BANKING,
GOING_TO_GE,
SELLING
}
/**
* Assign default skills and initial inventory
*/
init {
skills[Skills.SLAYER] = 99
inventory.add(Item(Items.LOBSTER_379,10))
}
/**
* List of tasks that this bot can receive
*/
enum class Task(val npc_name: String, val minAmt: Int, val maxAmt: Int, val hub: TaskHub, val borders: ZoneBorders) {
CAVE_CRAWLER("Cave crawler",20,100, TaskHub.FREMENNIK_CAVE, ZoneBorders(2778, 9988,2798, 10002))
}
/**
* The task hubs
*/
enum class TaskHub {
FREMENNIK_CAVE,
SLAYER_TOWER,
TAVERLY_DUNGEON
}
class Assignment(val npc_name: String, var amount: Int) //class used to keep track of current assignment and how many are left.
}