From 46658026cd50cebfdb1c0b2af3d53563a2173d25 Mon Sep 17 00:00:00 2001 From: Tooze Date: Wed, 10 Jun 2026 23:46:39 -0400 Subject: [PATCH] grounditem Resoawns fixed, Runner escape logic better --- .../barbassault/arena/BAGroundSpawn.kt | 10 +++- .../minigame/barbassault/arena/BASession.kt | 48 +++++++++++++------ .../arena/npcs/PenanceHealerNPC.kt | 28 ++++++----- .../arena/npcs/PenanceRunnerNPC.kt | 18 ++++++- .../barbassault/arena/scenery/DefenderTrap.kt | 2 + .../barbassault/bots/HealerBehavior.kt | 2 +- 6 files changed, 78 insertions(+), 30 deletions(-) diff --git a/Server/src/main/content/minigame/barbassault/arena/BAGroundSpawn.kt b/Server/src/main/content/minigame/barbassault/arena/BAGroundSpawn.kt index a522508db..04d814231 100644 --- a/Server/src/main/content/minigame/barbassault/arena/BAGroundSpawn.kt +++ b/Server/src/main/content/minigame/barbassault/arena/BAGroundSpawn.kt @@ -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 } }) } -} \ No newline at end of file +} diff --git a/Server/src/main/content/minigame/barbassault/arena/BASession.kt b/Server/src/main/content/minigame/barbassault/arena/BASession.kt index 43ec66b4d..724ebedf0 100644 --- a/Server/src/main/content/minigame/barbassault/arena/BASession.kt +++ b/Server/src/main/content/minigame/barbassault/arena/BASession.kt @@ -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("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 diff --git a/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceHealerNPC.kt b/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceHealerNPC.kt index 570bf9296..1b8ed3f8f 100644 --- a/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceHealerNPC.kt +++ b/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceHealerNPC.kt @@ -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(BA_SESSION_KEY) ?: return false @@ -113,6 +115,7 @@ class PenanceHealerNPC : NPCBehavior(*PENANCE_HEALER_IDS) { val target = currentTarget(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(self) ?: visibleRunner(self, session)?.also { setTarget(self, it) } if (target == null || !isValidRunnerTarget(self, target)) { clearTarget(self) + wander(self) return } diff --git a/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceRunnerNPC.kt b/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceRunnerNPC.kt index 529e6c513..1ab97c042 100644 --- a/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceRunnerNPC.kt +++ b/Server/src/main/content/minigame/barbassault/arena/npcs/PenanceRunnerNPC.kt @@ -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) } diff --git a/Server/src/main/content/minigame/barbassault/arena/scenery/DefenderTrap.kt b/Server/src/main/content/minigame/barbassault/arena/scenery/DefenderTrap.kt index a7c96f10a..c1b06988b 100644 --- a/Server/src/main/content/minigame/barbassault/arena/scenery/DefenderTrap.kt +++ b/Server/src/main/content/minigame/barbassault/arena/scenery/DefenderTrap.kt @@ -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)}!") diff --git a/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt index 352715d8b..2a09e5b35 100644 --- a/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt +++ b/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt @@ -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