diff --git a/Server/src/main/content/minigame/barbassault/BarbassDevHelper.kt b/Server/src/main/content/minigame/barbassault/BarbassDevHelper.kt index 8b111916b..a4d4166cb 100644 --- a/Server/src/main/content/minigame/barbassault/BarbassDevHelper.kt +++ b/Server/src/main/content/minigame/barbassault/BarbassDevHelper.kt @@ -32,6 +32,11 @@ class BarbassDevHelper : CommandSet(Privilege.ADMIN) { define("barbqueen"){ player,_-> player.teleport(Location.create(1885, 5403, 0)) } + //nods to the defender guide I found, as "suggested" defender gear. + define("defgear"){ player,_-> + player.equipment.replace(Item(954),2) + + } define("hch"){ player,args-> val chId = args[1].toIntOrNull() diff --git a/Server/src/main/content/minigame/barbassault/arena/BarbScoreManager.kt b/Server/src/main/content/minigame/barbassault/arena/BarbScoreManager.kt index 0d6391f87..b74699cfa 100644 --- a/Server/src/main/content/minigame/barbassault/arena/BarbScoreManager.kt +++ b/Server/src/main/content/minigame/barbassault/arena/BarbScoreManager.kt @@ -2,6 +2,7 @@ package content.minigame.barbassault.arena import content.minigame.barbassault.lobby.BarbTeam import core.game.node.entity.player.Player +//https://www.youtube.com/watch?v=OJ2BDEM03Dw class BarbScoreManager { @@ -20,11 +21,12 @@ class BarbScoreManager { fun personal(player: Player, caps: SpawnCaps): RoleScore { return trackerFor(player).toScoreboard(caps) } - - fun team(team: BarbTeam, caps: SpawnCaps): RoleScore { + //val caps = session.currentWaveCaps() + //val teamScore = session.scoreManager.team(caps) + fun team(caps: SpawnCaps): RoleScore { var total = RoleScore.ZERO - for (player in team.allPlayers()) { - total = total.add(trackerFor(player).toScoreboard(caps)) + for (tracker in allTrackers()) { + total = total.add(tracker.toScoreboard(caps)) } return total } @@ -46,9 +48,19 @@ data class ScoreTracker(var attackerStats: AttackerStats = AttackerStats(), var } fun toScoreboard(caps: SpawnCaps): RoleScore = BarbAssaultScoreBuilder.build(this, caps) } -//Wave spawn counts // may pull from wave to count table latter +val waveCaps = listOf( //i should put this somewhere else + SpawnCaps(4,4,2,2), //wave1 + SpawnCaps(4,5,3,3), + SpawnCaps(6,5,4,3), + SpawnCaps(6,6,4,4), + SpawnCaps(6,6,5,5), + SpawnCaps(7,6,6,6), + SpawnCaps(7,7,6,7), + SpawnCaps(8,7,7,7), + SpawnCaps(8,8,9,8) // wave 9 +) data class SpawnCaps(val rangers: Int, val fighters: Int, val runners: Int, val healers: Int) -data class RoleScore(val rangersKilled: Int, val fightersKilled: Int, val incorrectStylePenalty: Int, + data class RoleScore(val rangersKilled: Int, val fightersKilled: Int, val incorrectStylePenalty: Int, val eggsScore: Int, val runnersKilledScore: Int, val runnersPastPenalty: Int, val healersKilledScore: Int, val hitpointsHealedScore: Int, val wrongPoisonPenalty: Int ) diff --git a/Server/src/main/content/minigame/barbassault/arena/BarbassEvent.kt b/Server/src/main/content/minigame/barbassault/arena/BarbassEvent.kt new file mode 100644 index 000000000..8689376cb --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/arena/BarbassEvent.kt @@ -0,0 +1,36 @@ +package content.minigame.barbassault.arena + +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player + +sealed class BarbAssEvent { + data class NPCDied(val npc: NPC, val killer: Player) : BarbAssEvent() + data class EggCollected(val player: Player, val count: Int) : BarbAssEvent() + data class HitpointsHealed(val player: Player, val amount: Int) : BarbAssEvent() + data class WrongPoisonUsed(val player: Player) : BarbAssEvent() + +} +class BarbAssEventBus { + private val listeners = mutableMapOf, MutableList<(BarbAssEvent) -> Unit>>() + private val pendingEvents = mutableListOf() + + fun register(eventType: Class, listener: (T) -> Unit) { + listeners.computeIfAbsent(eventType) { mutableListOf() }.add { listener(it as T) } + } + + fun emit(event: BarbAssEvent) { + pendingEvents.add(event) + } + + fun processEvents() { + for (event in pendingEvents) { + listeners[event::class.java]?.forEach { it.invoke(event) } + } + pendingEvents.clear() + } + + fun clear() { + listeners.clear() + } +} + diff --git a/Server/src/main/content/minigame/barbassault/arena/BarbassaultSession.kt b/Server/src/main/content/minigame/barbassault/arena/BarbassaultSession.kt index fc460e175..73e6cfccd 100644 --- a/Server/src/main/content/minigame/barbassault/arena/BarbassaultSession.kt +++ b/Server/src/main/content/minigame/barbassault/arena/BarbassaultSession.kt @@ -5,6 +5,7 @@ import content.minigame.barbassault.BarbassaultActivity import content.minigame.barbassault.arena.scenery.EggCannon import content.minigame.barbassault.arena.scenery.GloryHorn import content.minigame.barbassault.lobby.BarbTeam +import content.minigame.barbassault.lobby.BarbassaultLobby import content.minigame.barbassault.lobby.baSession import core.api.* import core.game.node.entity.Entity @@ -23,6 +24,7 @@ import core.tools.Log import core.tools.secondsToTicks import core.tools.ticksToSeconds import org.rs09.consts.Components +import org.rs09.consts.Items import org.rs09.consts.Music.ASSAULT_AND_BATTERY_604 import org.rs09.consts.NPCs @@ -42,7 +44,7 @@ Player enum class BarbassaultState { PARTY_CREATION, STARTING, IN_ARENA,FORFEIT, COMPLETE, END } -class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea { +class BarbassaultSession( val activity: BarbassaultActivity ? = null) :LogoutListener, MapArea { constructor(region: DynamicRegion, activity: BarbassaultActivity) : this(activity) {this.region = region; this.base = region.baseLocation} lateinit var region: DynamicRegion @@ -55,6 +57,10 @@ class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea val groundItems = mutableListOf() val eggHopper = EggCannon.EggHopper() val scoreManager = BarbScoreManager() + val eventBus = BarbAssEventBus() + val npcCaps = SpawnCaps(4,4,2,2)//wave 1 + + fun beginStartingPhase() { if (state != BarbassaultState.PARTY_CREATION) return @@ -64,6 +70,7 @@ class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea } private fun enterArena() { + state = BarbassaultState.IN_ARENA region.setMusicId(ASSAULT_AND_BATTERY_604) @@ -90,6 +97,13 @@ class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea // https://www.youtube.com/watch?v=vYKbHNZn80w destroyArena() } + override fun logout(player: Player) { + if (!defineAreaBorders().any { it.insideBorder(player.location) }) { + return + } + + player.properties.teleportLocation = Location.create(2593, 5264, 0) + } private fun startCountdown() { var ticks = secondsToTicks(12) @@ -120,20 +134,60 @@ class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea } }) } + private fun InitEvents(){ + + eventBus.register(BarbAssEvent.NPCDied::class.java) { event -> + val tracker = scoreManager.trackerFor(event.killer) + val npcRoleType = event.npc.getAttribute("barbass-role") + when (npcRoleType) { + BarbRole.ATTACKER -> tracker.attackerStats.rangersKilled++ + BarbRole.DEFENDER -> tracker.defenderStats.runnersKilled++ + BarbRole.HEALER -> tracker.healerStats.healersKilled++ + else -> {} + } + } + + eventBus.register(BarbAssEvent.EggCollected::class.java) { event -> + val tracker = scoreManager.trackerFor(event.player) + tracker.collectorStats.eggsCollected += event.count + } + + eventBus.register(BarbAssEvent.HitpointsHealed::class.java) { event -> + val tracker = scoreManager.trackerFor(event.player) + tracker.healerStats.hitpointsReplenished += event.amount + } + + eventBus.register(BarbAssEvent.WrongPoisonUsed::class.java) { event -> + val tracker = scoreManager.trackerFor(event.player) + tracker.healerStats.wrongPoisonUsed++ + } + } private inner class GamePulse : Pulse(1) { private var roleCallTicks = secondsToTicks(30) - + private var waveSpawns = secondsToTicks(6) override fun pulse(): Boolean { + if (state != BarbassaultState.IN_ARENA) return true + if (state == BarbassaultState.FORFEIT){ + eventBus.clear() + scoreManager.resetAll() + BarbassaultLobby.TeamToLobby(team,team.wave) + + } + if (state == BarbassaultState.COMPLETE){ + //advance to next wave lobby! + BarbassaultLobby.TeamToLobby(team,team.wave+1) + } + + eventBus.processEvents() roleCallTicks-- if (roleCallTicks <= 0) { rollNewRoleCalls() roleCallTicks = secondsToTicks(30) } - // TODO: wave logic, timers, win/lose - // reSpawnItems + return false } } @@ -142,21 +196,31 @@ class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea region = DynamicRegion.create(BarbassaultGameArea.BA_ARENA.MAIN) base = region.baseLocation zone.register(getRegionBorders(region.id)) + + region.toggleMulticombat() spawnEggCannons() } private fun destroyArena() { - if (!this::region.isInitialized) return + if (!this::region.isInitialized) return zone.unregister(getRegionBorders(region.id)) region.clear() + region.flagInactive() + } private fun handleLogout(player: Player) { + state = BarbassaultState.FORFEIT + zone.cleanItems(player,arrayOf(Item(ATTACKER_ICON),Item(DEFENDER_ICON),Item(COLLECTOR_ICON),Item(HEALER_ICON))) + + region.remove(player) team.removePlayer(player) - player.properties.teleportLocation = Location.create(2593, 5264, 0) player.locks.unlockTeleport() + // player.properties.teleportLocation = Location.create(2593, 5264, 0) + player.location = Location.create(2593, 5264, 0) if (team.allPlayers().isEmpty()) { + player.properties.teleportLocation = Location.create(2593, 5264, 0) endSession() } } @@ -170,6 +234,7 @@ class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea ZoneRestriction.TELEPORT ) + override fun areaEnter(entity: Entity) { log(this::class.java, Log.FINE, "ENTERED Barbassault Arena") @@ -186,13 +251,20 @@ class BarbassaultSession( val activity: BarbassaultActivity ? = null) : MapArea override fun areaLeave(entity: Entity, logout: Boolean) { log(this::class.java, Log.FINE, "LEFT Barbassault Arena") + super.areaLeave(entity, logout) var player = entity as Player //exitMiniGame(player) removeTimer(player, "teleblock") + zone.cleanItems(player,arrayOf(Item(ATTACKER_ICON),Item(DEFENDER_ICON),Item(COLLECTOR_ICON),Item(HEALER_ICON))) + //region.remove(player) + clearLogoutListener(player, "ba-logout") + + destroyArena() } fun sessionNPCSpawn(id: Int, location: Location, direction: Direction, vararg objects: Any): NPC? { val npc = NPC.create(id, location, direction, *objects) npc.init() + sessionNpcs.add(npc) return npc } diff --git a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceFighterNPC.kt b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceFighterNPC.kt index ee678d5e3..2e5152b15 100644 --- a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceFighterNPC.kt +++ b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceFighterNPC.kt @@ -1,7 +1,11 @@ package content.minigame.barbassault.arenas.monsters +import content.minigame.barbassault.BarbRole import content.minigame.barbassault.arena.BaHornSystem +import content.minigame.barbassault.arena.BarbAssEvent +import content.minigame.barbassault.lobby.baSession import core.api.* +import core.game.container.impl.EquipmentContainer import core.game.node.entity.Entity import core.game.node.entity.combat.BattleState import core.game.node.entity.combat.CombatStyle @@ -34,10 +38,60 @@ class PenanceFighterNPC : NPCBehavior(*PENANCE_FIGHTER_IDS.toIntArray()) { return 0.0 } override fun beforeDamageReceived(self: NPC, attacker: Entity, state: BattleState) { + attacker as Player val firstBefore = state.estimatedHit - //I should set a value in my players session instead of scanning the inventory every time for a horn. - state.estimatedHit = firstBefore + (BaHornSystem.HornHelper.getAttackerHorn(attacker as Player)?.ordinal?.plus(1) ?: 0) +1 + //I should read my players level instead of scanning the inventory every time for a horn. + var toDamage = firstBefore + (BaHornSystem.HornHelper.getAttackerHorn(attacker)?.ordinal?.plus(1) ?: 0) +1 + //if wrong attack recoil 1 damage to player. + val attackStyle = attacker.properties.attackStyle.style + val combatType = state.style + when (combatType) { + CombatStyle.MELEE -> { + when (attackStyle) { + 0 -> sendMessage(attacker, "Melee: Accurate") + 1 -> sendMessage(attacker, "Melee: Aggressive") + 2 -> sendMessage(attacker, "Melee: Controlled") + 3 -> sendMessage(attacker, "Melee: Defensive") + else -> { + toDamage = 0 + sendMessage(attacker, "Melee: Unknown style") + } + } + } + + CombatStyle.RANGE -> { + val arrows = attacker.equipment.get(EquipmentContainer.SLOT_ARROWS).name + sendMessage(attacker, "Ranged attack, Arrows: $arrows") + + val ammunitionID = state.ammunition.itemId + when(ammunitionID){ + 882 -> "bronze" + 884 -> "iron" + 886 -> "steel" + 888 -> "mithril" + else -> { + toDamage = 0 + sendMessage(attacker,"Only allowed to use provided arrows.")} + } + + + } + CombatStyle.MAGIC -> { + val castSpell = state.spell.spellId + when(castSpell){ + 1,10,24,45 -> sendMessage(attacker, "Magic spell: Air") + 4,14,27,48 -> sendMessage(attacker, "Magic spell: Water") + 6,17,66,52 -> sendMessage(attacker, "Magic spell: Earth") + 8,20,38,55 -> sendMessage(attacker, "Magic spell: Fire") + else -> { + toDamage = 0 + } + } + } + } + + state.estimatedHit = toDamage } override fun onCreation (self: NPC) { self.setAttribute("agg_radius",2) @@ -47,10 +101,20 @@ class PenanceFighterNPC : NPCBehavior(*PENANCE_FIGHTER_IDS.toIntArray()) { self.isAggressive = true self.isRespawn = false + self.setAttribute("barbass-role", BarbRole.ATTACKER) + self.definition.combatDistance = 1 self.properties.combatPulse.style = CombatStyle.MELEE } + + override fun onDeathFinished(self: NPC, killer: Entity) { + super.onDeathFinished(self, killer) + val player = killer as? Player ?: return + val session = player.baSession ?: return + + session.eventBus.emit(BarbAssEvent.NPCDied(self,player)) + } } //Shrink death 5098 diff --git a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceHealerNPC.kt b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceHealerNPC.kt index 37f77737c..bb8922302 100644 --- a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceHealerNPC.kt +++ b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceHealerNPC.kt @@ -1,8 +1,12 @@ package content.minigame.barbassault.arena.monsters +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BarbAssEvent +import content.minigame.barbassault.lobby.baSession import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPCBehavior +import core.game.node.entity.player.Player import org.rs09.consts.NPCs val PENANCE_HEALER_IDS = listOf( @@ -22,8 +26,20 @@ class PenanceHealerNPC : NPCBehavior(*PENANCE_HEALER_IDS.toIntArray()) { return 0.0 } + + override fun onCreation (self: NPC) { + self.setAttribute("barbass-role", BarbRole.HEALER) + } //sendMessage(player,"that's the wrong type of poisoned food to use! Penalty!") + override fun onDeathFinished(self: NPC, killer: Entity) { + super.onDeathFinished(self, killer) + val player = killer as? Player ?: return + val session = player.baSession ?: return + + session.eventBus.emit(BarbAssEvent.NPCDied(self,player)) + } + } /* diff --git a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceQueenNPC.kt b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceQueenNPC.kt index 1fe23f59f..ae54b9612 100644 --- a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceQueenNPC.kt +++ b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceQueenNPC.kt @@ -8,6 +8,7 @@ import core.game.node.entity.npc.NPCBehavior import core.game.node.entity.player.Player import org.rs09.consts.NPCs +//.configureBossData() class PenanceQueenNPC : NPCBehavior(NPCs.PENANCE_QUEEN_5247){ override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean { if (attacker is Player ) { @@ -19,6 +20,7 @@ class PenanceQueenNPC : NPCBehavior(NPCs.PENANCE_QUEEN_5247){ override fun getXpMultiplier(self: NPC, attacker: Entity): Double { return 0.0 } + } diff --git a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRangerNPC.kt b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRangerNPC.kt index 3e6ad2706..b7df12f1c 100644 --- a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRangerNPC.kt +++ b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRangerNPC.kt @@ -1,5 +1,8 @@ package content.minigame.barbassault.arena.monsters +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BarbAssEvent +import content.minigame.barbassault.lobby.baSession import core.api.* import core.api.getItemFromEquipment import core.game.node.entity.Entity @@ -40,10 +43,20 @@ class PenanceRangerNPC : NPCBehavior(*PENANCE_RANGER_IDS.toIntArray()) { self.walkRadius = 64 self.isAggressive = true + self.setAttribute("barbass-role",BarbRole.ATTACKER) + self.definition.combatDistance = 8 self.properties.combatPulse.style = CombatStyle.RANGE } + override fun onDeathFinished(self: NPC, killer: Entity) { + super.onDeathFinished(self, killer) + val player = killer as? Player ?: return + val session = player.baSession ?: return + + session.eventBus.emit(BarbAssEvent.NPCDied(self,player)) + } + } diff --git a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRunnerNPC.kt b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRunnerNPC.kt index fcfa6b04d..6907e2d12 100644 --- a/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRunnerNPC.kt +++ b/Server/src/main/content/minigame/barbassault/arena/monsters/PenanceRunnerNPC.kt @@ -1,14 +1,17 @@ package content.minigame.barbassault.arena.monsters +import content.minigame.barbassault.BarbRole import core.game.node.entity.Entity import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPCBehavior import core.game.world.map.Location import org.rs09.consts.NPCs import content.minigame.barbassault.arena.* +import content.minigame.barbassault.lobby.baSession import core.api.forceWalk import core.api.removeGroundItem import core.api.sendChat +import core.game.node.entity.player.Player import core.game.node.item.GroundItem import core.game.node.item.GroundItemManager @@ -38,6 +41,8 @@ class PenanceRunnerNPC : NPCBehavior(*PENANCE_RUNNER_IDS.toIntArray()) { self.walkRadius = 22 self.destinationFlag + self.setAttribute("barbass-role", BarbRole.DEFENDER) + } override fun tick(self: NPC): Boolean { @@ -59,8 +64,13 @@ class PenanceRunnerNPC : NPCBehavior(*PENANCE_RUNNER_IDS.toIntArray()) { fun seekFood(){ } + override fun onDeathFinished(self: NPC, killer: Entity) { + super.onDeathFinished(self, killer) + val player = killer as? Player ?: return + val session = player.baSession ?: return - + session.eventBus.emit(BarbAssEvent.NPCDied(self,player)) + } } diff --git a/Server/src/main/content/minigame/barbassault/lobby/BarbassaultLobby.kt b/Server/src/main/content/minigame/barbassault/lobby/BarbassaultLobby.kt index b58bf681e..4bea7e04c 100644 --- a/Server/src/main/content/minigame/barbassault/lobby/BarbassaultLobby.kt +++ b/Server/src/main/content/minigame/barbassault/lobby/BarbassaultLobby.kt @@ -23,8 +23,9 @@ import org.rs09.consts.Items import org.rs09.consts.Scenery import org.rs09.consts.Sounds - +//https://www.youtube.com/watch?v=0d5I97HLUEs ending of video shows we are allowed capes in lap but not wave rooms //"-- Next wave no longer starting" +// The game ended early because one of your team-mated died. private var activity: BarbassaultActivity? = null class BarbassaultLobby : InteractionListener, MapArea { @@ -302,18 +303,25 @@ class BarbassaultLobby : InteractionListener, MapArea { } } } - fun waveAdvance(player: Player) { - val wave = player.getAttribute("barbass:wave", 1) - if (wave in 1..waveLobbies.size) { - val targetLobby = waveLobbies[wave] - teleport(player, targetLobby.randomWalkableLoc) - if (wave == 10) {player.setAttribute("/save:barbass:wave", 1)} - } else { - println("Invalid wave number: $wave") - } - } companion object { + fun TeamToLobby(team: BarbTeam, wave: Int) { + if (wave in 1..waveLobbies.size) { + val targetLobby = waveLobbies[wave] + for (player in team.allPlayers()) { + teleport(player, targetLobby.randomWalkableLoc) + } + } + } + fun waveAdvance(player: Player) { + val wave = player.getAttribute("barbass:wave", 1) + if (wave in 1..waveLobbies.size) { + if (wave == 10) {player.setAttribute("/save:barbass:wave", 1)} + } else { + println("Invalid wave number: $wave") + } + } + // Locations val QUICK_START: ZoneBorders = ZoneBorders(2595, 5278, 2610, 5271, 0) val MAIN_LOBBY: ZoneBorders = ZoneBorders(2588, 5266, 2597, 5261, 0)