mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-21 10:25:13 -06:00
collector behavior started,
defender behavior started, switched tick() order in SmartBABot() DefenderInsult during idle fixed
This commit is contained in:
parent
00d876485b
commit
35738bb170
8 changed files with 478 additions and 69 deletions
|
|
@ -35,7 +35,7 @@ class CollectorBagManager(val player: Player) {
|
|||
|
||||
fun totalEggs(): Int = container.toArray().filterNotNull().sumOf { it.amount }
|
||||
fun freeEggSpace(): Int = capacity - totalEggs()
|
||||
fun getEggCount(itemId: Int): Int = container.toArray().filterNotNull().count { it.id == itemId }
|
||||
fun getEggCount(itemId: Int): Int = container.toArray().filterNotNull().filter { it.id == itemId }.sumOf { it.amount }
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -48,4 +48,4 @@ class CollectorBagManager(val player: Player) {
|
|||
sendMessage(player, "You put the egg in the bag.")
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package content.minigame.barbassault.bots.roles
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.PenanceType
|
||||
import content.minigame.barbassault.arena.BarbassaultSession.AttackerStyle
|
||||
import content.minigame.barbassault.bots.RoleBehavior
|
||||
import content.minigame.barbassault.bots.core.BABotContext
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.game.node.entity.combat.DeathTask
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.AttackStyle
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.BONUS_SLASH
|
||||
|
|
@ -16,13 +18,11 @@ class AttackerBehavior : RoleBehavior {
|
|||
override fun tick(ctx: BABotContext) {
|
||||
|
||||
val bot = ctx.bot
|
||||
val api = ctx.api
|
||||
|
||||
ctx.insultDefender()
|
||||
useCalledAttackStyle(bot)
|
||||
if (attackPenance(ctx)) return
|
||||
if (ctx.poolIdle()) return
|
||||
if (ctx.insultDefender(bot)) return
|
||||
|
||||
if (ctx.poolIdle("BA-Attacker: Idling at pool")) return
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -36,6 +36,9 @@ class AttackerBehavior : RoleBehavior {
|
|||
}
|
||||
private fun checkValidTargets(target: NPC): Boolean {
|
||||
if (!target.isActive()) return false
|
||||
if (target.skills.lifepoints <= 0 || DeathTask.isDead(target)) return false
|
||||
val penanceType = target.getAttribute<PenanceType?>("barbass-type", null)
|
||||
if (penanceType != PenanceType.FIGHTER && penanceType != PenanceType.RANGER) return false
|
||||
if (!target.getProperties().isMultiZone() && target.inCombat()) return false
|
||||
if (!target.getDefinition().hasAction("attack")) return false
|
||||
return true
|
||||
|
|
@ -59,4 +62,4 @@ class AttackerBehavior : RoleBehavior {
|
|||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
package content.minigame.barbassault.bots.core
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BAGroundSpawn
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.PenanceType
|
||||
import core.game.bots.Script
|
||||
import core.game.bots.ScriptAPI
|
||||
import core.game.global.action.PickupHandler
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListeners
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.GroundItemManager
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
|
||||
|
||||
|
|
@ -18,7 +24,7 @@ class BABotContext( val bot: Player,val api: ScriptAPI ) {
|
|||
var role: BarbRole? = null
|
||||
|
||||
private var delayTicks = 0
|
||||
internal var insultNextTick = 0
|
||||
private var defenderInsultNextTick = 0
|
||||
|
||||
var tick: Int = 0
|
||||
|
||||
|
|
@ -51,32 +57,103 @@ class BABotContext( val bot: Player,val api: ScriptAPI ) {
|
|||
return false
|
||||
}
|
||||
|
||||
fun poolIdle(): Boolean {
|
||||
val base = session?.base ?: return false
|
||||
fun poolIdle(state: String = "BA-Bot: Idling at pool"): Boolean {
|
||||
val s = session ?: return false
|
||||
val base = s.base
|
||||
val poolArea = ZoneBorders(base.x+27, base.y+18, base.x+24, base.y+16, 0)
|
||||
if (poolArea.insideBorder(bot.location)) {
|
||||
return false
|
||||
}
|
||||
api.walkTo(poolArea.randomWalkableLoc)
|
||||
bot.customState = state
|
||||
api.walkTo(base.transform(25, 17, 0))
|
||||
return true
|
||||
}
|
||||
|
||||
fun insultDefender(bot: Player): Boolean {
|
||||
val s = session!!
|
||||
if (!s.isPenanceDead(PenanceType.HEALER) && !s.isPenanceDead(PenanceType.RANGER )&& !s.isPenanceDead(PenanceType.FIGHTER)) return false
|
||||
fun sameTile(a: Location, b: Location): Boolean {
|
||||
return a.x == b.x && a.y == b.y && a.z == b.z
|
||||
}
|
||||
|
||||
fun walkToTile(loc: Location, state: String, delay: Int = 2): Boolean {
|
||||
if (sameTile(bot.location, loc)) return false
|
||||
|
||||
bot.customState = state
|
||||
api.walkTo(loc)
|
||||
tickDelay(delay)
|
||||
return true
|
||||
}
|
||||
|
||||
fun findBAGroundItem(itemId: Int, spawnLoc: Location? = null): BAGroundSpawn? {
|
||||
val s = session ?: return null
|
||||
return s.BAgroundItems
|
||||
.filter {
|
||||
it.id == itemId &&
|
||||
it.isActive &&
|
||||
GroundItemManager.getItems().contains(it) &&
|
||||
(spawnLoc == null || sameTile(it.location, spawnLoc))
|
||||
}
|
||||
.minByOrNull { it.location.getDistance(bot.location) }
|
||||
}
|
||||
|
||||
fun findNearestBAGroundItem(itemId: Int, spawnLocs: List<Location>): BAGroundSpawn? {
|
||||
val s = session ?: return null
|
||||
return s.BAgroundItems
|
||||
.filter { item ->
|
||||
item.id == itemId &&
|
||||
item.isActive &&
|
||||
GroundItemManager.getItems().contains(item) &&
|
||||
spawnLocs.any { sameTile(item.location, it) }
|
||||
}
|
||||
.minByOrNull { it.location.getDistance(bot.location) }
|
||||
}
|
||||
|
||||
fun takeBAGroundItem(item: BAGroundSpawn, state: String, delay: Int = 3): Boolean {
|
||||
if (walkToTile(item.location, state)) return true
|
||||
|
||||
bot.customState = state
|
||||
val takeListener = InteractionListeners.get(item.id, IntType.GROUNDITEM.ordinal, "Take")
|
||||
?: InteractionListeners.get("Take", IntType.GROUNDITEM.ordinal)
|
||||
|
||||
if (takeListener != null) {
|
||||
takeListener.invoke(bot, item)
|
||||
} else {
|
||||
PickupHandler.take(bot, item)
|
||||
}
|
||||
tickDelay(delay)
|
||||
return true
|
||||
}
|
||||
|
||||
fun pickUpBAGroundItem(itemId: Int, spawnLoc: Location, state: String): Boolean {
|
||||
val item = findBAGroundItem(itemId, spawnLoc) ?: return walkToTile(spawnLoc, state)
|
||||
return takeBAGroundItem(item, state)
|
||||
}
|
||||
|
||||
fun pickUpNearestBAGroundItem(itemId: Int, spawnLocs: List<Location>, state: String): Boolean {
|
||||
val item = findNearestBAGroundItem(itemId, spawnLocs)
|
||||
if (item != null) return takeBAGroundItem(item, state)
|
||||
|
||||
val nearestSpawn = spawnLocs.minByOrNull { it.getDistance(bot.location) } ?: return false
|
||||
return walkToTile(nearestSpawn, state)
|
||||
}
|
||||
|
||||
fun insultDefender() {
|
||||
val s = session ?: return
|
||||
if (!s.isPenanceDead(PenanceType.HEALER) || !s.isPenanceDead(PenanceType.RANGER) ||
|
||||
!s.isPenanceDead(PenanceType.FIGHTER) || s.isPenanceDead(PenanceType.RUNNER)
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (tick < defenderInsultNextTick) return
|
||||
|
||||
if (tick < insultNextTick) return false
|
||||
val defenderInsults = listOf(
|
||||
"you defend like Ryan codes Barbass",
|
||||
"You defend like Ryan codes Barbass",
|
||||
"R u asleep?",
|
||||
"get szued",
|
||||
"Get szued",
|
||||
"I've seen better defense from a broken gate",
|
||||
"do you even see the runners?",
|
||||
"my grandma can do better then that!"
|
||||
"Do you even see the runners?",
|
||||
"My grandma can do better then that!"
|
||||
)
|
||||
api.sendChat(defenderInsults.random())
|
||||
insultNextTick = tick + (8..20).random()
|
||||
return true
|
||||
defenderInsultNextTick = tick + (8..20).random()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,149 @@
|
|||
package content.minigame.barbassault.bots.roles
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.bots.RoleBehavior
|
||||
import content.minigame.barbassault.bots.core.BABotContext
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListeners
|
||||
import content.minigame.barbassault.arena.scenery.EggCannon
|
||||
import core.api.amountInInventory
|
||||
import core.api.freeSlots
|
||||
import getCollectorBag
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
class CollectorBehavior : RoleBehavior {
|
||||
|
||||
override fun tick(ctx: BABotContext) {
|
||||
|
||||
val bot = ctx.bot
|
||||
val api = ctx.api
|
||||
val session = ctx.session ?: return
|
||||
ctx.script?.preventRandomIdle = true
|
||||
|
||||
if (ctx.insultDefender(bot)) return
|
||||
ctx.insultDefender()
|
||||
if (isHopperFull(session)) {
|
||||
bot.customState = "BA-Collector: Hopper full, idling at cannon"
|
||||
idleAtCannon(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
bot.customState = "Collector"
|
||||
if (hasLoadableCarriedEggs(ctx, session)) {
|
||||
if (loadHopper(ctx)) return
|
||||
}
|
||||
|
||||
val calledEgg = getCalledEgg(session) ?: run {
|
||||
bot.customState = "BA-Collector: Waiting for attacker call"
|
||||
idleAtCannon(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
val cannon = api.getNearestNode(2213, true)
|
||||
if (cannon != null) {
|
||||
api.walkTo(cannon.location)
|
||||
if (bot.skills.lifepoints <= MIN_SAFE_EGG_HP) {
|
||||
bot.customState = "BA-Collector: Low HP (${bot.skills.lifepoints}), not picking eggs"
|
||||
idleAtCannon(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
if (!canHopperTake(session, calledEgg.itemId)) {
|
||||
bot.customState = "BA-Collector: Hopper already full for ${calledEgg.name.lowercase()} eggs"
|
||||
idleAtCannon(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
if (pickUpCalledEgg(ctx, calledEgg)) return
|
||||
|
||||
bot.customState = "BA-Collector: No ${calledEgg.name.lowercase()} eggs nearby"
|
||||
idleAtCannon(ctx)
|
||||
}
|
||||
|
||||
private fun getCalledEgg(session: BarbassaultSession): BarbassaultSession.EggColor? {
|
||||
val call = session.roleCalls[BarbRole.COLLECTOR] as? BarbassaultSession.CollectorCall
|
||||
return call?.called
|
||||
}
|
||||
|
||||
private fun loadHopper(ctx: BABotContext): Boolean {
|
||||
val hopper = ctx.api.getNearestNode(Scenery.EGG_HOPPER_20264, true) ?: run {
|
||||
ctx.bot.customState = "BA-Collector: Looking for egg hopper"
|
||||
return false
|
||||
}
|
||||
|
||||
if (hopper.location.getDistance(ctx.bot.location) > 2) {
|
||||
ctx.bot.customState = "BA-Collector: Walking to egg hopper"
|
||||
ctx.api.walkTo(hopper.location)
|
||||
ctx.tickDelay(2)
|
||||
return true
|
||||
}
|
||||
|
||||
val session = ctx.session ?: return false
|
||||
val redBefore = session.eggHopper.red
|
||||
val carriedBefore = carriedEggCount(ctx, Items.RED_EGG_10532)
|
||||
ctx.bot.customState = "BA-Collector: Loading red eggs into hopper carried=$carriedBefore hopper=$redBefore"
|
||||
|
||||
PRIORITY_HOPPER_EGGS.filter { carriedEggCount(ctx, it) > 0 && canHopperTake(session, it) }
|
||||
.forEach { EggCannon.loadHopperEggs(ctx.bot, it) }
|
||||
|
||||
ctx.bot.customState = "BA-Collector: Loaded red eggs carried=$carriedBefore hopper=$redBefore->${session.eggHopper.red}"
|
||||
ctx.tickDelay(5)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun pickUpCalledEgg(ctx: BABotContext, calledEgg: BarbassaultSession.EggColor): Boolean {
|
||||
if (!canCarryMoreEggs(ctx)) return false
|
||||
|
||||
val egg = ctx.findBAGroundItem(calledEgg.itemId) ?: return false
|
||||
return ctx.takeBAGroundItem(
|
||||
egg,
|
||||
"BA-Collector: Picking up ${calledEgg.name.lowercase()} egg id=${egg.id} loc=${egg.location}"
|
||||
)
|
||||
}
|
||||
|
||||
private fun canCarryMoreEggs(ctx: BABotContext): Boolean {
|
||||
return getCollectorBag(ctx.bot).bag.freeEggSpace() > 0 || freeSlots(ctx.bot) > 0
|
||||
}
|
||||
|
||||
private fun hasLoadableCarriedEggs(ctx: BABotContext, session: BarbassaultSession): Boolean {
|
||||
return PRIORITY_HOPPER_EGGS.any { carriedEggCount(ctx, it) > 0 && canHopperTake(session, it) }
|
||||
}
|
||||
|
||||
private fun carriedEggCount(ctx: BABotContext, itemId: Int): Int {
|
||||
val bot = ctx.bot
|
||||
return getCollectorBag(bot).bag.getEggCount(itemId) + amountInInventory(bot, itemId)
|
||||
}
|
||||
|
||||
private fun canHopperTake(session: BarbassaultSession, itemId: Int): Boolean {
|
||||
val hopper = session.eggHopper
|
||||
return when (itemId) {
|
||||
Items.GREEN_EGG_10531 -> hopper.green < MAX_HOPPER_EGGS_PER_COLOR
|
||||
Items.RED_EGG_10532 -> hopper.red < MAX_HOPPER_EGGS_PER_COLOR
|
||||
Items.BLUE_EGG_10533 -> hopper.blue < MAX_HOPPER_EGGS_PER_COLOR
|
||||
Items.OMEGA_EGG_10537 -> hopper.yellow < MAX_HOPPER_EGGS_PER_COLOR
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isHopperFull(session: BarbassaultSession): Boolean {
|
||||
val hopper = session.eggHopper
|
||||
return hopper.green >= MAX_HOPPER_EGGS_PER_COLOR &&
|
||||
hopper.red >= MAX_HOPPER_EGGS_PER_COLOR &&
|
||||
hopper.blue >= MAX_HOPPER_EGGS_PER_COLOR
|
||||
}
|
||||
|
||||
private fun idleAtCannon(ctx: BABotContext) {
|
||||
val cannon = ctx.api.getNearestNode(NPCs.EGG_LAUNCHER_5026, false)
|
||||
if (cannon != null && cannon.location.getDistance(ctx.bot.location) > 2) {
|
||||
ctx.api.walkTo(cannon.location)
|
||||
ctx.tickDelay(2)
|
||||
return
|
||||
}
|
||||
|
||||
val hopper = ctx.api.getNearestNode(Scenery.EGG_HOPPER_20264, true)
|
||||
if (hopper != null && hopper.location.getDistance(ctx.bot.location) > 2) {
|
||||
ctx.api.walkTo(hopper.location)
|
||||
ctx.tickDelay(2)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val MIN_SAFE_EGG_HP = 6
|
||||
private const val MAX_HOPPER_EGGS_PER_COLOR = 5
|
||||
private val PRIORITY_HOPPER_EGGS = intArrayOf(Items.RED_EGG_10532)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,230 @@
|
|||
package content.minigame.barbassault.bots.roles
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.LureItems
|
||||
import content.minigame.barbassault.arena.BAGroundSpawn
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.PenanceType
|
||||
import content.minigame.barbassault.bots.RoleBehavior
|
||||
import content.minigame.barbassault.bots.core.BABotContext
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.api.sendChat
|
||||
import core.game.node.entity.player.Player
|
||||
import core.api.getWorldTicks
|
||||
import core.api.setAttribute
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
class DefenderBehavior : RoleBehavior {
|
||||
|
||||
override fun tick(ctx: BABotContext) {
|
||||
val bot = ctx.bot
|
||||
val api = ctx.api
|
||||
val session = ctx.session ?: return
|
||||
ctx.script?.preventRandomIdle = true
|
||||
|
||||
if (!bot.walkingQueue.isMoving) {
|
||||
//ctx.api.walkTo(null)
|
||||
ctx.tickDelay(3)
|
||||
if (session.isPenanceDead(PenanceType.RUNNER)) {
|
||||
if (ctx.poolIdle("BA-Defender: Idling at pool")) return
|
||||
bot.customState = "BA-Defender: Idle at pool"
|
||||
return
|
||||
}
|
||||
if (defendInsults(ctx)) return
|
||||
|
||||
bot.customState = "Defender: "
|
||||
val calledFood = getCalledFood(session) ?: run {
|
||||
bot.customState = "BA-Defender: Waiting for healer call"
|
||||
return
|
||||
}
|
||||
|
||||
if (stockUp(ctx, session, calledFood)) return
|
||||
if (repairTrap(ctx, session)) return
|
||||
if (dropTrapFood(ctx, session, calledFood)) return
|
||||
if (dropTrailFood(ctx, session, calledFood)) return
|
||||
if (pickUpTools(ctx)) return
|
||||
|
||||
bot.customState = "BA-Defender: Guarding trap"
|
||||
walkNearTrap(ctx, session)
|
||||
}
|
||||
|
||||
fun defendInsults(ctx: BABotContext): Boolean {
|
||||
val s = ctx.session!!
|
||||
if (!s.isPenanceDead(PenanceType.HEALER) && !s.isPenanceDead(PenanceType.RANGER )&& !s.isPenanceDead(PenanceType.FIGHTER)) return false
|
||||
if (ctx.tick < ctx.insultNextTick) return false
|
||||
val defenderInsults = listOf(
|
||||
"Have you seen the size of these things?",
|
||||
"them leggs",
|
||||
"get szued",
|
||||
"like to see you try...",
|
||||
"Where? what runners? I CANT SEEE!!",
|
||||
"...",
|
||||
"call the right food!"
|
||||
)
|
||||
ctx.api.sendChat(defenderInsults.random())
|
||||
ctx.insultNextTick = ctx.tick + (8..20).random()
|
||||
return true
|
||||
private fun getCalledFood(session: BarbassaultSession): Int? {
|
||||
val call = session.roleCalls[BarbRole.DEFENDER] as? BarbassaultSession.DefenderCall
|
||||
return call?.called?.itemId
|
||||
}
|
||||
|
||||
private fun stockUp(ctx: BABotContext, session: BarbassaultSession, calledFood: Int): Boolean {
|
||||
val bot = ctx.bot
|
||||
|
||||
if (!needsMoreFood(session) || bot.inventory.containsAtLeastOneItem(calledFood)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val machine = ctx.api.getNearestNode(Scenery.DEFENDER_ITEM_MACHINE_20242, true) ?: return false
|
||||
val option = defenderMachineOption(calledFood) ?: "Stock-up"
|
||||
bot.customState = "BA-Defender: Taking food id=$calledFood ($option)"
|
||||
ctx.api.interact(bot, machine, option)
|
||||
ctx.tickDelay(5)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private fun repairTrap(ctx: BABotContext, session: BarbassaultSession): Boolean {
|
||||
val bot = ctx.bot
|
||||
if (!bot.inventory.containsAtLeastOneItem(Items.HAMMER_2347) || !bot.inventory.containsAtLeastOneItem(Items.LOGS_11760)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val trap = RegionManager.getObject(trapLocation(session)) ?: return false
|
||||
if (trap.id != Scenery.RUNNER_TRAP1_20230 && trap.id != Scenery.BROKEN_TRAP0_20231) {
|
||||
return false
|
||||
}
|
||||
|
||||
bot.customState = "BA-Defender: Repairing trap"
|
||||
ctx.api.interact(bot, trap, "Fix")
|
||||
ctx.tickDelay(6)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dropTrapFood(ctx: BABotContext, session: BarbassaultSession, calledFood: Int): Boolean {
|
||||
val existingTrapFood = countTrapFood(session)
|
||||
if (existingTrapFood >= TRAP_DROP_COUNT) return false
|
||||
|
||||
val botLoc = ctx.bot.location
|
||||
val inTrapArea = trapTiles(session).any { sameTile(botLoc, it) }
|
||||
if (!inTrapArea || hasLureFoodAt(session, botLoc)) {
|
||||
val trapDropLoc = trapDropLocation(session, botLoc)
|
||||
if (ctx.walkToTile(trapDropLoc, "BA-Defender: Moving to trap bait")) return true
|
||||
}
|
||||
|
||||
if (!dropFood(ctx, session, calledFood, "BA-Defender: Dropping trap bait ${existingTrapFood + 1}/$TRAP_DROP_COUNT")) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dropTrailFood(ctx: BABotContext, session: BarbassaultSession, calledFood: Int): Boolean {
|
||||
val nextTrail = TRAIL_SPOTS
|
||||
.mapIndexed { index, offset -> index to session.base.transform(offset) }
|
||||
.firstOrNull { (_, loc) -> !hasLureFoodAt(session, loc) }
|
||||
?: return false
|
||||
|
||||
val (trailIndex, loc) = nextTrail
|
||||
if (ctx.walkToTile(loc, "BA-Defender: Walking trail ${trailIndex + 1}/${TRAIL_SPOTS.size}")) return true
|
||||
|
||||
if (!dropFood(ctx, session, calledFood, "BA-Defender: Dropping trail food ${trailIndex + 1}/${TRAIL_SPOTS.size}")) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun pickUpTools(ctx: BABotContext): Boolean {
|
||||
val bot = ctx.bot
|
||||
val base = ctx.session?.base ?: return false
|
||||
|
||||
if (!bot.inventory.containsAtLeastOneItem(Items.HAMMER_2347)) {
|
||||
return ctx.pickUpBAGroundItem(
|
||||
Items.HAMMER_2347,
|
||||
base.transform(32, 42, 0),
|
||||
"BA-Defender: Getting hammer"
|
||||
)
|
||||
}
|
||||
|
||||
if (!bot.inventory.containsAtLeastOneItem(Items.LOGS_11760)) {
|
||||
return ctx.pickUpNearestBAGroundItem(
|
||||
Items.LOGS_11760,
|
||||
listOf(base.transform(30, 46, 0), base.transform(29, 47, 0)),
|
||||
"BA-Defender: Getting logs"
|
||||
)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun dropFood(ctx: BABotContext, session: BarbassaultSession, foodId: Int, state: String): Boolean {
|
||||
val bot = ctx.bot
|
||||
val inventoryItem = bot.inventory.getItem(Item(foodId)) ?: run {
|
||||
bot.customState = "$state - missing food id=$foodId"
|
||||
return false
|
||||
}
|
||||
val item = Item(foodId, 1)
|
||||
val droppedItem = item.dropItem
|
||||
val requiredFood = (session.roleCalls[BarbRole.DEFENDER] as? BarbassaultSession.DefenderCall)?.required?.itemId
|
||||
val isGoodFood = foodId == requiredFood
|
||||
|
||||
if (!bot.inventory.remove(item)) {
|
||||
bot.customState = "$state - failed remove ${inventoryItem.name} id=${inventoryItem.id}"
|
||||
return false
|
||||
}
|
||||
|
||||
bot.customState = "$state - ${inventoryItem.name} id=${inventoryItem.id}"
|
||||
BAGroundSpawn(session, 60, droppedItem, bot.location, isGoodFood).init()
|
||||
setAttribute(bot, "droppedItem:${droppedItem.id}", getWorldTicks() + 2)
|
||||
ctx.tickDelay(2)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun walkNearTrap(ctx: BABotContext, session: BarbassaultSession) {
|
||||
ctx.walkToTile(trapDropLocation(session, ctx.bot.location), "BA-Defender: Returning to trap")
|
||||
}
|
||||
|
||||
private fun trapLocation(session: BarbassaultSession): Location {
|
||||
return session.base.transform(45, 34, 0)
|
||||
}
|
||||
|
||||
private fun trapDropLocation(session: BarbassaultSession, from: Location): Location {
|
||||
val center = trapLocation(session)
|
||||
if (!hasLureFoodAt(session, center)) return center
|
||||
|
||||
return trapTiles(session)
|
||||
.filter { !hasLureFoodAt(session, it) }
|
||||
.minByOrNull { it.getDistance(from) }
|
||||
?: center
|
||||
}
|
||||
|
||||
private fun countTrapFood(session: BarbassaultSession): Int {
|
||||
val trapTiles = trapTiles(session)
|
||||
return session.BAgroundItems.count {
|
||||
it.id in LureItems &&
|
||||
it.isActive &&
|
||||
trapTiles.any { tile -> sameTile(it.location, tile) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun needsMoreFood(session: BarbassaultSession): Boolean {
|
||||
return countTrapFood(session) < TRAP_DROP_COUNT ||
|
||||
TRAIL_SPOTS.any { !hasLureFoodAt(session, session.base.transform(it)) }
|
||||
}
|
||||
|
||||
private fun hasLureFoodAt(session: BarbassaultSession, loc: Location): Boolean {
|
||||
return session.BAgroundItems.any {
|
||||
it.id in LureItems &&
|
||||
it.isActive &&
|
||||
sameTile(it.location, loc)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sameTile(a: Location, b: Location): Boolean {
|
||||
return a.x == b.x && a.y == b.y && a.z == b.z
|
||||
}
|
||||
|
||||
private fun trapTiles(session: BarbassaultSession): List<Location> {
|
||||
return trapLocation(session).get3x3Tiles()
|
||||
}
|
||||
|
||||
private fun defenderMachineOption(foodId: Int): String? {
|
||||
return when (foodId) {
|
||||
Items.WORMS_10515 -> "Take-worms"
|
||||
Items.CRACKERS_10513 -> "Take-crackers"
|
||||
Items.TOFU_10514 -> "Take-tofu"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TRAP_DROP_COUNT = 2
|
||||
|
||||
private val TRAIL_SPOTS = listOf(
|
||||
Location.create(44, 36, 0),
|
||||
Location.create(41, 37, 0),
|
||||
Location.create(36, 37, 0),
|
||||
Location.create(34, 40, 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,17 @@ class HealerBehavior : RoleBehavior {
|
|||
val bot = ctx.bot
|
||||
val session = ctx.session ?: return
|
||||
|
||||
ctx.insultDefender()
|
||||
if (healTeamMate(ctx, session)) return
|
||||
if (stockUp(ctx)) return
|
||||
if (fillVial(ctx)) return
|
||||
if (healSelf(ctx)) return
|
||||
if (poisonPenanceHealer(ctx, session)) return
|
||||
if (healAnyTeammate(ctx, session)) return
|
||||
if (ctx.insultDefender(bot)) return
|
||||
|
||||
bot.customState = "BA-Healer: Idle"
|
||||
if (ctx.poolIdle("BA-Healer: Idling at pool")) return
|
||||
|
||||
bot.customState = "BA-Healer: Idle at pool"
|
||||
}
|
||||
|
||||
private fun healTeamMate(ctx: BABotContext, session: BarbassaultSession): Boolean {
|
||||
|
|
@ -69,8 +71,16 @@ class HealerBehavior : RoleBehavior {
|
|||
}
|
||||
|
||||
val machine = ctx.api.getNearestNode(Scenery.HEALER_ITEM_MACHINE_20243, true) ?: return false
|
||||
bot.customState = "BA-Healer: Stocking up"
|
||||
ctx.api.interact(bot, machine, "Stock-up")
|
||||
val healerCall = ctx.session?.roleCalls?.get(BarbRole.HEALER) as? BarbassaultSession.HealerCall
|
||||
val calledPoison = healerCall?.called?.itemId
|
||||
val option = when {
|
||||
!hasAnyVial(bot) -> "Take-vial"
|
||||
calledPoison != null && !bot.inventory.containsAtLeastOneItem(calledPoison) -> healerMachineOption(calledPoison)
|
||||
else -> "Stock-up"
|
||||
} ?: "Stock-up"
|
||||
|
||||
bot.customState = "BA-Healer: Taking supplies ($option)"
|
||||
ctx.api.interact(bot, machine, option)
|
||||
ctx.tickDelay(5)
|
||||
return true
|
||||
}
|
||||
|
|
@ -108,8 +118,9 @@ class HealerBehavior : RoleBehavior {
|
|||
|
||||
if (!bot.inventory.containsAtLeastOneItem(poison.itemId)) {
|
||||
val machine = ctx.api.getNearestNode(Scenery.HEALER_ITEM_MACHINE_20243, true) ?: return false
|
||||
bot.customState = "BA-Healer: Restocking ${poison.ui}"
|
||||
ctx.api.interact(bot, machine, "Stock-up")
|
||||
val option = healerMachineOption(poison.itemId) ?: "Stock-up"
|
||||
bot.customState = "BA-Healer: Restocking ${poison.ui} ($option)"
|
||||
ctx.api.interact(bot, machine, option)
|
||||
ctx.tickDelay(5)
|
||||
return true
|
||||
}
|
||||
|
|
@ -148,6 +159,15 @@ class HealerBehavior : RoleBehavior {
|
|||
!DeathTask.isDead(npc)
|
||||
}
|
||||
|
||||
private fun healerMachineOption(foodId: Int): String? {
|
||||
return when (foodId) {
|
||||
Items.POISONED_TOFU_10539 -> "Take-tofu"
|
||||
Items.POISONED_WORMS_10540 -> "Take-worms"
|
||||
Items.POISONED_MEAT_10541 -> "Take-meat"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TEAM_HEAL_PERCENT = 0.65
|
||||
private const val SELF_HEAL_PERCENT = 0.40
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@ class LobbyBehavior : RoleBehavior {
|
|||
private fun state(ctx: BABotContext): LobbyState {
|
||||
val loc = ctx.bot.location
|
||||
val session = getBASession(ctx.bot)
|
||||
ctx.bot.debug(
|
||||
"loc=$loc waiting=${isWaitingArea(loc)} halls=${isInHalls(loc)} session=${session != null}"
|
||||
)
|
||||
ctx.bot.debug("loc=$loc waiting=${isWaitingArea(loc)} halls=${isInHalls(loc)} session=${session != null}")
|
||||
|
||||
return when {
|
||||
(session?.state == BarbassaultState.IN_ARENA) -> LobbyState.IN_ARENA
|
||||
(session?.state == BarbassaultState.END) -> LobbyState.IN_ARENA
|
||||
|
|
@ -53,8 +52,8 @@ class LobbyBehavior : RoleBehavior {
|
|||
return
|
||||
}
|
||||
|
||||
if (ctx.tick % 50 == 0) {
|
||||
ctx.bot.sendChat("Cmon, we need more people!!")
|
||||
if (ctx.tick % 150 == 0) {
|
||||
ctx.api.sendChat("Cmon, we need more people!!")
|
||||
}
|
||||
}
|
||||
private fun getToBA(ctx: BABotContext) {
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ class SmartBABot(l: Location) : PvMBots(l) {
|
|||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
brain.tick()
|
||||
super.tick()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue