grounditem Resoawns fixed, Runner escape logic better

This commit is contained in:
Tooze 2026-06-10 23:46:39 -04:00
parent 2437d287f2
commit 46658026cd
6 changed files with 78 additions and 30 deletions

View file

@ -32,14 +32,20 @@ class BAGroundSpawn(private var session: BarbassaultSession, private var respawn
fun addLureRange(addRange: Int) { lureRange += addRange }
override fun respawn() {
if (!autoSpawn || respawnRate < 0)
if (!autoSpawn || respawnRate < 0) {
return
}
GameWorld.Pulser.submit(object : Pulse(respawnRate) {
override fun pulse(): Boolean {
active = true
GroundItemManager.create(this@BAGroundSpawn)
if (!session.BAgroundItems.contains(this@BAGroundSpawn)) {
session.BAgroundItems.add(this@BAGroundSpawn)
}
return true
}
})
}
}
}

View file

@ -191,23 +191,30 @@ class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, M
tracker.defenderStats.runnersPast++
}
}
fun isPenanceDead( type: PenanceType): Boolean = currentNPCDeathCount[type] >= currentNPCCount[type]
fun isPenanceDead(type: PenanceType): Boolean = currentNPCDeathCount[type] >= currentWaveDefinition.caps[type]
fun isAllPenanceDead(): Boolean = PenanceType.values().all { isPenanceDead(it) }
fun runnerEscaped(runner: NPC) {
if (!sessionNpcs.remove(runner)) {
return
}
currentNPCEscapeCount[PenanceType.RUNNER] = currentNPCEscapeCount[PenanceType.RUNNER] + 1
val defenders = team.getPlayersByRole(BarbRole.DEFENDER)
val penalizedPlayers = if (defenders.isEmpty()) team.allPlayers() else defenders
penalizedPlayers.forEach { eventBus.emit(BarbAssEvent.RunnerEscaped(it)) }
runner.clear()
val spawn = npcTunnel.firstOrNull { it.type == PenanceType.RUNNER } ?: return
runner.resetWalk()
runner.teleport(base.transform(spawn.spawnOffset))
}
fun runnerKilledByTrap(runner: NPC) {
sessionNpcs.remove(runner)
pennanceClearedMessage(runner)
}
fun pennanceClearedMessage(npc: NPC) {
val session = getBASession(npc) ?: return
if (npc.getAttribute("ba:npc-death-counted", false)) {
return
}
npc.setAttribute("ba:npc-death-counted", true)
val type = npc.getAttribute<PenanceType>("barbass-type")
session.currentNPCDeathCount[type]++
if (session.isPenanceDead(type)) {
@ -238,17 +245,20 @@ class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, M
}
fun tryPenanceSpawn(type: PenanceType, force: Boolean = false): Boolean {
val current = currentNPCCount[type] - currentNPCEscapeCount[type]
val cap = currentWaveDefinition.caps[type]
val npcId = currentWaveDefinition.npcIds[type] ?: return false
if (currentNPCDeathCount[type] >= cap) return false
val current = currentNPCCount[type]
if (!force && current >= cap) return false
val spawn = npcTunnel.firstOrNull { it.type == type } ?: return false
val npc = sessionNPCSpawn(npcId, location(30, 31, 0), spawn.direction)
npc?.location = base.transform(spawn.spawnOffset)
val npc = NPC.create(npcId, base.transform(location(30, 31, 0)), spawn.direction) ?: return false
setBASession(npc as Entity,this)
npc.location = base.transform(spawn.spawnOffset)
npc.init()
sessionNpcs.add(npc)
currentNPCCount[type]++
return isCaveBlocked(type)
@ -268,20 +278,28 @@ class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, M
fun pickUpGroundItem(player: Player,node:BAGroundSpawn): Boolean {
if (player.inventory.add(node)) {
destroyGroundItem(node)
destroyGroundItem(node, allowRespawn = isArenaSpawnItem(node))
return true
}
sendMessage(player,"You don't have enough inventory space to hold that item.")
return false
}
fun destroyGroundItem(node: BAGroundSpawn){
fun destroyGroundItem(node: BAGroundSpawn, allowRespawn: Boolean = false){
node.isActive = false
node.isAutoSpawn = false
BAgroundItems.remove(node)
if (!allowRespawn) {
node.isAutoSpawn = false
BAgroundItems.remove(node)
}
GroundItemManager.destroy(node)
}
private fun isArenaSpawnItem(node: BAGroundSpawn): Boolean {
return arenaSpawnItems.any { spawnItem ->
node.id == spawnItem.id && node.location == base.transform(spawnItem.location)
}
}
fun findClosestLure(target: Location): BAGroundSpawn? {
fun distance(a: Location, b: Location): Int =Math.abs(a.x - b.x) + Math.abs(a.y - b.y)
return BAgroundItems

View file

@ -1,10 +1,11 @@
package content.minigame.barbassault.arena.npcs
import content.minigame.barbassault.BA_SESSION_KEY
import content.minigame.barbassault.applyBAPoison
import content.minigame.barbassault.isBAPoisoned
import content.minigame.barbassault.arena.BarbAssEvent
import content.minigame.barbassault.arena.BarbassaultSession
import content.minigame.barbassault.arena.PenanceType
import content.minigame.barbassault.BA_SESSION_KEY
import content.minigame.barbassault.applyBAPoison
import content.minigame.barbassault.getBASession
import core.api.forceWalk
import core.api.hasLineOfSight
@ -73,15 +74,16 @@ class PenanceHealerNPC : NPCBehavior(*PENANCE_HEALER_IDS) {
val definition = PENANCE_HEALER_DEFINITIONS_BY_ID[self.id] ?: return
self.getSkills().setStaticLevel(Skills.ATTACK, definition.attack)
self.getSkills().setStaticLevel(Skills.STRENGTH, definition.strength)
self.getSkills().setStaticLevel(Skills.DEFENCE, definition.defence)
self.getSkills().setStaticLevel(Skills.RANGE, definition.range)
self.getSkills().setStaticLevel(Skills.MAGIC, definition.magic)
self.getSkills().setLevel(Skills.ATTACK, definition.attack)
self.getSkills().setLevel(Skills.STRENGTH, definition.strength)
self.getSkills().setLevel(Skills.DEFENCE, definition.defence)
self.getSkills().setLevel(Skills.RANGE, definition.range)
self.getSkills().setLevel(Skills.MAGIC, definition.magic)
self.getSkills().setLevel(Skills.HITPOINTS, definition.hp)
self.getSkills().setStaticLevel(Skills.HITPOINTS, definition.hp)
}
//sendMessage(player,"that's the wrong type of poisoned food to use! Penalty!")
override fun tick(self: NPC): Boolean {
val session = self.getAttribute<BarbassaultSession>(BA_SESSION_KEY) ?: return false
@ -113,6 +115,7 @@ class PenanceHealerNPC : NPCBehavior(*PENANCE_HEALER_IDS) {
val target = currentTarget<Player>(self) ?: visiblePlayer(self, session)?.also { setTarget(self, it) }
if (target == null || !isValidPlayerTarget(self, target)) {
clearTarget(self)
wander(self)
return
}
@ -123,17 +126,20 @@ class PenanceHealerNPC : NPCBehavior(*PENANCE_HEALER_IDS) {
self.resetWalk()
self.face(target)
target.impactHandler.manualHit(self, PLAYER_POISON_DAMAGE, ImpactHandler.HitsplatType.POISON)
applyBAPoison(target, self, 6)
if (!isBAPoisoned(target)) {
target.impactHandler.manualHit(self, PLAYER_POISON_DAMAGE, ImpactHandler.HitsplatType.POISON)
applyBAPoison(target, self, 6)
}
clearTarget(self)
self.setAttribute(MODE, HealerMode.TARGET_RUNNER)
self.setAttribute(WANDER_TICKS, WANDER_AFTER_ACTION_TICKS)
self.setAttribute(WANDER_TICKS, 1)
}
private fun tickRunnerTarget(self: NPC, session: BarbassaultSession) {
val target = currentTarget<NPC>(self) ?: visibleRunner(self, session)?.also { setTarget(self, it) }
if (target == null || !isValidRunnerTarget(self, target)) {
clearTarget(self)
wander(self)
return
}

View file

@ -67,6 +67,7 @@ class PenanceRunnerNPC : NPCBehavior(*PENANCE_RUNNER_IDS.toIntArray()) {
return 0.0
}
override fun onCreation(self: NPC) {
self.isRespawn = false
self.isWalks = false
self.walkRadius = 0
self.destinationFlag
@ -95,6 +96,7 @@ class PenanceRunnerNPC : NPCBehavior(*PENANCE_RUNNER_IDS.toIntArray()) {
self.resetWalk()
if (escapeRemoveTicks <= 1) {
session.runnerEscaped(self)
resetAfterEscape(self)
}
return false
}
@ -321,7 +323,8 @@ class PenanceRunnerNPC : NPCBehavior(*PENANCE_RUNNER_IDS.toIntArray()) {
}
private fun isAtEscapeTunnel(session: BarbassaultSession, location: Location): Boolean {
return location.y <= escapeLocation(session).y
val escape = escapeLocation(session)
return location.y <= escape.y || (location.y <= escape.y + 1 && abs(location.x - escape.x) <= 2)
}
private fun beginEscape(self: NPC) {
@ -331,6 +334,19 @@ class PenanceRunnerNPC : NPCBehavior(*PENANCE_RUNNER_IDS.toIntArray()) {
self.setAttribute(ESCAPE_REMOVE_TICKS, 1)
}
private fun resetAfterEscape(self: NPC) {
sendChat(self, "")
clearTarget(self)
self.removeAttribute(SKIP_NEXT_HUNT)
self.removeAttribute(BAD_FOOD_WALK_TICKS)
self.removeAttribute(EAT_PAUSE_TICKS)
self.removeAttribute(ESCAPE_REMOVE_TICKS)
self.setAttribute(MODE, RunnerMode.RANDOM_WALKING)
self.setAttribute(MODE_TICKS, (0..4).random())
self.setAttribute(HUNT_TICKS, (0..2).random())
self.resetWalk()
}
private fun escapeLocation(session: BarbassaultSession): Location {
return session.base.transform(35, 15, 0)
}

View file

@ -9,6 +9,7 @@ import content.minigame.barbassault.getBASession
import core.api.*
import core.game.node.entity.Entity
import core.game.node.entity.combat.DeathTask
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.GameWorld
@ -91,6 +92,7 @@ class DefenderTrap : MapArea {
val bait = goodTrapBait(session, trapLocation) ?: return false
session.destroyGroundItem(bait)
entity.sendChat(GOOD_EAT)
(entity as? NPC)?.let { session.runnerKilledByTrap(it) }
killRunner(entity)
updateTrap(scenery, trapLocation)
session.broadcastToRole(BarbRole.DEFENDER, "A Penance Runner broke a trap to the ${trapDirectionFor(session, trapLocation)}!")

View file

@ -20,13 +20,13 @@ 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
ctx.insultDefender()
if (ctx.poolIdle("BA-Healer: Idling at pool")) return