mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-20 18:05:13 -06:00
Merge branch 'master' into 'master'
Draft: Barb Assault: Progressing See merge request 2009scape/2009scape!2115
This commit is contained in:
commit
0c027bd77b
60 changed files with 7970 additions and 67 deletions
128
Server/src/main/content/minigame/barbassault/BABlackBoard.kt
Normal file
128
Server/src/main/content/minigame/barbassault/BABlackBoard.kt
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import core.api.*
|
||||
import core.game.component.Component
|
||||
import core.game.node.entity.player.Player
|
||||
import org.rs09.consts.Components
|
||||
|
||||
data class RoleChildIds(
|
||||
val chpId: Int,
|
||||
val levelId: Int,
|
||||
val rewardNextLevelId: Int,
|
||||
val pointsNextLevelId: Int
|
||||
)
|
||||
data class RoleDisplayValues(
|
||||
val chpId: Int,
|
||||
val levelId: Int,
|
||||
val rewardNextLevelId: Int,
|
||||
val pointsNextLevelId: Int,
|
||||
val rewardText: String,
|
||||
val pointsText: String
|
||||
)
|
||||
|
||||
data class RewardInfo(
|
||||
val reward: String,
|
||||
val pointsToNextLevel: String
|
||||
)
|
||||
|
||||
class BarbassBlackBoard {
|
||||
companion object {
|
||||
const val PLAYER_NAME = 19
|
||||
const val CURRENT_WAVE = 25
|
||||
|
||||
val roleComponents: Map<BarbRole, RoleChildIds> = mapOf(
|
||||
BarbRole.ATTACKER to RoleChildIds(20,15,27,10),
|
||||
BarbRole.DEFENDER to RoleChildIds(21,16,28,11),
|
||||
BarbRole.COLLECTOR to RoleChildIds(22,17,29,12),
|
||||
BarbRole.HEALER to RoleChildIds(23,18,30,13)
|
||||
)
|
||||
|
||||
fun getRewardInfo(role: BarbRole, level: Int): RewardInfo {
|
||||
val reward = when (role) {
|
||||
BarbRole.ATTACKER -> when (level) {
|
||||
1 -> "+2 bonus damage"
|
||||
2 -> "+3 bonus damage"
|
||||
3 -> "+4 bonus damage"
|
||||
4 -> "+5 bonus damage"
|
||||
else -> " - Mastered - "
|
||||
}
|
||||
|
||||
BarbRole.DEFENDER -> when (level) {
|
||||
1 -> "Lure range 5"
|
||||
2 -> "Lure range 6"
|
||||
3 -> "Lure range 8"
|
||||
4 -> "Lure range 10"
|
||||
else -> " - Mastered - "
|
||||
}
|
||||
//https://youtu.be/wb1InggbaZc?t=57
|
||||
BarbRole.COLLECTOR -> when (level) {
|
||||
1 -> "Egg convert success 20%"
|
||||
2 -> "Egg convert success 40%"
|
||||
3 -> "Egg convert success 60%"
|
||||
4 -> "Egg convert success 80%"
|
||||
else -> " - Mastered - "
|
||||
}
|
||||
|
||||
BarbRole.HEALER -> when (level) {
|
||||
1 -> "Heal 15 points"
|
||||
2 -> "Heal 20 points"
|
||||
3 -> "Heal 25 points"
|
||||
4 -> "Heal 35 points"
|
||||
else -> " - Mastered - "
|
||||
}
|
||||
}
|
||||
|
||||
val points = getPointsTillNextLevel(level)
|
||||
return RewardInfo(reward, points)
|
||||
}
|
||||
|
||||
fun getPointsTillNextLevel(level: Int): String {
|
||||
return when (level) {
|
||||
1 -> "200"
|
||||
2 -> "300"
|
||||
3 -> "400"
|
||||
4 -> "500"
|
||||
else -> "---"
|
||||
}
|
||||
}
|
||||
fun getAllRoleValues(role: BarbRole, level: Int): RoleDisplayValues {
|
||||
val ids = roleComponents[role]
|
||||
val rewardInfo = getRewardInfo(role, level)
|
||||
|
||||
return RoleDisplayValues(
|
||||
ids!!.chpId, ids.levelId, ids.rewardNextLevelId, ids.pointsNextLevelId,
|
||||
rewardInfo.reward, rewardInfo.pointsToNextLevel
|
||||
)
|
||||
}
|
||||
|
||||
fun updateBlackBoard(player: Player) {
|
||||
player.interfaceManager.open(Component(Components.BARBASSAULT_PLAYERSTAT_490))
|
||||
setInterfaceText(player, player.username, Components.BARBASSAULT_PLAYERSTAT_490, PLAYER_NAME)
|
||||
setInterfaceText(player, getBAWave(player).toString(), Components.BARBASSAULT_PLAYERSTAT_490, CURRENT_WAVE)
|
||||
|
||||
val playerLevel = getBALevels(player)
|
||||
val playerPoints = getBAPoints(player)
|
||||
|
||||
for (role in BarbRole.values()) {
|
||||
val level = when (role) {
|
||||
BarbRole.ATTACKER -> playerLevel.atk
|
||||
BarbRole.DEFENDER -> playerLevel.def
|
||||
BarbRole.COLLECTOR -> playerLevel.col
|
||||
BarbRole.HEALER -> playerLevel.heal
|
||||
}
|
||||
val points = when (role) {
|
||||
BarbRole.ATTACKER -> playerPoints.atk
|
||||
BarbRole.DEFENDER -> playerPoints.def
|
||||
BarbRole.COLLECTOR -> playerPoints.col
|
||||
BarbRole.HEALER -> playerPoints.heal
|
||||
}
|
||||
val roleValues = getAllRoleValues(role, level)
|
||||
|
||||
setInterfaceText(player, points.toString(), 490, roleValues.chpId)
|
||||
setInterfaceText(player, level.toString(), 490, roleValues.levelId)
|
||||
setInterfaceText(player, roleValues.rewardText, 490, roleValues.rewardNextLevelId)
|
||||
setInterfaceText(player, roleValues.pointsText, 490, roleValues.pointsNextLevelId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
228
Server/src/main/content/minigame/barbassault/BADevHelper.kt
Normal file
228
Server/src/main/content/minigame/barbassault/BADevHelper.kt
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import content.minigame.barbassault.bots.oldbot.BABot
|
||||
import content.minigame.barbassault.lobby.BALobby
|
||||
import core.api.*
|
||||
import core.game.container.impl.EquipmentContainer
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.command.Privilege
|
||||
import core.game.system.command.sets.CommandSet
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.repository.Repository
|
||||
import core.plugin.Initializable
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
import content.minigame.barbassault.bots.SmartBAPlayerScript
|
||||
import content.minigame.barbassault.bots.SmartBABot
|
||||
import core.game.bots.AIPlayer
|
||||
import core.game.bots.GeneralBotCreator
|
||||
|
||||
@Initializable
|
||||
class BADevHelper : CommandSet(Privilege.ADMIN) {
|
||||
var babotcount = 0
|
||||
|
||||
override fun defineCommands() {
|
||||
define ("maxbapoints") { player,_ ->
|
||||
addBAPoints(player,BarbAssaultPoints(500, 500, 500,500))
|
||||
return@define
|
||||
}
|
||||
define ("setbawave") { player,args ->
|
||||
setBAWave(player,args[1].toInt())
|
||||
return@define
|
||||
}
|
||||
|
||||
define ("resetbapoints") { player,_ ->
|
||||
setBAPoints(player,BarbAssaultPoints(0, 0, 0,0))
|
||||
return@define
|
||||
}
|
||||
define ("resetbalevels") { player,_ ->
|
||||
setBALevels(player,BarbAssaultLevels(0, 0, 0,0))
|
||||
return@define
|
||||
}
|
||||
define("barbgame"){ player,_->
|
||||
player.teleport(Location.create(1886, 5467, 0))
|
||||
return@define
|
||||
}
|
||||
define("barbqueen"){ player,_->
|
||||
player.teleport(Location.create(1885, 5403, 0))
|
||||
return@define
|
||||
}
|
||||
//nods to the defender guide I found, as "suggested" defender gear.
|
||||
define("defgear"){ player,_->
|
||||
player.equipment.replace(Item(Items.ROPE_954),EquipmentContainer.SLOT_AMULET)
|
||||
return@define
|
||||
}
|
||||
define("eggloot"){ player,_->
|
||||
content.minigame.barbassault.arena.npcs.dropPenanceEggCluster(player)
|
||||
return@define
|
||||
}
|
||||
define("cleanfloor"){ player,_->
|
||||
val session = getBASession(player) ?: return@define
|
||||
session.clearGroundItems()
|
||||
return@define
|
||||
}
|
||||
define("spawnwave"){ player,_->
|
||||
getBASession(player)?.forceWaveSpawn()
|
||||
return@define
|
||||
}
|
||||
define("spawnwaveforce"){ player,_->
|
||||
getBASession(player)?.forceWaveSpawn(true)
|
||||
return@define
|
||||
}
|
||||
define("babot"){ player,_->
|
||||
if (babotcount >= 25) {
|
||||
sendMessage(player, "25 is max amount of BA bots allowed")
|
||||
}else {
|
||||
BABot(BALobby.MAIN_LOBBY.randomWalkableLoc)
|
||||
babotcount++
|
||||
}
|
||||
return@define
|
||||
|
||||
}
|
||||
define("smartbabot") { player, _ ->
|
||||
if (babotcount >= 25) {
|
||||
sendMessage(player, "25 is max amount of BA bots allowed")
|
||||
return@define
|
||||
}
|
||||
|
||||
SmartBABot(BALobby.MAIN_LOBBY.randomWalkableLoc)
|
||||
|
||||
babotcount++
|
||||
sendMessage(player, "Spawned Smart BA bot.")
|
||||
return@define
|
||||
}
|
||||
|
||||
define("smartbaplayer") { player, _ ->
|
||||
GeneralBotCreator(SmartBAPlayerScript(), player, true)
|
||||
sendMessage(player, "Started Smart BA bot script on your player.")
|
||||
return@define
|
||||
}
|
||||
|
||||
define("babotstate") { player, args ->
|
||||
val nameFilter = args.getOrNull(1)?.lowercase()
|
||||
val bots = Repository.players
|
||||
.filterIsInstance<AIPlayer>()
|
||||
.filter { nameFilter == null || it.username.lowercase().contains(nameFilter) }
|
||||
|
||||
val bot = bots.minByOrNull { it.location.getDistance(player.location) }
|
||||
if (bot == null) {
|
||||
sendMessage(player, "No BA bot found.")
|
||||
return@define
|
||||
}
|
||||
|
||||
sendMessage(player, "${bot.username}: ${bot.customState} : loc: ${bot.location}")
|
||||
return@define
|
||||
}
|
||||
define("iswait"){player,_ ->
|
||||
val iswait = BALobby.isWaitingArea(player.location)
|
||||
sendMessage(player,"isWaiting : ${iswait}")
|
||||
}
|
||||
define("ishall"){player,_ ->
|
||||
val ishall = BALobby.isInHalls(player.location)
|
||||
sendMessage(player,"isInhall : ${ishall}")
|
||||
}
|
||||
|
||||
define("hch"){ player,args->
|
||||
val chId = args[1].toIntOrNull()
|
||||
if (chId != null) {
|
||||
player.packetDispatch.sendInterfaceConfig(488, chId,true)
|
||||
}
|
||||
return@define
|
||||
}
|
||||
define("vch"){ player,args->
|
||||
val chId = args[1].toIntOrNull()
|
||||
if (chId != null) {
|
||||
player.packetDispatch.sendInterfaceConfig(488, chId,false)
|
||||
}
|
||||
return@define
|
||||
}
|
||||
define("setifacemodel") { player, args ->
|
||||
val modelId = args.getOrNull(1)?.toIntOrNull() ?: return@define
|
||||
val iface = args.getOrNull(2)?.toIntOrNull() ?: return@define
|
||||
val child = args.getOrNull(3)?.toIntOrNull() ?: return@define
|
||||
|
||||
val zoom = args.getOrNull(4)?.toIntOrNull() ?: 0
|
||||
val pitch = args.getOrNull(5)?.toIntOrNull() ?: 0
|
||||
val yaw = args.getOrNull(6)?.toIntOrNull() ?: 0
|
||||
|
||||
setInterfaceModel(player, modelId, iface, child, zoom, pitch, yaw)
|
||||
}
|
||||
//layer.packetDispatch.sendRepositionOnInterface(HealerIface.ID, 24, 45, 46)
|
||||
define("setifaceoffset") { player, args ->
|
||||
val iface = args.getOrNull(1)?.toIntOrNull() ?: return@define
|
||||
val child = args.getOrNull(2)?.toIntOrNull() ?: return@define
|
||||
|
||||
val posX = args.getOrNull(3)?.toIntOrNull() ?: 0
|
||||
val posY = args.getOrNull(4)?.toIntOrNull() ?: 0
|
||||
|
||||
player.packetDispatch.sendRepositionOnInterface(iface, child, posX, posY)
|
||||
}
|
||||
//sendItemZoomOnInterface(int itemId, int zoom, int interfaceId, int childId)
|
||||
define("setifaceitem") { player, args ->
|
||||
val iface = args.getOrNull(1)?.toIntOrNull() ?: return@define
|
||||
val child = args.getOrNull(2)?.toIntOrNull() ?: return@define
|
||||
|
||||
val itemId = args.getOrNull(3)?.toIntOrNull() ?: 0
|
||||
val zoom = args.getOrNull(4)?.toIntOrNull() ?: 0
|
||||
|
||||
sendItemZoomOnInterface(player,itemId, zoom, iface, child)
|
||||
}
|
||||
|
||||
define("trap"){ player,args->
|
||||
var thistrap = Location.create(1901, 5474, 0)
|
||||
var thistrapscen = core.game.node.scenery.Scenery(Scenery.RUNNER_TRAP2_20135, Location(1901, 5474))
|
||||
// RUNNER_TRAP2_20135
|
||||
// RUNNER_TRAP1_20230
|
||||
// BROKEN_TRAP0_20231
|
||||
val scenery = getScenery(thistrap)
|
||||
val emoteId = args[1].toIntOrNull()
|
||||
animateScenery(scenery!!, emoteId!!)//5076
|
||||
|
||||
//replaceScenery(getScenery(thistrap)!!,Scenery.RUNNER_TRAP1_20230,40,thistrap)
|
||||
return@define
|
||||
}
|
||||
//should not need during testing now.
|
||||
define("rolekit", Privilege.ADMIN, "<role> <level>", "Gives Barbarian Assault kit") { player, args ->
|
||||
data class RoleKit( val horns: IntArray? = null, val bags: IntArray? = null, val extraItems: List<Int> = emptyList() )
|
||||
val roleKits = mapOf(
|
||||
"healer" to RoleKit(
|
||||
horns = intArrayOf(Items.HEALER_HORN_10526,Items.HEALER_HORN_10527,Items.HEALER_HORN_10528,Items.HEALER_HORN_10529,Items.HEALER_HORN_10530 ),
|
||||
extraItems = listOf(10559,Items.HEALING_VIAL_10546, Items.POISONED_WORMS_10540, Items.POISONED_TOFU_10539,Items.POISONED_MEAT_10541)
|
||||
),
|
||||
"attacker" to RoleKit(
|
||||
horns = intArrayOf(Items.ATTACKER_HORN_10516,Items.ATTACKER_HORN_10517,Items.ATTACKER_HORN_10518,Items.ATTACKER_HORN_10519,Items.ATTACKER_HORN_10520),
|
||||
extraItems = listOf(10556)
|
||||
),
|
||||
"defender" to RoleKit(
|
||||
horns = intArrayOf(Items.DEFENDER_HORN_10538),
|
||||
extraItems = listOf(10558,Items.DEFENDER_HORN_10538,Items.WORMS_10515,Items.CRACKERS_10513,Items.TOFU_10514)
|
||||
),
|
||||
"collector" to RoleKit(
|
||||
horns = intArrayOf(Items.COLLECTION_BAG_10521, Items.COLLECTION_BAG_10522, Items.COLLECTION_BAG_10523, Items.COLLECTION_BAG_10524, Items.COLLECTION_BAG_10525),
|
||||
extraItems = listOf(10557,Items.COLLECTOR_HORN_10560)
|
||||
)
|
||||
)
|
||||
|
||||
if (args.size < 3) {
|
||||
sendMessage(player,"Usage: ::rolekit <healer|attacker|collector|defender> <level 1-5>")
|
||||
return@define
|
||||
}
|
||||
|
||||
val roleName = args[1].lowercase()
|
||||
val level = args[2].toIntOrNull()
|
||||
if (level == null || level !in 1..5) {
|
||||
sendMessage(player,"Invalid level. Use a number between 1 and 5.")
|
||||
return@define
|
||||
}
|
||||
val role = roleKits[roleName]
|
||||
if (role == null) {
|
||||
sendMessage(player,"Unknown role: $roleName. Use healer, attacker, defender, or collector.")
|
||||
return@define
|
||||
}
|
||||
player.inventory.add(Item(role.horns?.get(level - 1) ?:1 ))
|
||||
role.extraItems.forEach { player.inventory.add(Item(it)) }
|
||||
sendMessage(player,"Gave $roleName kit for level $level.")
|
||||
return@define
|
||||
}
|
||||
}
|
||||
}
|
||||
142
Server/src/main/content/minigame/barbassault/BAListeners.kt
Normal file
142
Server/src/main/content/minigame/barbassault/BAListeners.kt
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
|
||||
import content.minigame.barbassault.BarbassBlackBoard.Companion.updateBlackBoard
|
||||
import core.api.*
|
||||
import core.game.component.Component
|
||||
import core.game.global.action.ClimbActionHandler
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.map.Location
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
class BAListeners : InteractionListener {
|
||||
|
||||
override fun defineListeners() {
|
||||
// addClimbDest(Location.create(2593, 5261, 0),Location.create(2593, 5261, 0))
|
||||
on(Scenery.LADDER_20226, IntType.SCENERY, "Climb-down") { player, _ ->
|
||||
// if (GameWorld.settings?.enable_barbassault != true) return@on false
|
||||
//todo players are allowed to wear capes in to the lobby, But not the Wave Rooms
|
||||
if (joinError(player)) return@on true
|
||||
val loc = Location(2593 , 5261 )
|
||||
ClimbActionHandler.climb(player, ClimbActionHandler.CLIMB_DOWN, loc)
|
||||
face(player,Location(2593, 5262))
|
||||
return@on true
|
||||
|
||||
}
|
||||
on(Scenery.LADDER_20227, IntType.SCENERY, "Climb-up") { player, _ ->
|
||||
val loc = Location(2535 , 3572 )
|
||||
player.inventory.removeAll(Items.SCROLL_10512)
|
||||
ClimbActionHandler.climb(player, ClimbActionHandler.CLIMB_UP, loc)
|
||||
face(player,Location(2533, 3572))
|
||||
return@on true
|
||||
|
||||
}
|
||||
on(Scenery.BLACKBOARD_20134, IntType.SCENERY, "Read") { player, _ ->
|
||||
//emote 5354
|
||||
//todo Are we suppose to animate while reading?
|
||||
updateBlackBoard(player)
|
||||
return@on true
|
||||
|
||||
}
|
||||
on(NPCs.COMMANDER_CONNAD_5029, IntType.NPC, "Get-rewards") { player, _ ->
|
||||
player.interfaceManager.open(Component(Components.BARBASSAULT_REWARD_SHOP_491))
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(NPCs.CAPTAIN_CAIN_5030, IntType.NPC, "Tutorial") { player, _ ->
|
||||
player.interfaceManager.open(Component(Components.BARBASSAULT_TUTORIAL_496))
|
||||
return@on true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun forbiddenItemsCheck(player: Player): String? {
|
||||
val forbiddenRunes = setOf(
|
||||
Items.AIR_RUNE_556,
|
||||
Items.FIRE_RUNE_554,
|
||||
Items.EARTH_RUNE_557,
|
||||
Items.WATER_RUNE_555,
|
||||
Items.BLOOD_RUNE_565,
|
||||
Items.BODY_RUNE_559,
|
||||
Items.CHAOS_RUNE_562,
|
||||
Items.COSMIC_RUNE_564,
|
||||
Items.ASTRAL_RUNE_9075,
|
||||
Items.DEATH_RUNE_560,
|
||||
Items.LAVA_RUNE_4699,
|
||||
Items.MUD_RUNE_4698,
|
||||
Items.SMOKE_RUNE_4697,
|
||||
Items.STEAM_RUNE_4694,
|
||||
Items.SOUL_RUNE_566,
|
||||
Items.NATURE_RUNE_561
|
||||
//todo extend not allowed items list.
|
||||
//no Logs
|
||||
//add food
|
||||
//add ammo
|
||||
//summoning pouches
|
||||
|
||||
)
|
||||
|
||||
for (item in player.inventory.toArray()) {
|
||||
if (item != null) {
|
||||
if (item.id in forbiddenRunes) {
|
||||
//todo find source for this message
|
||||
return "The barbarians do not allow outside food or runes."
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
private fun familiarCheck(player: Player): String? {
|
||||
if(player.familiarManager.hasFamiliar()) {
|
||||
//todo find correct message
|
||||
return "The barbarians do not allow followers."
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private fun joinError(player: Player): Boolean {
|
||||
val errorMessage = forbiddenItemsCheck(player) ?: familiarCheck(player) ?: return false
|
||||
player.sendMessage(errorMessage).also { return true }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
class BarbSelectRole : InterfaceListener {
|
||||
//Team related
|
||||
//Leader leaving room and causing disband "Your leader has left the room and therefore cleared the team!"
|
||||
// //"Your recruiter exited the room."
|
||||
//Accpting invite text " Your application has been accepted"
|
||||
//The applicant declined your offer.
|
||||
//the other player hasn't confirmed their role yet.
|
||||
//the applicant has chosen a role[0]
|
||||
//You removed the person from the team.
|
||||
override fun defineInterfaceListeners() {
|
||||
onOpen(493) { player, _ -> // change this for roles
|
||||
val lines: Array<String> = player.getAttribute("ifaces:220:lines", arrayOf())
|
||||
for(i in 0 until Math.min(lines.size, 15)) {
|
||||
setInterfaceText(player, lines[i], 220, i+1)
|
||||
//setInterfaceText(player, "${i}", 220, i+1)
|
||||
}
|
||||
return@onOpen true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
|
||||
import core.api.*
|
||||
import core.game.component.Component
|
||||
import core.game.component.ComponentDefinition
|
||||
import core.game.component.ComponentPlugin
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import core.tools.*
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.Items
|
||||
|
||||
@Initializable
|
||||
class BarbRewardInterface : ComponentPlugin() {
|
||||
override fun open(player: Player?, component: Component?) {
|
||||
super.open(player, component)
|
||||
player ?: return
|
||||
updateRewardButtons(player)
|
||||
}
|
||||
var selectedShopButton = -1
|
||||
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
|
||||
//https://youtu.be/AG5Iv-ysAW0?t=11
|
||||
//todo find right values to highlight box blue when selecting.
|
||||
if (button == 213) {
|
||||
player!!.sendMessage("Accepted selection from button: $selectedShopButton")
|
||||
acceptReward(player,selectedShopButton)
|
||||
selectedShopButton = -1
|
||||
return true
|
||||
}
|
||||
selectedShopButton = button
|
||||
updateRewardButtons(player!!, button)
|
||||
return true
|
||||
}
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
ComponentDefinition.forId(Components.BARBASSAULT_REWARD_SHOP_491).plugin = this
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
//may have client side script instead of this.
|
||||
//dumps/scripts/2845.cs2 is for a newer revision with an overhauled interface.
|
||||
|
||||
fun updateRewardButtons(player: Player, selected: Int = -1) {
|
||||
interfaceUpdate(player,selected)
|
||||
|
||||
//points @ bottom
|
||||
val playerPoints = getBAPoints(player)
|
||||
setInterfaceText(player, playerPoints.atk.toString(), 491, 219)
|
||||
setInterfaceText(player, playerPoints.def.toString(), 491, 220)
|
||||
setInterfaceText(player, playerPoints.col.toString(), 491, 221)
|
||||
setInterfaceText(player, playerPoints.heal.toString(), 491, 222)
|
||||
}
|
||||
|
||||
fun acceptReward(player:Player, selected :Int){
|
||||
if (selected == -1 ) return
|
||||
val reward = barbRewardShop.find { it.buttonChildId == selected } ?: return
|
||||
if (!canBuyReward(player, reward, true)) return
|
||||
|
||||
when {
|
||||
reward.item != null -> { addItem(player, reward.item, 1) }
|
||||
// reward.gamble != null -> { }
|
||||
reward.levelUp != null -> { increaseBARoleLevel(player,reward.levelUp) }
|
||||
}
|
||||
removeCost(player, reward)
|
||||
updateRewardButtons(player)
|
||||
}
|
||||
|
||||
fun rollGambleReward(tier: GambleTier): Item {
|
||||
if (tier == GambleTier.HIGH) return Item(Items.DRAGON_CHAINBODY_13481,1)
|
||||
if (tier == GambleTier.MEDIUM) return Item(Items.RUNE_ARROWP_PLUS_5621,52)
|
||||
if (tier == GambleTier.LOW) return Item(Items.UNICORN_HORN_238,10)
|
||||
return Item(Items.FLAX_1779,1)
|
||||
|
||||
}
|
||||
|
||||
fun interfaceUpdate(player: Player, selected: Int) {
|
||||
val playerLevels = getBALevels(player)
|
||||
val hasQueenKill = hasQueenKill(player)
|
||||
barbRewardShop.forEach { reward ->
|
||||
val isSelected = reward.buttonChildId == selected
|
||||
val canBuy = canBuyReward(player, reward)
|
||||
val LAVENDER = "<col=D6CCFD>"
|
||||
var costText = reward.rewardCostText.text
|
||||
val nameColor = if (isSelected) BLUE else LAVENDER
|
||||
val resolvedText = if (reward.model != null) {
|
||||
val text = reward.rewardText.resolve(playerLevels).text
|
||||
val model = reward.model.resolve(playerLevels).modelId
|
||||
val perkText = reward.perkText!!.resolve(playerLevels).text
|
||||
|
||||
costText = reward.rewardCostText.resolve(playerLevels).text
|
||||
setInterfaceModel(player, model, 491, reward.model.childId, 2372)
|
||||
setInterfaceText(player, perkText, 491, reward.perkText.childId)
|
||||
text
|
||||
} else {
|
||||
reward.rewardText.text
|
||||
}
|
||||
setInterfaceText(player, nameColor + resolvedText, 491, reward.rewardText.childId)
|
||||
val costColor = if (canBuy) GREEN else RED
|
||||
setInterfaceText(player, costColor + costText, 491, reward.rewardCostText.childId)
|
||||
|
||||
if (reward.queenKillText != null) {
|
||||
val color = if (hasQueenKill) GREEN else RED
|
||||
setInterfaceText(player, color + reward.queenKillText.text, 491, reward.queenKillText.childId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun canBuyReward(player: Player, reward: RewardRow, buying: Boolean = false): Boolean {
|
||||
val points = getBAPoints(player)
|
||||
val hasQueenKill = hasQueenKill(player)
|
||||
val barbLevels = getBALevels(player)
|
||||
val resolvedCost = reward.cost.resolve(barbLevels)
|
||||
|
||||
fun requireQueenKill(base: Boolean): Boolean {
|
||||
return if (buying && reward.queenKillText != null) base && hasQueenKill else base
|
||||
}
|
||||
return when (resolvedCost) {
|
||||
is RewardCost.AllRoles -> requireQueenKill(
|
||||
points.atk >= resolvedCost.amountPerRole &&
|
||||
points.def >= resolvedCost.amountPerRole &&
|
||||
points.col >= resolvedCost.amountPerRole &&
|
||||
points.heal >= resolvedCost.amountPerRole
|
||||
)
|
||||
is RewardCost.AnyRole -> requireQueenKill( listOf( points.atk, points.def, points.col, points.heal).any { it >= resolvedCost.minimum })
|
||||
is RewardCost.Coins -> requireQueenKill(inInventory(player, 995, resolvedCost.amount))
|
||||
is RewardCost.Specific -> {
|
||||
if (isBarbRewardMaxed(reward,barbLevels)) return false
|
||||
requireQueenKill(
|
||||
points.atk >= resolvedCost.required.atk &&
|
||||
points.def >= resolvedCost.required.def &&
|
||||
points.col >= resolvedCost.required.col &&
|
||||
points.heal >= resolvedCost.required.heal
|
||||
)
|
||||
}
|
||||
is RewardCost.Dynamic -> TODO()
|
||||
}
|
||||
}
|
||||
fun isBarbRewardMaxed(reward: RewardRow, barbLevels: BarbAssaultLevels): Boolean {
|
||||
val text = reward.rewardText.text.lowercase()
|
||||
return when {
|
||||
"attacker" in text -> barbLevels.atk >= 5
|
||||
"defender" in text -> barbLevels.def >= 5
|
||||
"collector" in text -> barbLevels.col >= 5
|
||||
"healer" in text -> barbLevels.heal >= 5
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
fun removeCost(player: Player, reward: RewardRow) {
|
||||
val barbLevels = getBALevels(player)
|
||||
val resolvedCost = reward.cost.resolve(barbLevels)
|
||||
|
||||
when (resolvedCost) {
|
||||
is RewardCost.AllRoles -> {
|
||||
if (reward.queenKillText != null) { setAttribute(player,"barbass:queen-kill", 0)}
|
||||
removeBAPoints(player,BarbAssaultPoints(resolvedCost.amountPerRole, resolvedCost.amountPerRole, resolvedCost.amountPerRole, resolvedCost.amountPerRole))
|
||||
}
|
||||
is RewardCost.AnyRole -> { closeInterface(player);gambleDialogReward(player,resolvedCost.minimum) } //player.removeBarbPoints(BarbAssaultPoints(cost.minimum, cost.minimum, cost.minimum, cost.minimum))
|
||||
is RewardCost.Coins -> {
|
||||
if (reward.queenKillText != null) { setAttribute(player,"barbass:queen-kill", 0)}
|
||||
removeItem(player, Item(Items.COINS_995, resolvedCost.amount), Container.INVENTORY)
|
||||
}
|
||||
is RewardCost.Specific -> removeBAPoints(player,resolvedCost.required)
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
//https://youtu.be/KKUbBrJBab0?t=44
|
||||
fun gambleDialogReward(player: Player, cost: Int) {
|
||||
var costChoice: BarbRole? = null
|
||||
//todo Finish Gamble reward
|
||||
/*openDialogue(player, object : DialogueFile() {
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
// this.npc = NPC( NPCs.COMMANDER_CONNAD_5029)
|
||||
when (stage) {
|
||||
0 -> {sendDialogueOptions(player,"Which points would you like to spend?", "Attacker Honor Points","Defender Honor Points","Collector Honor Points","Healer Honor Points")
|
||||
addDialogueAction(player) { player , buttonId ->
|
||||
when(buttonId) {
|
||||
2 -> {costChoice = BarbRole.ATTACKER; stage++}
|
||||
3 -> {costChoice = BarbRole.DEFENDER; stage++}
|
||||
4 -> {costChoice = BarbRole.COLLECTOR; stage++}
|
||||
5 -> {costChoice = BarbRole.HEALER; stage++}
|
||||
}
|
||||
//return@addDialogueAction
|
||||
} }
|
||||
|
||||
2 -> sendNPCDialogue(player,NPCs.COMMANDER_CONNAD_5029,"Gamble you say! Let me take something from my big bag of prizes!").also { stage++}
|
||||
3 -> npc("What can i find!").also { stage++ }
|
||||
4 -> npc("Ah, found something!").also { stage++ }
|
||||
5 -> npc("You've got...").also { stage++ }
|
||||
6 -> sendItemDialogue(player,995,"ItemName!").also{end()}
|
||||
}
|
||||
}
|
||||
}).also {
|
||||
val barbPoints = player.getBarbPoints()
|
||||
|
||||
val costPointsSelected = when (costChoice) {
|
||||
BarbRole.ATTACKER -> BarbAssaultPoints(atk = cost)
|
||||
BarbRole.COLLECTOR -> BarbAssaultPoints(col = cost)
|
||||
BarbRole.DEFENDER -> BarbAssaultPoints(def = cost)
|
||||
BarbRole.HEALER -> BarbAssaultPoints(heal = cost)
|
||||
else -> {return}
|
||||
}
|
||||
|
||||
if (barbPoints.hasEnough(costPointsSelected)) {
|
||||
player.removeBarbPoints(costPointsSelected)
|
||||
} else {
|
||||
player.sendMessage("You don't have enough ${costChoice!!.name.lowercase()} points to gamble.")
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
data class InterfaceModel( val childId: Int, val modelId: Int, val dynamicModelId: ((playerLevel: BarbAssaultLevels) -> Int)? = null) {
|
||||
fun resolve(playerLevel: BarbAssaultLevels): InterfaceModel {
|
||||
val resolvedID = dynamicModelId?.invoke(playerLevel) ?: modelId
|
||||
return InterfaceModel(childId, resolvedID, null)
|
||||
}
|
||||
}
|
||||
data class InterfaceText( val childId: Int, val text: String, val dynamicText: ((playerLevel: BarbAssaultLevels) -> String)? = null) {
|
||||
fun resolve(playerLevel: BarbAssaultLevels): InterfaceText {
|
||||
val resolvedText = dynamicText?.invoke(playerLevel) ?: text
|
||||
return InterfaceText(childId, resolvedText, null)
|
||||
}
|
||||
}
|
||||
sealed class RewardCost {
|
||||
data class Specific(val required: BarbAssaultPoints) : RewardCost()
|
||||
data class AllRoles(val amountPerRole: Int) : RewardCost()
|
||||
data class AnyRole(val minimum: Int) : RewardCost()
|
||||
data class Coins(val amount: Int) : RewardCost()
|
||||
data class Dynamic(val generator: (BarbAssaultLevels) -> RewardCost) : RewardCost()
|
||||
|
||||
fun resolve(levels: BarbAssaultLevels): RewardCost = when (this) {
|
||||
is Dynamic -> generator(levels)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
data class RewardRow(
|
||||
val buttonChildId: Int,
|
||||
val model : InterfaceModel? = null,
|
||||
val rewardText: InterfaceText,
|
||||
val perkText: InterfaceText? = null,
|
||||
val rewardCostText: InterfaceText,
|
||||
val queenKillText: InterfaceText? = null,
|
||||
val cost: RewardCost,
|
||||
val item: Int? = null,
|
||||
val levelUp: BarbRole? = null,
|
||||
val gamble: GambleTier? = null
|
||||
)
|
||||
enum class GambleTier {LOW, MEDIUM, HIGH }
|
||||
//https://youtu.be/DZ9FqGFFVDw?t=4 -- 2009
|
||||
//https://youtu.be/md3naJdy2MM?t=67 -- 2008
|
||||
//https://youtu.be/u69JPBlDtVc?t=21 -- 2007
|
||||
/*
|
||||
Level | Honour Points | Collector | Healer | Attacker | Defender
|
||||
------|---------------|------------------------------------------|-------------|-----------|-------------------
|
||||
1 | Start level | Bag holds 2 eggs | Heals 10 hp | +1 Damage | Lure 4 spaces
|
||||
2 | 200 | Bag holds 4 eggs + Egg conversion | Heals 15 hp | +2 Damage | Lure 5 spaces
|
||||
3 | 300 | Bag holds 6 eggs + Conversion chance 40% | Heals 20 hp | +3 Damage | Lure 6 spaces
|
||||
4 | 400 | Bag holds 7 eggs + Conversion chance 60% | Heals 25 hp | +4 Damage | Lure 8 spaces
|
||||
5 | 500 | Bag holds 8 eggs + Conversion chance 80% | Heals 35 hp | +5 Damage | Lure 10 spaces
|
||||
*/
|
||||
|
||||
val barbRewardShop = listOf(
|
||||
RewardRow(81,
|
||||
model = InterfaceModel(80,20522){ level -> (20521 + level.atk).coerceIn(20522,20525) },
|
||||
rewardText = InterfaceText(82, "Attacker level up to 2"){ level -> if (level.atk >= 5) "Attacker level up complete" else "Attacker level up to ${level.atk + 1}"},
|
||||
rewardCostText = InterfaceText(83, "200 Attacker points"){ level -> if (level.atk >= 5) " - Mastered - " else "${level.atk + 1}00 Attacker points"},
|
||||
perkText = InterfaceText(85, "+2 bonus damage") { level -> if (level.atk >= 5) " - Mastered - " else "+${level.atk + 1} bonus damage" },
|
||||
cost = RewardCost.Dynamic { level -> RewardCost.Specific(BarbAssaultPoints((level.atk + 1) * 100, 0, 0, 0))},
|
||||
levelUp = BarbRole.ATTACKER
|
||||
),
|
||||
RewardRow(90,
|
||||
model = InterfaceModel(89,20526){ level -> (20525 + level.col).coerceIn(20526,20529) },
|
||||
rewardText = InterfaceText(91, "Collector level up to 2"){ level -> if (level.col >= 5) "Collector level up complete" else "Collector level up to ${level.col + 1}"},
|
||||
rewardCostText = InterfaceText(92, "200 Collector points"){ level -> if (level.col >= 5) " - Mastered - " else "${level.col + 1}00 Collector points"},
|
||||
perkText = InterfaceText(94, "Egg conversion") { level -> if (level.col <= 1) "Egg conversion" else if (level.col in 2..4) "Egg convert success ${(level.col - 2) * 20 + 40}%" else " - Mastered - " },
|
||||
cost = RewardCost.Dynamic { level -> RewardCost.Specific(BarbAssaultPoints(0, (level.col + 1) * 100, 0, 0))},
|
||||
levelUp = BarbRole.COLLECTOR
|
||||
),
|
||||
RewardRow(97,
|
||||
model = InterfaceModel(96,20531){ level -> (20530 + level.def).coerceIn(20531,20534) },
|
||||
rewardText = InterfaceText(98, "Defender level up to 2"){ level -> if (level.def >= 5) "Defender level up complete" else "Defender level up to ${level.def + 1}"},
|
||||
rewardCostText = InterfaceText(99, "200 Defender points"){ level -> if (level.def >= 5) " - Mastered - " else "${level.def + 1}00 Defender points"},
|
||||
perkText = InterfaceText(101, "Lure range 5") { level -> when (level.def) { 0, 1 -> "Lure range 5"; 2 -> "Lure range 6"; 3 -> "Lure range 8"; 4 -> "Lure range 10"; else -> " - Mastered - " } },
|
||||
cost = RewardCost.Dynamic { level -> RewardCost.Specific(BarbAssaultPoints(0, 0, (level.def + 1) * 100, 0))},
|
||||
levelUp = BarbRole.DEFENDER
|
||||
),
|
||||
RewardRow(104,
|
||||
model = InterfaceModel(103,20538){ level -> (20537 + level.heal).coerceIn(20538,20541) },
|
||||
rewardText = InterfaceText(105, "Healer level up to 2"){ level -> if (level.heal >= 5) "Healer level up complete" else "Healer level up to ${level.heal + 1}"},
|
||||
rewardCostText = InterfaceText(106, "200 Defender points"){ level -> if (level.heal >= 5) " - Mastered - " else "${level.heal + 1}00 Healer points"},
|
||||
perkText = InterfaceText(108, "Heal 15 points") { level -> when (level.heal) { 0, 1 -> "Heal 15 points"; 2 -> "Heal 20 points"; 3 -> "Heal 25 points"; 4 -> "Heal 35 points"; else -> " - Mastered - " } },
|
||||
cost = RewardCost.Dynamic { level -> RewardCost.Specific(BarbAssaultPoints(0, 0, 0, (level.heal + 1) * 100))},
|
||||
levelUp = BarbRole.HEALER
|
||||
),
|
||||
|
||||
RewardRow(111,
|
||||
rewardText = InterfaceText(112, "Penance Fighter hat"),
|
||||
rewardCostText = InterfaceText(113, "275 points in each role"),
|
||||
queenKillText = InterfaceText(229, "Kill Queen"),
|
||||
cost = RewardCost.AllRoles(275),
|
||||
item = Items.FIGHTER_HAT_10548
|
||||
),
|
||||
RewardRow(118,
|
||||
rewardText = InterfaceText(119, "Penance Ranger hat"),
|
||||
rewardCostText = InterfaceText(120, "275 points in each role"),
|
||||
queenKillText = InterfaceText(228, "Kill Queen"),
|
||||
cost = RewardCost.AllRoles(275),
|
||||
item = Items.RANGER_HAT_10550
|
||||
),
|
||||
RewardRow(125,
|
||||
rewardText = InterfaceText(126, "Penance Runner hat"),
|
||||
rewardCostText = InterfaceText(127, "275 points in each role"),
|
||||
queenKillText = InterfaceText(227, "Kill Queen"),
|
||||
cost = RewardCost.AllRoles(275),
|
||||
item = Items.RUNNER_HAT_10549
|
||||
),
|
||||
RewardRow(132,
|
||||
rewardText = InterfaceText(133, "Penance Healer hat"),
|
||||
rewardCostText = InterfaceText(134, "275 points in each role"),
|
||||
queenKillText = InterfaceText(226, "Kill Queen"),
|
||||
cost = RewardCost.AllRoles(275),
|
||||
item = Items.HEALER_HAT_10547
|
||||
),
|
||||
RewardRow(139,
|
||||
rewardText = InterfaceText(140, "Penance torso"),
|
||||
rewardCostText = InterfaceText(141, "375 points in each role"),
|
||||
queenKillText = InterfaceText(225, "Kill Queen"),
|
||||
cost = RewardCost.AllRoles(375),
|
||||
item = Items.FIGHTER_TORSO_10551
|
||||
),
|
||||
RewardRow(146,
|
||||
rewardText = InterfaceText(147, "Penance skirt"),
|
||||
rewardCostText = InterfaceText(148, "375 points in each role"),
|
||||
queenKillText = InterfaceText(224, "Kill Queen"),
|
||||
cost = RewardCost.AllRoles(375),
|
||||
item = Items.PENANCE_SKIRT_10555
|
||||
),
|
||||
RewardRow(153,
|
||||
rewardText = InterfaceText(154, "Penance boots"),
|
||||
rewardCostText = InterfaceText(155, "100 points in each role"),
|
||||
cost = RewardCost.AllRoles(100),
|
||||
item = Items.RUNNER_BOOTS_10552
|
||||
),
|
||||
RewardRow(160,
|
||||
rewardText = InterfaceText(161, "Penance gloves"),
|
||||
rewardCostText = InterfaceText(162, "150 points in each role"),
|
||||
cost = RewardCost.AllRoles(150),
|
||||
item = Items.PENANCE_GLOVES_10553
|
||||
),
|
||||
RewardRow(167,
|
||||
rewardText = InterfaceText(168, "Granite body"),
|
||||
rewardCostText = InterfaceText(169, "95,000 coins"),
|
||||
queenKillText = InterfaceText(230, "Kill Queen"),
|
||||
cost = RewardCost.Coins(95000),
|
||||
item = Items.GRANITE_BODY_10564
|
||||
),
|
||||
RewardRow(174,
|
||||
rewardText = InterfaceText(175, "Gamble points - low items"),
|
||||
rewardCostText = InterfaceText(176, "200 points (any role)"),
|
||||
cost = RewardCost.AnyRole(200),
|
||||
gamble = GambleTier.LOW
|
||||
),
|
||||
RewardRow(181,
|
||||
rewardText = InterfaceText(182, "Gamble points - medium items"),
|
||||
rewardCostText = InterfaceText(183, "400 points (any role)"),
|
||||
cost = RewardCost.AnyRole(400),
|
||||
gamble = GambleTier.MEDIUM
|
||||
),
|
||||
RewardRow(188,
|
||||
rewardText = InterfaceText(189, "Gamble points - high items"),
|
||||
rewardCostText = InterfaceText(190, "500 points (any role)"),
|
||||
queenKillText = InterfaceText(223, "Kill Queen"),
|
||||
cost = RewardCost.AnyRole(500),
|
||||
gamble = GambleTier.HIGH
|
||||
),
|
||||
)
|
||||
82
Server/src/main/content/minigame/barbassault/BATutorial.kt
Normal file
82
Server/src/main/content/minigame/barbassault/BATutorial.kt
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import core.api.MapArea
|
||||
import core.api.getRegionBorders
|
||||
import core.api.log
|
||||
import core.api.produceGroundItem
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.item.GroundItemManager
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.tools.Log
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
class BATutorial: MapArea {
|
||||
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> {
|
||||
//block standard teleports.
|
||||
BarbassTutNPCs.forEach {
|
||||
npc -> npc.init()
|
||||
npc.isWalks = false
|
||||
|
||||
}
|
||||
spawnItems()
|
||||
return arrayOf(getRegionBorders(7509))
|
||||
}
|
||||
override fun areaEnter(entity: Entity) {
|
||||
//todo move tut maparea to barbtut
|
||||
log(this::class.java, Log.FINE, "ENTERED BARBASS TUT")
|
||||
}
|
||||
|
||||
|
||||
override fun areaLeave(entity: Entity, logout: Boolean) {
|
||||
//val player = entity as? Player ?: return
|
||||
log(this::class.java, Log.FINE, "EXITED BARBASS TUT")
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
data class TutorialItemSpawn(val itemId: Int, val location: Location)
|
||||
val BarbassTutItems: List<TutorialItemSpawn> = listOf(
|
||||
TutorialItemSpawn(Items.LOGS_11760, Location.create(1885, 5487, 0)),
|
||||
TutorialItemSpawn(Items.LOGS_11760, Location.create(1886, 5486, 0)),
|
||||
TutorialItemSpawn(Items.HAMMER_2347, Location.create(1888, 5482, 0))
|
||||
)
|
||||
val BarbassTutNPCs: List<NPC> = listOf(
|
||||
NPC.create(NPCs.PENANCE_RANGER_5041, Location.create(1874, 5485, 0), Direction.SOUTH),
|
||||
NPC.create(NPCs.PENANCE_FIGHTER_5040, Location.create(1880, 5486, 0), Direction.SOUTH),
|
||||
NPC.create(NPCs.PENANCE_HEALER_5043, Location.create(1892, 5486, 0), Direction.SOUTH),
|
||||
NPC.create(NPCs.PENANCE_RUNNER_5042, Location.create(1898, 5485, 0), Direction.SOUTH),
|
||||
|
||||
NPC.create(NPCs.MAJOR_DEFEND_5037, Location.create(1891, 5466, 0), Direction.SOUTH),
|
||||
NPC.create(NPCs.MAJOR_HEAL_5038, Location.create(1882, 5466, 0), Direction.SOUTH),
|
||||
NPC.create(NPCs.MAJOR_ATTACK_5035, Location.create(1882, 5477, 0), Direction.SOUTH),
|
||||
NPC.create(NPCs.MAJOR_COLLECT_5036, Location.create(1891, 5477, 0), Direction.SOUTH),
|
||||
|
||||
NPC.create(NPCs.EGG_LAUNCHER_5026, Location.create(1896, 5474, 0), Direction.NORTH),
|
||||
NPC.create(NPCs.EGG_LAUNCHER_5026, Location.create(1877, 5474, 0), Direction.NORTH)
|
||||
)
|
||||
|
||||
fun spawnItems() {
|
||||
val groundItems = GroundItemManager.getItems()
|
||||
BarbassTutItems.forEach { (id, loc) ->
|
||||
if (groundItems.none { it.id == id && it.location == loc && !it.isRemoved })
|
||||
produceGroundItem(null, id, 1, loc).apply { forceVisible = true }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
https://www.youtube.com/watch?v=2A5hMOm0TMY
|
||||
[CAPTAIN_CAIN_5030]: option [ Tutorial]
|
||||
|
||||
|
||||
|
||||
*/
|
||||
279
Server/src/main/content/minigame/barbassault/BAUtils.kt
Normal file
279
Server/src/main/content/minigame/barbassault/BAUtils.kt
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.PenanceType
|
||||
import core.api.getTimer
|
||||
import core.api.hasTimerActive
|
||||
import core.api.registerTimer
|
||||
import core.api.removeTimer
|
||||
import core.api.spawnTimer
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.ImpactHandler
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.timer.PersistTimer
|
||||
import core.game.system.timer.RSTimer
|
||||
import core.game.system.timer.TimerFlag
|
||||
import core.tools.secondsToTicks
|
||||
|
||||
//thank you Ceikry
|
||||
|
||||
const val BA_SESSION_KEY = "ba-session"
|
||||
|
||||
/**
|
||||
* @param player [Player]
|
||||
*
|
||||
* @return The current [BarbassaultSession] if the player is in a session,
|
||||
* or `null` if they are not participating in Barbarian Assault.
|
||||
*/
|
||||
//getBASession(player)
|
||||
fun getBASession(entity: Entity): BarbassaultSession? = entity.getAttribute(BA_SESSION_KEY)
|
||||
|
||||
fun setBASession(entity: Entity, session: BarbassaultSession?) {
|
||||
if (session == null) {
|
||||
entity.removeAttribute(BA_SESSION_KEY)
|
||||
} else {
|
||||
entity.setAttribute(BA_SESSION_KEY, session)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the player's current Barbarian Assault points.
|
||||
* @param player [Player]
|
||||
* @return [BarbAssaultPoints] representing the player's stored points in each role:
|
||||
* - `atk`: Attacker points
|
||||
* - `col`: Collector points
|
||||
* - `def`: Defender points
|
||||
* - `heal`: Healer points
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* val points = getBAPoints(player)
|
||||
* println("Attacker points: ${points.atk}")
|
||||
* ```
|
||||
*///getBAPoints(player)
|
||||
fun getBAPoints(player: Player): BarbAssaultPoints = BarbAssaultPoints(
|
||||
player.getAttribute("barbass:atk-points", 0),
|
||||
player.getAttribute("barbass:col-points", 0),
|
||||
player.getAttribute("barbass:def-points", 0),
|
||||
player.getAttribute("barbass:heal-points", 0)
|
||||
)
|
||||
|
||||
/**
|
||||
* Sets the player's Barbarian Assault role points, clamping each to the allowed range (0 to 500)
|
||||
* and saving them to persistent storage.
|
||||
* @param player [Player]
|
||||
* @param points [BarbAssaultPoints] containing the new point values for each role:
|
||||
* - `atk`: Attacker points
|
||||
* - `col`: Collector points
|
||||
* - `def`: Defender points
|
||||
* - `heal`: Healer points
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* val newPoints = BarbAssaultPoints(atk = 120, col = 80, def = 200, heal = 0)
|
||||
* setBAPoints(player,newPoints)
|
||||
* ```
|
||||
*/
|
||||
fun setBAPoints(player: Player, points: BarbAssaultPoints) {
|
||||
val rolePoints = points.clamped()
|
||||
player.setAttribute("/save:barbass:atk-points", rolePoints.atk)
|
||||
player.setAttribute("/save:barbass:col-points", rolePoints.col)
|
||||
player.setAttribute("/save:barbass:def-points", rolePoints.def)
|
||||
player.setAttribute("/save:barbass:heal-points", rolePoints.heal)
|
||||
}
|
||||
/**
|
||||
* @param player [Player]
|
||||
* @param additional The points to be added to the player's current Barbarian Assault points.
|
||||
* Values will be automatically clamped between 0 and 500.
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* // Give the player 30 attacker points and 10 collector points
|
||||
* addBAPoints(player,BarbAssaultPoints(atk = 30, col = 10, def = 0, heal = 0))
|
||||
* ```
|
||||
*/
|
||||
fun addBAPoints(player: Player,additional: BarbAssaultPoints) {
|
||||
setBAPoints(player,getBAPoints(player) + additional)
|
||||
//todo Add warning message if points hit cap.
|
||||
//"You have maxed out your Healer Honor Points. You should spend them /n
|
||||
//commands."
|
||||
//https://youtu.be/rWRWL5PUj94?t=244
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player [Player]
|
||||
* @param toRemove The points to be subtracted from the player's current Barbarian Assault points.
|
||||
* Values will be clamped so that no role goes below 0.
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* // Remove 15 attacker points and 5 defender points
|
||||
* removeBAPoints(BarbAssaultPoints(atk = 15, col = 0, def = 5, heal = 0))
|
||||
* ```
|
||||
*/
|
||||
fun removeBAPoints(player: Player, toRemove: BarbAssaultPoints) {
|
||||
setBAPoints(player,getBAPoints(player) - toRemove)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player [Player]
|
||||
*
|
||||
* @return `true` if the player has one or more Queen kills,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
fun hasQueenKill(player: Player): Boolean = player.getAttribute("barbass:queen-kill", 0) > 0
|
||||
|
||||
/**
|
||||
* Retrieves the player's Barbarian Assault role levels
|
||||
* Defaults to level 1 for any role if not previously set.
|
||||
* @param player [Player]
|
||||
* @return [BarbAssaultLevels] containing the level for each role:
|
||||
* - `atk`: Attacker level
|
||||
* - `col`: Collector level
|
||||
* - `def`: Defender level
|
||||
* - `heal`: Healer level
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* val levels = getBALevels(player)
|
||||
* println("Attacker Level: ${levels.atk}")
|
||||
* ```
|
||||
*/
|
||||
fun getBALevels(player: Player): BarbAssaultLevels = BarbAssaultLevels(
|
||||
player.getAttribute("barbass:atk-level", 1),
|
||||
player.getAttribute("barbass:col-level", 1),
|
||||
player.getAttribute("barbass:def-level", 1),
|
||||
player.getAttribute("barbass:heal-level", 1)
|
||||
)
|
||||
/**
|
||||
* Sets the player's Barbarian Assault role levels
|
||||
* @param player [Player]
|
||||
* @param levels The [BarbAssaultLevels] object containing levels for each role:
|
||||
* - `atk`: Attacker level (1–5)
|
||||
* - `col`: Collector level (1–5)
|
||||
* - `def`: Defender level (1–5)
|
||||
* - `heal`: Healer level (1–5)
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* val newLevels = BarbAssaultLevels(atk = 2, col = 1, def = 3, heal = 1)
|
||||
* setBALevels(player,newLevels)
|
||||
* ```
|
||||
*/
|
||||
fun setBALevels(player: Player,levels: BarbAssaultLevels) {
|
||||
player.setAttribute("/save:barbass:atk-level", levels.atk)
|
||||
player.setAttribute("/save:barbass:col-level", levels.col)
|
||||
player.setAttribute("/save:barbass:def-level", levels.def)
|
||||
player.setAttribute("/save:barbass:heal-level", levels.heal)
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the level of the specified Barbarian Assault role by 1, up to a maximum of 5.
|
||||
*
|
||||
* Only one role can be increased at a time. The result is clamped to ensure the level does not exceed 5.
|
||||
* @param player [Player]
|
||||
* @param role The [BarbRole] to increase the level of. Must be one of:
|
||||
* - `BarbRole.ATTACKER`
|
||||
* - `BarbRole.COLLECTOR`
|
||||
* - `BarbRole.DEFENDER`
|
||||
* - `BarbRole.HEALER`
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* increaseBARoleLevel(player,BarbRole.ATTACKER)
|
||||
* ```
|
||||
*/
|
||||
fun increaseBARoleLevel(player: Player,role: BarbRole) {
|
||||
val current = getBALevels(player)
|
||||
val newLevels = when (role) {
|
||||
BarbRole.ATTACKER -> current.copy(atk = current.atk + 1)
|
||||
BarbRole.COLLECTOR -> current.copy(col = current.col + 1)
|
||||
BarbRole.DEFENDER -> current.copy(def = current.def + 1)
|
||||
BarbRole.HEALER -> current.copy(heal = current.heal + 1)
|
||||
}.clamped()
|
||||
setBALevels(player,newLevels)
|
||||
}
|
||||
/**
|
||||
* Retrieves the player's current Barbarian Assault wave.
|
||||
* @param player [Player]
|
||||
*
|
||||
* @return The current wave number. Defaults to `1` if no value is set.
|
||||
*/
|
||||
fun getBAWave(player: Player): Int? {
|
||||
return player.getAttribute("barbass:wave", 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player's current Barbarian Assault wave.
|
||||
* @param player [Player]
|
||||
*
|
||||
* @param wave The wave number to assign to the player.
|
||||
*/
|
||||
fun setBAWave(player: Player, wave: Int){
|
||||
player.setAttribute("/save:barbass:wave", wave)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Barbarian Assault role assigned to the player.
|
||||
*
|
||||
* @param player The player whose role should be retrieved.
|
||||
* @return The player's assigned [BarbRole], or `null` if the player is not in a Barbarian Assault session or team.
|
||||
*/
|
||||
fun getBARoleForPlayer(player: Player): BarbRole? {
|
||||
val team = getBASession(player)?.team ?: return null
|
||||
return team.getRoleForPlayer(player)
|
||||
}
|
||||
/**
|
||||
* Checks whether the player currently has the specified Barbarian Assault role.
|
||||
*
|
||||
* @param player The player to check.
|
||||
* @param role The role to compare against.
|
||||
* @return `true` if the player has the specified role, otherwise `false`.
|
||||
*/
|
||||
fun isBARole(player: Player, role: BarbRole) = getBARoleForPlayer(player) == role
|
||||
|
||||
|
||||
class BAPoison : PersistTimer (secondsToTicks(3), "BA-poison", flags = arrayOf(TimerFlag.ClearOnDeath)) {
|
||||
lateinit var damageSource: Entity
|
||||
var severity = 0
|
||||
|
||||
override fun run(entity: Entity): Boolean {
|
||||
entity.impactHandler.manualHit(damageSource,(severity + 4) / 5,ImpactHandler.HitsplatType.POISON)
|
||||
severity--
|
||||
return severity > 0
|
||||
}
|
||||
|
||||
override fun getTimer(vararg args: Any): RSTimer {
|
||||
val timer = BAPoison()
|
||||
timer.damageSource = args[0] as? Entity ?: return timer
|
||||
timer.severity = args[1] as? Int ?: return timer
|
||||
return timer
|
||||
}
|
||||
}
|
||||
|
||||
fun applyBAPoison (entity: Entity, source: Entity, severity: Int) {
|
||||
val existingTimer = getTimer<BAPoison>(entity)
|
||||
if (existingTimer != null) {
|
||||
if (existingTimer.severity > severity) {
|
||||
return
|
||||
} else {
|
||||
existingTimer.severity = severity
|
||||
existingTimer.damageSource = source
|
||||
}
|
||||
} else {
|
||||
registerTimer(entity, spawnTimer<BAPoison>(source, severity))
|
||||
}
|
||||
}
|
||||
|
||||
fun cureBAPoison(entity: Entity) {
|
||||
if (!hasTimerActive<BAPoison>(entity)) {
|
||||
return
|
||||
}
|
||||
removeTimer<BAPoison>(entity)
|
||||
}
|
||||
|
||||
fun isBAPoisoned(entity: Entity): Boolean {
|
||||
return hasTimerActive<BAPoison>(entity)
|
||||
}
|
||||
77
Server/src/main/content/minigame/barbassault/BarbAssault.kt
Normal file
77
Server/src/main/content/minigame/barbassault/BarbAssault.kt
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import content.minigame.barbassault.arena.ATTACKER_ICON
|
||||
import content.minigame.barbassault.arena.COLLECTOR_ICON
|
||||
import content.minigame.barbassault.arena.DEFENDER_ICON
|
||||
import content.minigame.barbassault.arena.HEALER_ICON
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
|
||||
|
||||
val LureItems = intArrayOf(Items.WORMS_10515, Items.CRACKERS_10513, Items.TOFU_10514)
|
||||
enum class BarbRole(val machineId: Int) {
|
||||
ATTACKER(Scenery.ATTACKER_ITEM_MACHINE_20241),
|
||||
DEFENDER(Scenery.DEFENDER_ITEM_MACHINE_20242),
|
||||
HEALER(Scenery.HEALER_ITEM_MACHINE_20243),
|
||||
COLLECTOR(Scenery.COLLECTOR_CONVERTER_21250)
|
||||
}
|
||||
data class BarbAssaultPoints( val atk: Int = 0, val col: Int = 0, val def: Int = 0, val heal: Int = 0) {
|
||||
val total: Int get() = atk + col + def + heal
|
||||
fun hasEnough(cost: BarbAssaultPoints): Boolean = atk >= cost.atk && col >= cost.col && def >= cost.def && heal >= cost.heal
|
||||
operator fun minus(other: BarbAssaultPoints): BarbAssaultPoints = BarbAssaultPoints(atk - other.atk,col - other.col,def - other.def,heal - other.heal).clamped()
|
||||
operator fun plus(other: BarbAssaultPoints): BarbAssaultPoints = BarbAssaultPoints(atk + other.atk,col + other.col,def + other.def,heal + other.heal).clamped()
|
||||
fun clamped(): BarbAssaultPoints = BarbAssaultPoints(atk.coerceIn(0, 500), col.coerceIn(0, 500), def.coerceIn(0, 500), heal.coerceIn(0, 500) )
|
||||
fun getPoints(role: BarbRole): Int = when (role) { BarbRole.ATTACKER -> atk; BarbRole.COLLECTOR -> col; BarbRole.DEFENDER -> def; BarbRole.HEALER -> heal; }
|
||||
}
|
||||
|
||||
data class BarbAssaultLevels(val atk: Int, val col: Int, val def: Int, val heal: Int) {
|
||||
fun clamped(): BarbAssaultLevels = BarbAssaultLevels( atk.coerceIn(1, 5), col.coerceIn(1, 5), def.coerceIn(1, 5), heal.coerceIn(1, 5) )
|
||||
fun getLevel(role: BarbRole): Int = when (role) { BarbRole.ATTACKER -> atk; BarbRole.COLLECTOR -> col; BarbRole.DEFENDER -> def; BarbRole.HEALER -> heal; }
|
||||
|
||||
}
|
||||
|
||||
val ALL_BARBASS_ITEMS = arrayOf(
|
||||
Item(ATTACKER_ICON),
|
||||
Item(Items.ATTACKER_HORN_10516), Item(Items.ATTACKER_HORN_10517), Item(Items.ATTACKER_HORN_10518), Item(Items.ATTACKER_HORN_10519), Item(Items.ATTACKER_HORN_10520),
|
||||
|
||||
Item(DEFENDER_ICON),
|
||||
Item(Items.WORMS_10515),Item(Items.CRACKERS_10513), Item(Items.TOFU_10514),
|
||||
Item(Items.LOGS_11760),Item(Items.HAMMER_2347),
|
||||
Item(Items.DEFENDER_HORN_10538),
|
||||
|
||||
Item(HEALER_ICON),
|
||||
Item(Items.HEALING_VIAL_10546),Item(Items.HEALING_VIAL1_10545),Item(Items.HEALING_VIAL2_10544),Item(Items.HEALING_VIAL3_10543),Item(Items.HEALING_VIAL4_10542),
|
||||
Item(Items.HEALER_HORN_10526),Item(Items.HEALER_HORN_10527),Item(Items.HEALER_HORN_10528),Item(Items.HEALER_HORN_10529),Item(Items.HEALER_HORN_10530),
|
||||
Item(Items.POISONED_WORMS_10540),Item(Items.POISONED_TOFU_10539),Item(Items.POISONED_MEAT_10541),
|
||||
|
||||
Item(COLLECTOR_ICON),
|
||||
Item(Items.COLLECTOR_HORN_10560),
|
||||
Item(Items.COLLECTION_BAG_10521),Item(Items.COLLECTION_BAG_10522),Item(Items.COLLECTION_BAG_10523),Item(Items.COLLECTION_BAG_10524),Item(Items.COLLECTION_BAG_10525),
|
||||
Item(Items.BLUE_EGG_10533),Item(Items.RED_EGG_10532),Item(Items.GREEN_EGG_10531),
|
||||
)
|
||||
|
||||
object BAGraphics {
|
||||
|
||||
const val GREEN_LARGE_EXPLOSION_867 = 867
|
||||
const val RED_LARGE_EXPLOSION_868 = 868
|
||||
const val BLUE_LARGE_EXPLOSION_869 = 869
|
||||
|
||||
const val GREEN_EGG_BREAK_873 = 873
|
||||
const val RED_EGG_BREAK_874 = 874
|
||||
const val BLUE_EGG_BREAK_875 = 875
|
||||
|
||||
const val PENANCE_HEALER_BAD_BREATH_863 = 863
|
||||
const val PENANCE_HEALER_GOOD_BREATH_864 = 864
|
||||
|
||||
const val GREEN_LARGE_EXPLOSION2_876 = 876
|
||||
const val RED_EGG_EXPLOSION_975 = 975
|
||||
const val GREEN_EGG_PROJECTILE_977 = 977
|
||||
const val RED_EGG_PROJECTILE_978 = 978
|
||||
const val Blue_EGG_PROJECTILE_978 = 979
|
||||
const val YELLOW_EGG_PROJECTILE_980 = 980
|
||||
const val STUNN_BIRDYS_981 = 981
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import core.api.MapArea
|
||||
import core.api.getRegionBorders
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.game.world.map.zone.ZoneType
|
||||
|
||||
class BarbAssaultArea : MapArea {
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> {
|
||||
return arrayOf(getRegionBorders(7509))
|
||||
}
|
||||
|
||||
override fun areaEnter(entity: Entity) {
|
||||
zone.zoneType = ZoneType.BARBARIAN_ASSAULT.id
|
||||
super.areaEnter(entity)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ class CaptainCainDialogue(player: Player? = null) : DialoguePlugin(player) {
|
|||
override fun open(vararg args: Any?): Boolean {
|
||||
npcl(FacialExpression.FRIENDLY, "Hello, there, adventurer. Say, you wouldn't happen to be interested in purchasing a Fighter Torso would you?")
|
||||
stage = 0
|
||||
player.setAttribute("barbass:tut", true)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -72,4 +73,26 @@ class CaptainCainDialogue(player: Player? = null) : DialoguePlugin(player) {
|
|||
return intArrayOf(NPCs.CAPTAIN_CAIN_5030)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lets keep the meme of WHEN you were able to buy a torso and ryans promise <3
|
||||
*
|
||||
* dialogoption to -> I heard you could sell me a fighter's torso.
|
||||
* FacialExpression.HALF_GUILTY, NPC: Sell you a torso? Oh, I couldn’t possibly… ,
|
||||
* I’m only here to teach adventurers the basics.
|
||||
*
|
||||
* FacialExpression.ASKING Player: But people say you did… back when Ryan promised Barbarian Assault.
|
||||
*
|
||||
* NPC: People say a lot of things.
|
||||
* I’ve never officially offered anything like that.
|
||||
* Official operations only started on {RELEASE_DATE} — anything before that is… unofficial.
|
||||
*
|
||||
* Player:“The promise was made on $start. Some adventurers even counted — it’s been $days days since then.”
|
||||
*
|
||||
* FacialExpression.SUSPICIOUS NPC: I see… the adventurers remember everything......
|
||||
*
|
||||
* FacialExpression.ANNOYED NPC: Fine, keep your rumours. But don’t expect me to give a torso for them.
|
||||
* Now, back to training!!
|
||||
*
|
||||
*/
|
||||
110
Server/src/main/content/minigame/barbassault/CommanderConnad.kt
Normal file
110
Server/src/main/content/minigame/barbassault/CommanderConnad.kt
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import core.api.addItem
|
||||
import core.api.freeSlots
|
||||
import core.api.openInterface
|
||||
import core.game.dialogue.DialoguePlugin
|
||||
import core.game.dialogue.FacialExpression
|
||||
import core.game.dialogue.Topic
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import core.tools.END_DIALOGUE
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
@Initializable
|
||||
class CommanderConnad(player: Player? = null) : DialoguePlugin(player) {
|
||||
override fun newInstance(player: Player?): DialoguePlugin {
|
||||
return CommanderConnad(player)
|
||||
}
|
||||
override fun open(vararg args: Any?): Boolean {
|
||||
val tutComplete = player.getAttribute("barbass:tut", false)
|
||||
stage = if (tutComplete) 5 else 0
|
||||
handle(0,0)
|
||||
return true
|
||||
}
|
||||
override fun handle(componentID: Int, buttonID: Int): Boolean {
|
||||
val barbasspoints = getBAPoints(player)
|
||||
val displayName = player.name.replaceFirstChar { it.uppercaseChar() }
|
||||
|
||||
when (stage) {
|
||||
0 -> playerl(FacialExpression.FRIENDLY, "Hello?").also { stage++ }
|
||||
1 -> npcl(FacialExpression.FRIENDLY, "Sorry soldier, you don't have permission to speak with me yet. Go and talk to the Captain.").also { stage = END_DIALOGUE }
|
||||
|
||||
5 -> playerl(FacialExpression.FRIENDLY, " I believe you might be able to reward me for my progress in this arena?.").also { stage++ }
|
||||
6 -> npcl(FacialExpression.FRIENDLY,"Well that depends upon your skill levels for each role.").also { stage++ }
|
||||
7 -> npcl(FacialExpression.ASKING,"What's your name soldier?").also { stage++ }
|
||||
8 -> playerl(FacialExpression.FRIENDLY, "${displayName}, Sir!").also { stage++ }
|
||||
9 -> npcl(FacialExpression.FRIENDLY," Okay. What exactly do you want to know, ${displayName}?").also { stage++ }
|
||||
10 -> showTopics(
|
||||
Topic(FacialExpression.ASKING,"Can I trade some of my points?",15),
|
||||
Topic(FacialExpression.ASKING,"What points do I have so far, sir?",25),
|
||||
Topic(FacialExpression.ASKING,"Could I have a 'Queen Help' book?", queenBookStage(player)),
|
||||
Topic(FacialExpression.ASKING,"Could I have my current wave reset to one?", areWaveOne(player)),
|
||||
Topic(FacialExpression.FRIENDLY,"That is all, sir.",100)
|
||||
)
|
||||
|
||||
//Open RewardInterface
|
||||
15-> npcl(FacialExpression.FRIENDLY,"Of course.").also { stage++ }
|
||||
16 -> {
|
||||
end()
|
||||
openInterface(player,Components.BARBASSAULT_REWARD_SHOP_491)
|
||||
}
|
||||
//Point Check
|
||||
25 -> npcl(FacialExpression.FRIENDLY,"Let me check...").also { stage = getBarbPointStage(barbasspoints.total) }
|
||||
26 -> npcl(FacialExpression.FRIENDLY,"You have absolutely no points, whatsoever. Best you get back into that arena!").also { stage = 10 }
|
||||
27 -> npcl(FacialExpression.FRIENDLY,"You have: ${barbasspoints.atk} Attacker Honour Points, ${barbasspoints.def} Defender Honour Points, ${barbasspoints.col} Collector Honour Points and ${barbasspoints.heal} Healer Honour Points.").also { stage = 10 }
|
||||
|
||||
//Get Queen book.
|
||||
50 -> npcl(FacialExpression.FRIENDLY,"By all means.").also {
|
||||
addItem(player, Items.QUEEN_HELP_BOOK_10562, 1)
|
||||
stage = 10
|
||||
}
|
||||
//Already have Queen book
|
||||
51 -> npcl(FacialExpression.ANNOYED,"You already have one!").also { stage++ }
|
||||
52 -> playerl(FacialExpression.WORRIED,"Oh yes, sorry.").also { stage = 10}
|
||||
|
||||
//not enough Inventory Space
|
||||
53 -> playerl(FacialExpression.WORRIED,"Oh, no. Wait, I don't have enough space to carry one.").also { stage++ }
|
||||
54 -> npcl(FacialExpression.FRIENDLY,"Well, you can come back and get one at any time from me.").also { stage = 10 }
|
||||
//Already have QueenBook
|
||||
75 -> npcl(FacialExpression.ANNOYED," You do realise that you're already on wave one?").also { stage++ }
|
||||
76 -> playerl(FacialExpression.WORRIED,"Ah. Yes. Sorry about that.").also { stage = END_DIALOGUE}
|
||||
//todo find Correct Dialog for wave reset
|
||||
77 -> npcl(FacialExpression.ASKING,"I can change it down to wave 1, Are you sure you want that?").also { stage++ }
|
||||
78 -> showTopics(
|
||||
Topic(FacialExpression.FRIENDLY, "Yes, reset my wave to one.",79),
|
||||
Topic(FacialExpression.FRIENDLY, "No, I want to stay on wave ${getBAWave(player)}.",10)
|
||||
)
|
||||
79 -> {
|
||||
npcl(FacialExpression.ASKING,"Very well.").also { stage = END_DIALOGUE }
|
||||
player.setAttribute("/save:barbass:wave", 1)
|
||||
}
|
||||
//END
|
||||
100 -> npcl(FacialExpression.FRIENDLY,"Very well, on your way.").also { stage = END_DIALOGUE }
|
||||
}
|
||||
return true
|
||||
}
|
||||
private fun getBarbPointStage(total: Int): Int {
|
||||
if (total == 0 ) return 26
|
||||
return 27
|
||||
}
|
||||
private fun queenBookStage(player: Player?): Int {
|
||||
if (freeSlots(player!!) == 0) return 53
|
||||
if (player.hasItem(Item(Items.QUEEN_HELP_BOOK_10562))) return 51
|
||||
return 50
|
||||
}
|
||||
private fun areWaveOne(player: Player): Int {
|
||||
if (getBAWave(player) != 1) return 77
|
||||
return 75
|
||||
}
|
||||
override fun getIds(): IntArray {
|
||||
return intArrayOf(NPCs.COMMANDER_CONNAD_5029)
|
||||
}
|
||||
}
|
||||
|
||||
//[COMMANDER_CONNAD_5029] Dialog: https://www.youtube.com/watch?v=wb1InggbaZc
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import core.api.openDialogue
|
||||
import core.api.sendDialogue
|
||||
import core.game.dialogue.DialogueFile
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
class PenanceStatueDialogues : InteractionListener {
|
||||
val statueToDialogId = mapOf(
|
||||
Scenery.PENANCE_FIGHTER_STATUE_20164 to 1,
|
||||
Scenery.PENANCE_HEALER_STATUE_20165 to 5,
|
||||
Scenery.PENANCE_RANGER_STATUE_20167 to 10,
|
||||
Scenery.PENANCE_RUNNER_STATUE_20166 to 15,
|
||||
Scenery.PENANCE_QUEEN_SPAWN_STATUE_20168 to 20
|
||||
)
|
||||
val STATUES: IntArray = statueToDialogId.keys.toIntArray()
|
||||
|
||||
override fun defineListeners() {
|
||||
on(STATUES, IntType.SCENERY, "Inspect") { player, node ->
|
||||
openDialogue(player, object : DialogueFile() {
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when (stage) {
|
||||
0 -> sendDialogue(player, "There seems to be a plaque on the statue. It says:").also { stage = statueToDialogId[node.id] ?: -1 }
|
||||
//FIGHTER STATUE
|
||||
1 -> sendDialogue(player, "'The Penance Fighter - With the single goal to attack all that may threaten its Queen, this monster uses it's giant claws to shred its prey, and can only be stopped with brute force. Sharing the telekinetic trait of the other Penance monsters, the Penance Fighter can anticipate and adapt to").also { stage++ }
|
||||
2 -> sendDialogue(player, "defend itself. Bearing this in mind, it's important when fighting this monster to change attack style periodically to ensure damage is dealt. Most combatants will be glad to notice this creature (like the other Penance) has only one eye, and hence its depth perception is not all that it could be! Otherwise, those claws would soon destroy the most").also { stage++ }
|
||||
3 -> sendDialogue(player, "experienced of warriors!'").also { stage = 26 }
|
||||
//HEALER STATUE
|
||||
5 -> sendDialogue(player,"'The Penance Healer - This monster could have arguably been called a 'Penance Poisoner', for it has a dual role - both healing other Penance and poisoning any creature it sees as a threat. It performs these roles with equal importance and switches from one to the other as soon as it has the").also { stage++ }
|
||||
6 -> sendDialogue(player,"chance of finding a target. The best way to stop a Penance Healer is fighting it at its own game. The Penance Healer is partial to food, which it uses to create its own chemicals for curing and poisoning. As a result it has to be very careful what it eats, and has a mechanism by which it will be immune to certain types of poisonous foods at").also { stage++ }
|
||||
7 -> sendDialogue(player,"different times. With this information in mind, it is in fact possible to poison the Penance Healer by using the right type of food at the right time.'").also { stage = 26 }
|
||||
//RANGER STATUE
|
||||
10 -> sendDialogue(player,"'The Penance Ranger - These creatures store a highly corrosive liquid in the abdomen at the base of their bodies. It is believed that this was initially used for breaking up food matter to be passed on to the Queen for digestion. With the increase of easily digestible food sources (e.g. 'daring'").also { stage++ }
|
||||
11 -> sendDialogue(player,"adventurers), this functionality has been removed. It now seems to be used for offensive means in the form of projectiles. The only way to defeat this monster is to confront it with brute force, as it has no convenient weakness. That being said, the Penance Ranger can anticipate and adapt to attacks using the telekenisis common between").also { stage++ }
|
||||
12 -> sendDialogue(player,"all Penance, and hence, when taking on this monster, it is important to change attack style periodically to perform damage.'").also { stage = 26 }
|
||||
//RUNNER STATUE
|
||||
15 -> sendDialogue(player,"'The Penance Runner - These creatures are attracted to the scent of their Queen - charging to her aid in the hope of creating a barrier to protect her from threat. Their slender legs aid in motion, and their bulky bodies are effective shields and a strong barrier when linked together. And so,").also { stage++ }
|
||||
16 -> sendDialogue(player,"they are willing to waste their own lives in the simple interest of protecting their Queen. Using this interesting trait against them, Penance Runners are lured in the arena by the exit cave, which is doused with this scent. This is used to test combatants in how many Penance Runners manage to get past and how many are stopped").also { stage++ }
|
||||
17 -> sendDialogue(player,"with the use of the traps. Penance Runners are an energetic group, and therefore take any opportunity to eat and restore energy. With this in mind, laying down food within smelling distance of the Runners will lure them along. However, they are not stupid, and look for different food to ensure they are not so easily tricked... Hence,").also { stage++ }
|
||||
18 -> sendDialogue(player,"giving them the wrong food will send them running back to their caves. It's an interesting evolutionary trait, which is transmitted telepathically between Penance Runners... One which we carefully intercept.'").also { stage = 26 }
|
||||
//QUEENSPAWN STATUE
|
||||
20 -> sendDialogue(player,"'The Penance Spawn - You're only likely to see these creatures in close proximity to their creator - the dreaded Penance Queen. All Penance begin their lives in this form, mutating into the seperate classes of Penance depending on the lack or abundance of other classes in the local environment.").also { stage++ }
|
||||
21 -> sendDialogue(player,"Through telepathic communication, the Queen is able to determine the number of each class of Penance (Fighter, Ranger, Healer or Runner) and communicate to her spawn the form they should take on to fill any gaps in numbers. If the spawn receives no communication from a Queen, it turns into a Queen itself, because").also { stage++ }
|
||||
22 -> sendDialogue(player,"of the evident neccessity of such a role. These spawn will attack on sight, but a few hits by any means should stop these slimy creatures.'").also { stage = 26 }
|
||||
//END OF DIALOGUE
|
||||
26 -> end()
|
||||
}
|
||||
}
|
||||
})
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import content.global.handlers.iface.BookInterface
|
||||
import content.global.handlers.iface.BookLine
|
||||
import content.global.handlers.iface.Page
|
||||
import content.global.handlers.iface.PageSet
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.player.Player
|
||||
import org.rs09.consts.Items
|
||||
|
||||
class QueenHelpBook : InteractionListener {
|
||||
companion object {
|
||||
private val TITLE = "Queen Help"
|
||||
private val CONTENTS = arrayOf(
|
||||
PageSet(
|
||||
Page( //1
|
||||
BookLine("<col=ff0000>1) <col=0b5394>Collector: <col=000000>Pick up ", 55),
|
||||
BookLine("yellow egg. pass to", 56),
|
||||
BookLine("healer.", 57),
|
||||
|
||||
BookLine("Take omega egg from", 58),
|
||||
BookLine("Defender. Load in to ", 59),
|
||||
BookLine("turret.", 60),
|
||||
|
||||
BookLine("<col=ff0000>2) <col=0b5394>Healer:<col=000000> Take yellow", 62),
|
||||
BookLine("egg from Collector.", 63),
|
||||
BookLine("Poison egg in pool. Pass", 64),
|
||||
BookLine("to Attacker.", 65),
|
||||
|
||||
),
|
||||
Page( //2
|
||||
BookLine("", 66),
|
||||
BookLine("<col=ff0000>3)<col=0b5394> Attacker:<col=000000> Take", 67),
|
||||
BookLine("poisoned, yellow egg from", 68),
|
||||
BookLine("healer Add spikes from", 69),
|
||||
BookLine("mushroom. Pass to", 70),
|
||||
BookLine("Defender.", 70),
|
||||
BookLine("", 72),
|
||||
BookLine("<col=ff0000>4)<col=0b5394> Defender:<col=000000> Take ", 73),
|
||||
BookLine("poisoned, spiked, yellow", 74),
|
||||
BookLine("from Attacker. Dunk", 75),
|
||||
BookLine("in lava. Pass to Collector.", 76),
|
||||
BookLine("", 77),
|
||||
BookLine("", 78)
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
private fun display(player: Player, pageNum: Int, buttonID: Int) : Boolean {
|
||||
BookInterface.pageSetup(player, BookInterface.FANCY_BOOK_3_49, TITLE, CONTENTS)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun defineListeners() {
|
||||
on(Items.QUEEN_HELP_BOOK_10562, IntType.ITEM, "read") { player, _ ->
|
||||
BookInterface.openBook(player, BookInterface.FANCY_BOOK_3_49, ::display)
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//[QUEEN_HELP_BOOK_10562] // https://www.youtube.com/watch?v=r1x8xbz3JAA
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.BarbassaultState
|
||||
import core.api.log
|
||||
import core.game.activity.ActivityManager
|
||||
import core.game.activity.ActivityPlugin
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
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
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.ZoneRestriction
|
||||
import core.plugin.Initializable
|
||||
import core.tools.Log
|
||||
|
||||
private val sessions = mutableListOf<BarbassaultSession>()
|
||||
private var activity: BAActivity? = null
|
||||
@Initializable
|
||||
open class BAActivity : ActivityPlugin("barbassault",false, true, true,ZoneRestriction.CANNON,ZoneRestriction.FIRES,ZoneRestriction.FOLLOWERS,ZoneRestriction.RANDOM_EVENTS) {
|
||||
init {
|
||||
activity = this
|
||||
}
|
||||
|
||||
override fun configure() {
|
||||
GameWorld.Pulser.submit(object : Pulse(10) {
|
||||
override fun pulse(): Boolean {
|
||||
sessions.removeIf { session ->
|
||||
val shouldRemove = session.state == BarbassaultState.END
|
||||
if (shouldRemove) {
|
||||
log(this.javaClass, Log.FINE, "Removing session: $session")
|
||||
}
|
||||
shouldRemove
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun start(player: Player?, login: Boolean, vararg args: Any?): Boolean {
|
||||
super.start(player, login, *args)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun enter(e: Entity?): Boolean { return super.enter(e) }
|
||||
|
||||
override fun continueAttack(e: Entity?, target: Node?, style: CombatStyle?, message: Boolean): Boolean {
|
||||
//BERR must of been good, idk why I put this in here
|
||||
return super.continueAttack(e, target, style, message)
|
||||
}
|
||||
override fun death(e: Entity, killer: Entity?): Boolean {
|
||||
log(this.javaClass, Log.FINE,"${e.name} has died in Barbass")
|
||||
val session = getBASession(e) ?:return false
|
||||
if (e is Player) {
|
||||
session.state = BarbassaultState.DEATH
|
||||
e.getProperties().setTeleportLocation(null)
|
||||
return true
|
||||
}
|
||||
if (e is NPC) {
|
||||
// dropPenanceEggCluster(e)
|
||||
session.sessionNpcs.remove(e)
|
||||
session.pennanceClearedMessage(e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun newInstance(p: Player?): ActivityPlugin {
|
||||
ActivityManager.register(this)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getSpawnLocation(): Location {
|
||||
return Location.create(2593, 5264, 0)
|
||||
}
|
||||
|
||||
//override when !2265 passes (void recovery)
|
||||
fun recover(player: Player){
|
||||
//removeBarbass items
|
||||
//super.recover(player)
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun createSession(leader: Player): BarbassaultSession {
|
||||
val activity = ActivityManager.getActivity("barbassault") as BAActivity
|
||||
val session = BarbassaultSession(activity)
|
||||
sessions += session
|
||||
|
||||
setBASession(leader,session)
|
||||
|
||||
return session
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
package content.minigame.barbassault.arena
|
||||
|
||||
import content.minigame.barbassault.*
|
||||
import content.minigame.barbassault.BAGraphics.BLUE_EGG_BREAK_875
|
||||
import content.minigame.barbassault.BAGraphics.GREEN_EGG_BREAK_873
|
||||
import content.minigame.barbassault.BAGraphics.RED_EGG_BREAK_874
|
||||
import content.minigame.barbassault.arena.BarbAssEvent.EggCollected
|
||||
import content.minigame.barbassault.arena.BarbAssEvent.HitpointsHealed
|
||||
import content.minigame.barbassault.arena.BarbAssEvent.WrongPoisonUsed
|
||||
import content.minigame.barbassault.arena.BarbassaultSession.AttackerStyle
|
||||
import content.minigame.barbassault.arena.npcs.PENANCE_HEALER_IDS
|
||||
import content.minigame.barbassault.arena.scenery.EggCannon
|
||||
import content.minigame.barbassault.arena.scenery.EggCannon.Companion.loadEggHopper
|
||||
import content.minigame.barbassault.arena.scenery.EggCannon.Companion.loadHopperEggs
|
||||
import content.minigame.barbassault.arena.scenery.EggCannon.Companion.showEggHopperCount
|
||||
import core.api.*
|
||||
import core.game.global.action.ClimbActionHandler
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.interaction.QueueStrength
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import core.game.node.entity.combat.ImpactHandler
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_ACCURATE
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_AGGRESSIVE
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_CONTROLLED
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_DEFENSIVE
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.info.LogType
|
||||
import core.game.node.entity.player.info.PlayerMonitor
|
||||
import core.game.node.item.GroundItem
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld.Pulser
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import getCollectorBag
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
import resetCollectorBag
|
||||
|
||||
|
||||
//1889 5407 - Barb assualt QUEEN area -- 7508
|
||||
//1891 5465 - barb assualt AREA under
|
||||
|
||||
val PENANCE_QUEEN_SPAWN_LOC = Location.create(1884, 5405, 0)
|
||||
|
||||
//sendMessage(player,"The barbarians forbid the use of prayer in their arena as they don't ~ value such methods!")
|
||||
|
||||
//should be multicombat
|
||||
val ATTACKER_ICON = 10556
|
||||
val DEFENDER_ICON = 10558
|
||||
val COLLECTOR_ICON = 10557
|
||||
val HEALER_ICON = 10559
|
||||
class BarbassaultArenaListener : InteractionListener {
|
||||
|
||||
val ROLE_ICON = intArrayOf( ATTACKER_ICON, DEFENDER_ICON, COLLECTOR_ICON, HEALER_ICON )
|
||||
val Fix_trap_IDs = intArrayOf( Scenery.RUNNER_TRAP1_20230, Scenery.BROKEN_TRAP0_20231 )
|
||||
val All_HEALING_VIALS = intArrayOf(Items.HEALING_VIAL_10546,Items.HEALING_VIAL1_10545,Items.HEALING_VIAL2_10544,Items.HEALING_VIAL3_10543,Items.HEALING_VIAL4_10542 )
|
||||
val ALL_COLLECTION_BAGS = intArrayOf(Items.COLLECTION_BAG_10521,Items.COLLECTION_BAG_10522,Items.COLLECTION_BAG_10523,Items.COLLECTION_BAG_10524,Items.COLLECTION_BAG_10525)
|
||||
object BA_ARENA { val MAIN = 7509; val QUEEN = 7508; val all = listOf(MAIN, QUEEN) }
|
||||
|
||||
override fun defineListeners() {
|
||||
//Wrong food message "That's the wrong type of poisoned food to use! Penalty!"
|
||||
on(Scenery.EGG_LAUNCHER_20133, IntType.SCENERY, "Shoot") { player, node ->
|
||||
EggCannon.openTurretIface(player)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.EGG_HOPPER_20264, IntType.SCENERY, "Load","Look-in") { player, node ->
|
||||
val loc = player.location
|
||||
val optionClicked = player.getAttribute<String>("interact:option")?.lowercase() ?: return@on false
|
||||
when(optionClicked){
|
||||
"load" -> loadEggHopper(player)
|
||||
"look-in" -> showEggHopperCount(player)
|
||||
}
|
||||
player.faceLocation(location(loc.x,loc.y+1,0))
|
||||
return@on true
|
||||
}
|
||||
onUseWith(IntType.SCENERY, EggCannon.ALL_EGGS,Scenery.EGG_HOPPER_20264){ player, used, with ->
|
||||
val loc = player.location
|
||||
player.faceLocation(location(loc.x,loc.y+1,0))
|
||||
loadHopperEggs(player,used.id )
|
||||
return@onUseWith true
|
||||
}
|
||||
//wrapperID for hopper
|
||||
on(20267, IntType.SCENERY, "Load","Look-in") { player, node ->
|
||||
sendMessage(player,"hopper")
|
||||
return@on true
|
||||
}
|
||||
setDest(IntType.SCENERY, intArrayOf(Scenery.EGG_HOPPER_20264), "use","Load","Look-in") { player, node ->
|
||||
//work around for running off to org location instead of copy location.
|
||||
//Player Name's Parlor chairs Should fix this!
|
||||
return@setDest sessionDestination(player as Player,node,Direction.SOUTH)
|
||||
}
|
||||
|
||||
on(Fix_trap_IDs, IntType.SCENERY, "Fix") { player, node ->
|
||||
if (hasTools(player)) { return@on true }
|
||||
playerChangeScenery(player,5416,node,Scenery.RUNNER_TRAP2_20135,5,"You fixed the Penance Runner trap.")
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.PENANCE_CAVE_20237, IntType.SCENERY, "block") { player, node ->
|
||||
//restrict to role
|
||||
if (hasTools(player)) { return@on true }
|
||||
playerChangeScenery(player,5417,node,Scenery.PENANCE_CAVE_20238,4)
|
||||
getBASession(player)?.setCaveBlocked(node,true)
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.PENANCE_CAVE_20238, IntType.SCENERY, "demolish") { player, node ->
|
||||
playerChangeScenery(player,5418,node,Scenery.PENANCE_CAVE_20239,5)
|
||||
getBASession(player)?.setCaveBlocked(node,false)
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.PENANCE_CAVE_20239, IntType.SCENERY, "fix") { player, node ->
|
||||
if (hasTools(player)) { return@on true }
|
||||
playerChangeScenery(player,5417,node,Scenery.PENANCE_CAVE_20238,4)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.LADDER_20194, IntType.SCENERY, "Climb-up") { player, _ ->
|
||||
sendDialogueOptions(player, "Are you sure you want to leave?", "Yes", "No")
|
||||
addDialogueAction(player) { _, buttonId ->
|
||||
if (buttonId == 2) {
|
||||
val animationDuration = animationDuration(ClimbActionHandler.CLIMB_UP)
|
||||
player.lock(animationDuration)
|
||||
player.animate(ClimbActionHandler.CLIMB_UP)
|
||||
Pulser.submit(object : Pulse(animationDuration) { override fun pulse(): Boolean {getBASession(player)?.forfeit(); return true }})
|
||||
}
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
//you healed $heal.count hitpoints.
|
||||
//You've been healed $amount hitpoints and your poison cured.
|
||||
on(Scenery.HEALER_SPRING_20150, IntType.SCENERY, "Drink-from") { player, _ ->
|
||||
if (isBARole(player, BarbRole.HEALER)) {
|
||||
player.animate(Animation(5407))
|
||||
player.lock(5)
|
||||
//todo use quescript here instead
|
||||
Pulser.submit(object : Pulse(3, player) {
|
||||
override fun pulse(): Boolean {
|
||||
val restoreAmount = getHealerHealAmount(player)
|
||||
val curedPoison = isBAPoisoned(player)
|
||||
heal(player, restoreAmount)
|
||||
cureBAPoison(player)
|
||||
player.settings.updateRunEnergy((-restoreAmount).toDouble())
|
||||
player.unlock()
|
||||
val message = if (curedPoison) {
|
||||
"You've been healed $restoreAmount hitpoints and your poison cured."
|
||||
} else {
|
||||
"You've been healed $restoreAmount hitpoints."
|
||||
}
|
||||
sendMessage(player, message)
|
||||
getBASession(player)?.updateBarbHealerIfaceHPOfPlayer(player)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
onUseWith(IntType.NPC, intArrayOf(Items.POISONED_TOFU_10539,Items.POISONED_MEAT_10541,Items.POISONED_WORMS_10540), *PENANCE_HEALER_IDS) { player, used, target ->
|
||||
val session = getBASession(player) ?: return@onUseWith true
|
||||
val currentCall = (session.roleCalls[BarbRole.HEALER] as? BarbassaultSession.HealerCall)?.required?.itemId
|
||||
removeItem(player,used)
|
||||
if (used.id == currentCall) {
|
||||
applyBAPoison(target as Entity,player,20)
|
||||
target.impactHandler.manualHit ( player,4, ImpactHandler.HitsplatType.POISON )
|
||||
return@onUseWith true
|
||||
}
|
||||
sendMessage(player,"that's the wrong type of poisoned food to use! Penalty!")
|
||||
session.eventBus.emit(WrongPoisonUsed(player))
|
||||
return@onUseWith true
|
||||
}
|
||||
onUseWithPlayer(*All_HEALING_VIALS) { player, _, target ->
|
||||
target as Player
|
||||
//todo find Healing sound
|
||||
val targetPoisoned = isBAPoisoned(target)
|
||||
if (target.skills.lifepoints >= target.skills.maximumLifepoints && !targetPoisoned) {
|
||||
sendMessage(player, "The player's hitpoints are full.")
|
||||
return@onUseWithPlayer true
|
||||
}
|
||||
val current = All_HEALING_VIALS.firstOrNull { player.inventory.containsAtLeastOneItem(it) }?: return@onUseWithPlayer true
|
||||
val index = All_HEALING_VIALS.indexOf(current)
|
||||
|
||||
if (index > 0) {
|
||||
queueScript(player, 0) {
|
||||
val session = getBASession(player)
|
||||
val next = All_HEALING_VIALS[index - 1]
|
||||
player.inventory.remove(Item(current))
|
||||
player.inventory.add(Item(next))
|
||||
|
||||
val restoreAmount =
|
||||
minOf(getHealerHealAmount(player), target.skills.maximumLifepoints - target.skills.lifepoints)
|
||||
val curedPoison = isBAPoisoned(target)
|
||||
sendHealerVialMessages(player, target, restoreAmount, curedPoison)
|
||||
player.animate(Animation(537))
|
||||
heal(target, restoreAmount)
|
||||
cureBAPoison(target)
|
||||
target.settings.updateRunEnergy((-restoreAmount).toDouble())
|
||||
session?.updateBarbHealerIfaceHPOfPlayer(target)
|
||||
session?.eventBus?.emit(HitpointsHealed(player, restoreAmount))
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return@onUseWithPlayer true
|
||||
}
|
||||
on(Scenery.HEALER_SPRING_20150, IntType.SCENERY, "Take-from") { player, _ -> fillHealerVial(player); return@on true }
|
||||
onUseAnyWith( IntType.SCENERY,Scenery.HEALER_SPRING_20150,*All_HEALING_VIALS) { player, used, with -> fillHealerVial(player); return@onUseAnyWith true}
|
||||
|
||||
onUnequip(ROLE_ICON) { player, _ ->
|
||||
if (getBASession(player)?.state == BarbassaultState.IN_ARENA){
|
||||
sendMessage(player, "You can't remove that!") // is there a proper message for this?
|
||||
return@onUnequip false
|
||||
}
|
||||
return@onUnequip true
|
||||
}
|
||||
|
||||
onEquip(ROLE_ICON) { player, _ ->
|
||||
if (getBASession(player)?.state == BarbassaultState.IN_ARENA) {
|
||||
sendMessage(player, "You can't remove that!")
|
||||
return@onEquip false
|
||||
}
|
||||
return@onEquip true
|
||||
}
|
||||
on(LureItems, IntType.GROUNDITEM, "Take") { player, node ->
|
||||
val session = getBASession(player) ?: return@on true
|
||||
if (session.team.getRoleForPlayer(player) != BarbRole.DEFENDER) {
|
||||
sendMessage(player,"not a Defender")
|
||||
}
|
||||
//if (getCollectorBag(player).addToBag())
|
||||
session.pickUpGroundItem(player, node as BAGroundSpawn)
|
||||
return@on true
|
||||
}
|
||||
on(LureItems, IntType.ITEM, "Drop") { player, node ->
|
||||
val session = getBASession(player) ?: return@on true
|
||||
val currentCall = (session.roleCalls[BarbRole.DEFENDER] as? BarbassaultSession.DefenderCall)?.required
|
||||
//sendMessage(player,currentCall?.itemId.toString())
|
||||
val flag = node.id == currentCall?.itemId
|
||||
handleDropItem(player,node,flag)
|
||||
|
||||
return@on true
|
||||
}
|
||||
on(EggCannon.ALL_EGGS, IntType.GROUNDITEM, "Take") { player, node ->
|
||||
if (node !is GroundItem) return@on true
|
||||
val session = getBASession(player) ?: return@on true
|
||||
//todo find authentic message
|
||||
if (session.team.getRoleForPlayer(player) != BarbRole.COLLECTOR) { sendMessage(player, "You need to be a collector to do that");return@on false }
|
||||
|
||||
val currentCall = (session.roleCalls[BarbRole.COLLECTOR]as? BarbassaultSession.CollectorCall)?.required
|
||||
if (node.id != currentCall?.itemId) { handleWrongEgg(player,node); return@on false }
|
||||
|
||||
val eggInBag = getCollectorBag(player).addToBag(node)
|
||||
|
||||
if (eggInBag) {
|
||||
session.destroyGroundItem(node as BAGroundSpawn)
|
||||
session.eventBus.emit(EggCollected(player,1))
|
||||
return@on true
|
||||
}
|
||||
|
||||
val didPickUp = session.pickUpGroundItem(player, node as BAGroundSpawn)
|
||||
if (!didPickUp) { handleWrongEgg(player,node,false); return@on true }
|
||||
|
||||
session.eventBus.emit(EggCollected(player,1))
|
||||
return@on true
|
||||
}
|
||||
on(ALL_COLLECTION_BAGS, IntType.ITEM, "Look-In") { player, node ->
|
||||
getCollectorBag(player).lookInBag()
|
||||
return@on true
|
||||
}
|
||||
on(ALL_COLLECTION_BAGS, IntType.ITEM, "Empty") { player, node ->
|
||||
resetCollectorBag(player)
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
fun handleWrongEgg(player: Player, groundItem: GroundItem,point: Boolean = true){
|
||||
val session = getBASession(player) ?: return
|
||||
if (point) { session.eventBus.emit(EggCollected(player,-1)) }
|
||||
impact(player, 5)
|
||||
val gfx = when (groundItem.id) {
|
||||
Items.GREEN_EGG_10531 -> GREEN_EGG_BREAK_873
|
||||
Items.RED_EGG_10532 -> RED_EGG_BREAK_874
|
||||
Items.BLUE_EGG_10533 -> BLUE_EGG_BREAK_875
|
||||
else -> 874
|
||||
}
|
||||
Graphics.send(Graphics(gfx), player.location)
|
||||
sendMessage(player,"The egg exploded")
|
||||
session.destroyGroundItem(groundItem as BAGroundSpawn)
|
||||
}
|
||||
|
||||
fun handleDropItem(player: Player, node: Node, flag: Boolean? = false): Boolean {
|
||||
val item = node as? Item ?: return false
|
||||
queueScript(player, strength = QueueStrength.SOFT) {
|
||||
val current = player.inventory.get(item.slot)
|
||||
val session = getBASession(player) ?: return@queueScript stopExecuting(player)
|
||||
if (current == null || current !== item) { return@queueScript stopExecuting(player) }
|
||||
if (player.inventory.replace(null, item.slot) !== item) { PlayerMonitor.log(player, LogType.DUPE_ALERT, "Potential exploit attempt when player ${player.name} tried to drop ${item.amount}x ${item.id}. BA session Items"); return@queueScript stopExecuting(player) }
|
||||
val droppedItem = item.dropItem
|
||||
val groundItem = BAGroundSpawn(session,60,droppedItem,player.location,flag)
|
||||
groundItem.init()
|
||||
// sendMessage(player, session.BAgroundItems.toString())
|
||||
setAttribute(player, "droppedItem:${droppedItem.id}", getWorldTicks() + 2)
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun playerChangeScenery(player: Player,anim: Int ,node: Node, newSceneryId: Int, pulseDelay: Int = 3, message: String = "") {
|
||||
|
||||
player.animate(Animation(anim))
|
||||
player.lock(pulseDelay)
|
||||
//if trap send message "You fixed the Penance Runner trap."
|
||||
Pulser.submit(object : Pulse(pulseDelay, player) {
|
||||
override fun pulse(): Boolean {
|
||||
player.unlock()
|
||||
val scenryNode = node as core.game.node.scenery.Scenery
|
||||
replaceScenery( scenryNode,newSceneryId ,-1 ,node.location )
|
||||
sendMessage(player, message)
|
||||
if ( node.id == Scenery.PENANCE_CAVE_20238) {return true}
|
||||
removeItem(player,Items.LOGS_11760)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
fun sessionDestination(player: Player, node: Node, direction: Direction? = null): Location {
|
||||
//work around for running off to org location instead of copy location.
|
||||
//Player Name's Parlor chairs Should fix this!
|
||||
val session = getBASession(player) ?: return node.location
|
||||
val borders = getRegionBorders(session.region.regionId)
|
||||
val base = session.base
|
||||
return Location.create(
|
||||
base.x + node.location.x - borders.southWestX + (direction?.stepX ?: 0),
|
||||
base.y + node.location.y - borders.southWestY + (direction?.stepY ?: 0),
|
||||
base.z
|
||||
)
|
||||
}
|
||||
private fun hasTools(player: Player): Boolean{
|
||||
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id != DEFENDER_ICON) {return true}
|
||||
val requiredItems = listOf(Items.HAMMER_2347, Items.LOGS_11760)
|
||||
for (item in requiredItems) {
|
||||
if (!inInventory(player, item)) {
|
||||
sendMessage(player, "You need a ${getItemName(item)}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
fun getHealerHealAmount(player: Player): Int {
|
||||
val healerHealAmounts = intArrayOf(5, 15, 20, 25, 35)
|
||||
val level = getBALevels(player).heal
|
||||
return healerHealAmounts.getOrElse(level) { healerHealAmounts.last() }
|
||||
}
|
||||
|
||||
private fun sendHealerVialMessages(player: Player, target: Player, restoreAmount: Int, curedPoison: Boolean) {
|
||||
when {
|
||||
restoreAmount > 0 && curedPoison -> {
|
||||
sendMessage(target, "You've been healed $restoreAmount hitpoints and your poison cured.")
|
||||
sendMessage(player, "You healed $restoreAmount hitpoints and cured their poison.")
|
||||
}
|
||||
restoreAmount > 0 -> {
|
||||
sendMessage(target, "You've been healed $restoreAmount hitpoints.")
|
||||
sendMessage(player, "You healed $restoreAmount hitpoints.")
|
||||
}
|
||||
curedPoison -> {
|
||||
sendMessage(target, "Your poison has been cured.")
|
||||
sendMessage(player, "You cured their poison.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fillHealerVial(player: Player){
|
||||
queueScript(player,1, QueueStrength.STRONG) {
|
||||
if (player.inventory.containsAtLeastOneItem(All_HEALING_VIALS)) {
|
||||
val current = All_HEALING_VIALS.firstOrNull { player.inventory.containsAtLeastOneItem(it) } ?: return@queueScript stopExecuting(player)
|
||||
player.animate(Animation(5400))
|
||||
player.inventory.remove(Item(current))
|
||||
player.inventory.add(Item(Items.HEALING_VIAL4_10542))
|
||||
sendMessage(player, "You filled the vial.")
|
||||
}
|
||||
return@queueScript stopExecuting(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object BACombatValidation {
|
||||
fun resolveAttackerStyle( attacker: Player, state: BattleState ): AttackerStyle? {
|
||||
return when (state.style) {
|
||||
CombatStyle.MELEE -> when (attacker.properties.attackStyle.style) {
|
||||
STYLE_CONTROLLED -> AttackerStyle.STYLE_1
|
||||
STYLE_ACCURATE -> AttackerStyle.STYLE_2
|
||||
STYLE_AGGRESSIVE -> AttackerStyle.STYLE_3
|
||||
STYLE_DEFENSIVE -> AttackerStyle.STYLE_4
|
||||
else -> null
|
||||
}
|
||||
CombatStyle.RANGE -> when (state.ammunition.itemId) {
|
||||
Items.BRONZE_ARROW_882 -> AttackerStyle.STYLE_1
|
||||
Items.IRON_ARROW_884 -> AttackerStyle.STYLE_2
|
||||
Items.STEEL_ARROW_886 -> AttackerStyle.STYLE_3
|
||||
Items.MITHRIL_ARROW_888 -> AttackerStyle.STYLE_4
|
||||
else -> null
|
||||
}
|
||||
CombatStyle.MAGIC -> when (state.spell.spellId) {
|
||||
1, 10, 24, 45 -> AttackerStyle.STYLE_1 // Air
|
||||
4, 14, 27, 48 -> AttackerStyle.STYLE_2 // Water
|
||||
6, 17, 66, 52 -> AttackerStyle.STYLE_3 // Earth
|
||||
8, 20, 38, 55 -> AttackerStyle.STYLE_4 // Fire
|
||||
else -> null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun applyAttackValidation( self: NPC, attacker: Player, state: BattleState ): Int {
|
||||
val session = getBASession(attacker) ?: return state.estimatedHit
|
||||
val currentCall = session.roleCalls[BarbRole.COLLECTOR]?.toCall
|
||||
//todo read my players level instead of scanning the inventory every time for a horn.
|
||||
|
||||
val hornBonus = (BAHornSystem.HornHelper.getAttackerHorn(attacker)?.ordinal ?: -1) + 2
|
||||
val damage = state.estimatedHit + hornBonus
|
||||
val usedStyle = resolveAttackerStyle(attacker, state)
|
||||
|
||||
if (usedStyle == null) { sendMessage(attacker, "That attack is not allowed."); return 0 }
|
||||
|
||||
if (usedStyle != currentCall) {
|
||||
sendMessage(attacker, "Wrong attack style!")
|
||||
impact(attacker, 1)
|
||||
session.eventBus.emit(BarbAssEvent.WrongAttack(self, attacker))
|
||||
return 0
|
||||
}
|
||||
return damage
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
the game ended early becasue one of your team mates died.
|
||||
|
||||
484 = horn of glory!
|
||||
Barricaded entrances will only slow down, not stop, Penance from entering the battlefield.
|
||||
Players are allowed to use normal potions; however, potions mixed using Barbarian training may not be brought into the arena.
|
||||
Every team member will lose points when a runner makes it to the end,
|
||||
The only combat experience you will get here is the base experience for a magic spell using the runes given to you by the attacker machine.
|
||||
//You can stand in front of the lure cave to block runners from passing by. (Note that a runner can get through if you are walked on by another player)
|
||||
|
||||
[DEFENDER_HORN_10538]
|
||||
[COLLECTOR_HORN_10560]
|
||||
Collector Level 1 = [COLLECTION_BAG_10521] - Bag holds 2 eggs
|
||||
Collector Level 2 = [COLLECTION_BAG_10522] - Bag holds 4 eggs + Egg conversion
|
||||
Collector Level 3 = [COLLECTION_BAG_10523] - Bag holds 6 eggs + 40% conversion
|
||||
Collector Level 4 = [COLLECTION_BAG_10524] - Bag holds 7 eggs + 60% conversion
|
||||
Collector Level 5 = [COLLECTION_BAG_10525] - Bag holds 8 eggs + 80% conversion
|
||||
|
||||
Attacker Level 1 = [ATTACKER_HORN_10516] - +1 Damage
|
||||
Attacker Level 2 = [ATTACKER_HORN_10517] - +2 Damage
|
||||
Attacker Level 3 = [ATTACKER_HORN_10518] - +3 Damage
|
||||
Attacker Level 4 = [ATTACKER_HORN_10519] - +4 Damage
|
||||
Attacker Level 5 = [ATTACKER_HORN_10520] - +5 Damage
|
||||
|
||||
Healer Level 1 = [HEALER_HORN_10526] - Heals 10 hp
|
||||
Healer Level 2 = [HEALER_HORN_10527] - Heals 15 hp
|
||||
Healer Level 3 = [HEALER_HORN_10528] - Heals 20 hp
|
||||
Healer Level 4 = [HEALER_HORN_10529] - Heals 25 hp
|
||||
Healer Level 5 = [HEALER_HORN_10530] - Heals 35 hp
|
||||
|
||||
HEALING_VIAL_10546
|
||||
HEALING_VIAL1_10545
|
||||
HEALING_VIAL2_10544
|
||||
HEALING_VIAL3_10543
|
||||
HEALING_VIAL4_10542
|
||||
|
||||
| Level | Honour Points | Defender |
|
||||
|-------|----------------|----------------|
|
||||
| 1 | Start level | Lure 4 spaces |
|
||||
| 2 | 200 | Lure 5 spaces |
|
||||
| 3 | 300 | Lure 6 spaces |
|
||||
| 4 | 400 | Lure 8 spaces |
|
||||
| 5 | 500 | Lure 10 spaces |
|
||||
|-------|----------------|----------------|
|
||||
RUNNER_TRAP2_20135
|
||||
RUNNER_TRAP1_20230
|
||||
BROKEN_TRAP0_20231
|
||||
|
||||
Only normal Magics can damage.
|
||||
we use these runes in barb assault.
|
||||
[ATTACKER_ITEM_MACHINE_20241]
|
||||
Options[ Take-runes, Take-arrows(300 of each)
|
||||
CATALYTIC_RUNE_12851, ELEMENTAL_RUNE_12850
|
||||
|
||||
https://youtu.be/_EipqTK3Qak?t=68
|
||||
Blocking off entrance, does NOT STOP runners entering, only slows
|
||||
|
||||
|
||||
Announce in game room when All of a monster has been killed
|
||||
" All of the $PENANCE Name have been killed!
|
||||
|
||||
* */
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
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()
|
||||
data class WrongAttack(val self: NPC, val attacker: Player) : BarbAssEvent()
|
||||
data class RunnerEscaped(val player: Player) : BarbAssEvent()
|
||||
|
||||
}
|
||||
class BarbAssEventBus {
|
||||
private val listeners = mutableMapOf<Class<out BarbAssEvent>, MutableList<(BarbAssEvent) -> Unit>>()
|
||||
private val pendingEvents = mutableListOf<BarbAssEvent>()
|
||||
|
||||
fun <T : BarbAssEvent> register(eventType: Class<T>, 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package content.minigame.barbassault.arena
|
||||
import core.game.node.item.GroundItem
|
||||
import core.game.node.item.GroundItemManager
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.GameWorld
|
||||
|
||||
import core.game.world.map.Location
|
||||
class BAGroundSpawn(private var session: BarbassaultSession, private var respawnRate: Int, item: Item?, location: Location?, var flag: Boolean? = null, private var lureRange: Int = 4) : GroundItem(item, location) {
|
||||
|
||||
private var active = true
|
||||
private var autoSpawn = true
|
||||
|
||||
override fun toString(): String = "SessionGroundSpawn [name=$name, respawnRate=$respawnRate, loc=$location, flag = $flag]"
|
||||
|
||||
fun init(): GroundItem {
|
||||
val thisGroundItem = GroundItemManager.create(this)
|
||||
session.BAgroundItems.add(thisGroundItem as BAGroundSpawn)
|
||||
return thisGroundItem
|
||||
}
|
||||
|
||||
override fun isActive(): Boolean = active
|
||||
override fun setActive(value: Boolean) { active = value }
|
||||
|
||||
override fun isPrivate(): Boolean = false
|
||||
|
||||
override fun isAutoSpawn(): Boolean = autoSpawn
|
||||
fun setAutoSpawn(value: Boolean) { autoSpawn = value }
|
||||
fun setRespawnRate(rate: Int) { respawnRate = rate }
|
||||
|
||||
fun getLureRange():Int = lureRange
|
||||
fun addLureRange(addRange: Int) { lureRange += addRange }
|
||||
|
||||
override fun respawn() {
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package content.minigame.barbassault.arena
|
||||
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.api.inInventory
|
||||
import core.api.sendChat
|
||||
import core.api.sendMessage
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.player.Player
|
||||
import org.rs09.consts.Items
|
||||
|
||||
class BAHornSystem : InteractionListener {
|
||||
|
||||
private val ATTACKER_HORNS = intArrayOf( Items.ATTACKER_HORN_10516, Items.ATTACKER_HORN_10517, Items.ATTACKER_HORN_10518, Items.ATTACKER_HORN_10519, Items.ATTACKER_HORN_10520 )
|
||||
private val HEALER_HORNS = intArrayOf( Items.HEALER_HORN_10526, Items.HEALER_HORN_10527, Items.HEALER_HORN_10528, Items.HEALER_HORN_10529, Items.HEALER_HORN_10530 )
|
||||
|
||||
override fun defineListeners() {
|
||||
|
||||
on(Items.DEFENDER_HORN_10538, IntType.ITEM, "Tell-tofu", "Tell-worms", "Tell-meat","Medic", "Drop") { player, _ ->
|
||||
val optionClicked = player.getAttribute<String>("interact:option")?.lowercase() ?: return@on false
|
||||
val session = getBASession(player) ?: return@on true
|
||||
var poisFoodToTell = BarbassaultSession.PoisonFood.TOFU
|
||||
when (optionClicked) {
|
||||
"tell-tofu" -> poisFoodToTell = BarbassaultSession.PoisonFood.TOFU
|
||||
"tell-worms" ->poisFoodToTell = BarbassaultSession.PoisonFood.WORMS
|
||||
"tell-meat" -> poisFoodToTell = BarbassaultSession.PoisonFood.MEAT
|
||||
"drop" -> { sendMessage(player, "I need that!");return@on true }
|
||||
"medic" -> { sendChat(player, "Medic!"); session.alertHealers(player);return@on true }
|
||||
else -> return@on true
|
||||
}
|
||||
sendChat(player, poisFoodToTell.hornShout)
|
||||
session.onHornCall(player, poisFoodToTell)
|
||||
true
|
||||
}
|
||||
|
||||
on(Items.COLLECTOR_HORN_10560, IntType.ITEM, "Tell-style1", "Tell-style2", "Tell-style3", "Tell-style4","Medic" , "Drop") { player, _ ->
|
||||
val optionClicked = player.getAttribute<String>("interact:option")?.lowercase() ?: return@on false
|
||||
val session = getBASession(player) ?: return@on true
|
||||
var styleToTell = BarbassaultSession.AttackerStyle.STYLE_1
|
||||
when (optionClicked){
|
||||
"tell-style1" -> styleToTell = BarbassaultSession.AttackerStyle.STYLE_1
|
||||
"tell-style2" -> styleToTell = BarbassaultSession.AttackerStyle.STYLE_2
|
||||
"tell-style3" -> styleToTell = BarbassaultSession.AttackerStyle.STYLE_3
|
||||
"tell-style4" -> styleToTell = BarbassaultSession.AttackerStyle.STYLE_4
|
||||
"drop" -> { sendMessage(player, "I need that!");return@on true }
|
||||
"medic" -> { sendChat(player, "Medic!"); session.alertHealers(player);return@on true }
|
||||
}
|
||||
sendChat(player, styleToTell.hornShout)
|
||||
session.onHornCall(player, styleToTell)
|
||||
true
|
||||
}
|
||||
on(ATTACKER_HORNS, IntType.ITEM, "Tell-red", "Tell-green", "Tell-blue", "Medic", "Drop") { player, _ ->
|
||||
val optionClicked = player.getAttribute<String>("interact:option")?.lowercase() ?: return@on false
|
||||
val session = getBASession(player) ?: return@on true
|
||||
var eggToTell = BarbassaultSession.EggColor.RED
|
||||
when (optionClicked) {
|
||||
"tell-red" -> eggToTell = BarbassaultSession.EggColor.RED
|
||||
"tell-green" -> eggToTell = BarbassaultSession.EggColor.GREEN
|
||||
"tell-blue" -> eggToTell = BarbassaultSession.EggColor.BLUE
|
||||
"drop" -> { sendMessage(player, "I need that!");return@on true }
|
||||
"medic" -> { sendChat(player, "Medic!"); session.alertHealers(player);return@on true }
|
||||
}
|
||||
sendChat(player, eggToTell.hornShout)
|
||||
session.onHornCall(player, eggToTell)
|
||||
true
|
||||
}
|
||||
|
||||
on(HEALER_HORNS, IntType.ITEM, "Tell-tofu", "Tell-crackers", "Tell-worms","Medic", "Drop") { player, _ ->
|
||||
val optionClicked = player.getAttribute<String>("interact:option")?.lowercase() ?: return@on false
|
||||
val session = getBASession(player) ?: return@on true
|
||||
var lureFoodToTell = BarbassaultSession.LureFood.TOFU
|
||||
when (optionClicked){
|
||||
"tell-tofu" -> lureFoodToTell = BarbassaultSession.LureFood.TOFU
|
||||
"tell-crackers" -> lureFoodToTell = BarbassaultSession.LureFood.CRACKERS
|
||||
"tell-worms" -> lureFoodToTell = BarbassaultSession.LureFood.WORMS
|
||||
"drop" -> { sendMessage(player, "I need that!");return@on true }
|
||||
"medic" -> { sendChat(player, "Medic!"); session.alertHealers(player);return@on true }
|
||||
}
|
||||
sendChat(player, lureFoodToTell.hornShout)
|
||||
session.onHornCall(player, lureFoodToTell)
|
||||
true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object HornHelper {
|
||||
//I should set a value in my players session instead of scanning the inventory every time for a horn.
|
||||
//multiple horn IDs suggest retail would use a gearSet check to apply a damage modifier.
|
||||
fun getAttackerHorn(player: Player): AttackerHorn? = AttackerHorn.values().firstOrNull { inInventory(player, it.itemId) }
|
||||
}
|
||||
|
||||
enum class AttackerHorn(val itemId: Int) {
|
||||
LEVEL_ONE(Items.ATTACKER_HORN_10516),
|
||||
LEVEL_TWO(Items.ATTACKER_HORN_10517),
|
||||
LEVEL_THREE(Items.ATTACKER_HORN_10518),
|
||||
LEVEL_FOUR(Items.ATTACKER_HORN_10519),
|
||||
LEVEL_FIVE(Items.ATTACKER_HORN_10520);
|
||||
|
||||
companion object {
|
||||
private val map = values().associateBy(AttackerHorn::itemId)
|
||||
fun fromId(id: Int): AttackerHorn? = map[id]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package content.minigame.barbassault.arena
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
//https://www.youtube.com/watch?v=OJ2BDEM03Dw
|
||||
|
||||
class BarbScoreManager {
|
||||
|
||||
private val trackers = mutableMapOf<Player, ScoreTracker>()
|
||||
|
||||
fun trackerFor(player: Player): ScoreTracker = trackers.getOrPut(player) { ScoreTracker() }
|
||||
|
||||
fun resetAll() {
|
||||
trackers.values.forEach { it.reset() }
|
||||
}
|
||||
|
||||
fun remove(player: Player) {
|
||||
trackers.remove(player)
|
||||
}
|
||||
fun allTrackers(): Collection<ScoreTracker> = trackers.values
|
||||
fun personal(player: Player, caps: SpawnCaps): RoleScore {
|
||||
return trackerFor(player).toScoreboard(caps)
|
||||
}
|
||||
//val caps = session.currentWaveCaps()
|
||||
//val teamScore = session.scoreManager.team(caps)
|
||||
fun team(caps: SpawnCaps): RoleScore {
|
||||
var total = RoleScore.ZERO
|
||||
for (tracker in allTrackers()) {
|
||||
total = total.add(tracker.toScoreboard(caps))
|
||||
}
|
||||
return total
|
||||
}
|
||||
}
|
||||
|
||||
data class AttackerStats(var rangersKilled: Int = 0, var fightersKilled: Int = 0, var incorrectStyleAttacks: Int = 0)
|
||||
data class CollectorStats(var eggsCollected: Int = 0, var eggsExploded: Int = 0) { val netEggs: Int get() = eggsCollected - eggsExploded }
|
||||
data class DefenderStats(var runnersKilled: Int = 0, var runnersPast: Int = 0)
|
||||
data class HealerStats(var healersKilled: Int = 0, var hitpointsReplenished: Int = 0, var wrongPoisonUsed: Int = 0)
|
||||
|
||||
data class ScoreTracker(var attackerStats: AttackerStats = AttackerStats(), var collectorStats: CollectorStats = CollectorStats(),
|
||||
var defenderStats: DefenderStats = DefenderStats(),var healerStats: HealerStats = HealerStats())
|
||||
{
|
||||
fun reset() {
|
||||
attackerStats = AttackerStats()
|
||||
collectorStats = CollectorStats()
|
||||
defenderStats = DefenderStats()
|
||||
healerStats = HealerStats()
|
||||
}
|
||||
fun toScoreboard(caps: SpawnCaps): RoleScore = BarbAssaultScoreBuilder.build(this, caps)
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
val attackerTotal: Int get() = rangersKilled + fightersKilled + incorrectStylePenalty
|
||||
val collectorTotal: Int get() = eggsScore
|
||||
val defenderTotal: Int get() = runnersKilledScore + runnersPastPenalty
|
||||
val healerTotal: Int get() = healersKilledScore + hitpointsHealedScore + wrongPoisonPenalty
|
||||
fun add(other: RoleScore): RoleScore = RoleScore(
|
||||
rangersKilled + other.rangersKilled,
|
||||
fightersKilled + other.fightersKilled,
|
||||
incorrectStylePenalty + other.incorrectStylePenalty,
|
||||
eggsScore + other.eggsScore,
|
||||
runnersKilledScore + other.runnersKilledScore,
|
||||
runnersPastPenalty + other.runnersPastPenalty,
|
||||
healersKilledScore + other.healersKilledScore,
|
||||
hitpointsHealedScore + other.hitpointsHealedScore,
|
||||
wrongPoisonPenalty + other.wrongPoisonPenalty
|
||||
)
|
||||
companion object {
|
||||
val ZERO = RoleScore(0,0,0,0,0,0,0,0,0)
|
||||
}
|
||||
}
|
||||
|
||||
object BarbAssaultScoreBuilder {
|
||||
fun build(tracker: ScoreTracker, caps: SpawnCaps): RoleScore {
|
||||
|
||||
val atk = tracker.attackerStats
|
||||
val col = tracker.collectorStats
|
||||
val def = tracker.defenderStats
|
||||
val heal = tracker.healerStats
|
||||
|
||||
val rangerKillScore = atk.rangersKilled.coerceAtMost(caps.rangers) - 1
|
||||
val fighterKillScore = atk.fightersKilled.coerceAtMost(caps.fighters) - 1
|
||||
val incorrectStylePenalty = (-atk.incorrectStyleAttacks + 1).coerceAtLeast(-10)
|
||||
|
||||
val eggScore = (col.netEggs.coerceAtMost(60) / 4.35).toInt()
|
||||
|
||||
val runnersKilledScore = (1.8 * def.runnersKilled.coerceAtMost(caps.runners)).toInt()
|
||||
val runnersPastPenalty = (-3 * def.runnersPast).coerceAtLeast(-10)
|
||||
|
||||
val healerKillScore = (0.7 * heal.healersKilled.coerceAtMost(caps.healers)).toInt()
|
||||
val hitpointsHealedScore = (heal.hitpointsReplenished / 18).coerceAtMost(28)
|
||||
val wrongPoisonPenalty = -(heal.wrongPoisonUsed.coerceAtMost(512) / 4)
|
||||
|
||||
return RoleScore(
|
||||
rangersKilled = rangerKillScore,
|
||||
fightersKilled = fighterKillScore,
|
||||
incorrectStylePenalty = incorrectStylePenalty,
|
||||
|
||||
eggsScore = eggScore,
|
||||
|
||||
runnersKilledScore = runnersKilledScore,
|
||||
runnersPastPenalty = runnersPastPenalty,
|
||||
|
||||
healersKilledScore = healerKillScore,
|
||||
hitpointsHealedScore = hitpointsHealedScore,
|
||||
wrongPoisonPenalty = wrongPoisonPenalty
|
||||
)
|
||||
}
|
||||
}
|
||||
687
Server/src/main/content/minigame/barbassault/arena/BASession.kt
Normal file
687
Server/src/main/content/minigame/barbassault/arena/BASession.kt
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
package content.minigame.barbassault.arena
|
||||
|
||||
import content.minigame.barbassault.ALL_BARBASS_ITEMS
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.BAActivity
|
||||
import content.minigame.barbassault.LureItems
|
||||
import content.minigame.barbassault.arena.scenery.EggCannon
|
||||
import content.minigame.barbassault.arena.scenery.GloryHorn
|
||||
import content.minigame.barbassault.getBALevels
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.getBAWave
|
||||
import content.minigame.barbassault.lobby.*
|
||||
import content.minigame.barbassault.lobby.BALobby.Companion.waveLobbies
|
||||
import content.minigame.barbassault.setBASession
|
||||
import core.api.*
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_ACCURATE
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_AGGRESSIVE
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_CONTROLLED
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface.STYLE_DEFENSIVE
|
||||
import core.game.node.entity.impl.PulseManager
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.GroundItemManager
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.GameWorld.Pulser
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
import core.game.world.map.zone.*
|
||||
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
|
||||
import removeCollectorBag
|
||||
import kotlin.text.lowercase
|
||||
|
||||
|
||||
enum class BarbassaultState { PARTY_CREATION, STARTING, IN_ARENA,FORFEIT, COMPLETE,DEATH, END }
|
||||
data class PenanceNpcTunnel( val type: PenanceType, val caveLocation: Location, val spawnOffset: Location, val direction: Direction)
|
||||
data class ArenaSpawnItems(val id: Int, val location: Location)
|
||||
|
||||
class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, MapArea {
|
||||
lateinit var region: DynamicRegion
|
||||
lateinit var base: Location
|
||||
lateinit var currentWaveDefinition: WaveDefinition
|
||||
lateinit var team: BarbTeam
|
||||
|
||||
var state: BarbassaultState = BarbassaultState.PARTY_CREATION
|
||||
|
||||
val sessionNpcs = mutableListOf<NPC>()
|
||||
var currentNPCCount = SpawnCaps(0,0,0,0)
|
||||
var currentNPCDeathCount = SpawnCaps(0,0,0,0)
|
||||
var currentNPCEscapeCount = SpawnCaps(0,0,0,0)
|
||||
|
||||
var npcTunnel: List<PenanceNpcTunnel> = listOf(
|
||||
PenanceNpcTunnel(PenanceType.RANGER,location(17,47,0),location(18,46,0),Direction.SOUTH),
|
||||
PenanceNpcTunnel(PenanceType.FIGHTER,location(23,48,0),location(24,47,0),Direction.SOUTH),
|
||||
PenanceNpcTunnel(PenanceType.RUNNER,location(35,48,0),location(36,47,0),Direction.SOUTH),
|
||||
PenanceNpcTunnel(PenanceType.HEALER,location(41,47,0),location(42,46,0),Direction.SOUTH))
|
||||
private val caveBlocked = mutableMapOf<PenanceType, Boolean>()
|
||||
|
||||
val BAgroundItems = mutableListOf<BAGroundSpawn>()
|
||||
val arenaSpawnItems: List<ArenaSpawnItems> = listOf(ArenaSpawnItems(Items.HAMMER_2347,location(32,42,0)),ArenaSpawnItems(Items.LOGS_11760,location(30,46,0)),ArenaSpawnItems(Items.LOGS_11760,location(29,47,0)))
|
||||
|
||||
val eggHopper = EggCannon.EggHopper()
|
||||
var eggCannonNpcWest: NPC? = null
|
||||
var eggCannonNpcEast: NPC? = null
|
||||
|
||||
val scoreManager = BarbScoreManager()
|
||||
val eventBus = BarbAssEventBus()
|
||||
|
||||
private var countDoown = if(GameWorld.settings?.isDevMode == true) 10 else 30
|
||||
private var countdownPulse: Pulse? = null
|
||||
|
||||
|
||||
fun beginStartingPhase(quickStart: Boolean = false) {
|
||||
if (state != BarbassaultState.PARTY_CREATION) return
|
||||
state = BarbassaultState.STARTING
|
||||
currentWaveDefinition = getWaveDefinition(team.wave)
|
||||
createArena()
|
||||
startCountdown(quickStart)
|
||||
}
|
||||
fun cancleStartingPhase(){
|
||||
if (state != BarbassaultState.STARTING) return
|
||||
state = BarbassaultState.PARTY_CREATION
|
||||
countdownPulse?.stop()
|
||||
countdownPulse = null
|
||||
broadcast("-- Next wave no longer starting")
|
||||
}
|
||||
private fun enterArena() {
|
||||
state = BarbassaultState.IN_ARENA
|
||||
region.setMusicId(ASSAULT_AND_BATTERY_604)
|
||||
|
||||
for (player in team.allPlayers()) {
|
||||
val pRole = getBASession(player)?.team?.getRoleForPlayer(player)
|
||||
equipBARoleIcon(player, pRole!!)
|
||||
player.properties.teleportLocation = team.spawnLocationFor(player)
|
||||
giveRoleItems(player,pRole)
|
||||
registerLogoutListener(player, "ba-logout") { handleLogout(player) }
|
||||
}
|
||||
|
||||
Pulser.submit(GamePulse())
|
||||
tryGroundItemSpawn()
|
||||
}
|
||||
|
||||
fun endSession() {
|
||||
if (state == BarbassaultState.END) return
|
||||
state = BarbassaultState.END
|
||||
|
||||
for (player in team.allPlayers()) {
|
||||
clearLogoutListener(player, "ba-logout")
|
||||
player.removeAttribute("ba-session")
|
||||
player.properties.teleportLocation = Location.create(2593, 5264, 0)
|
||||
player.interfaceManager.closeOverlay()
|
||||
}
|
||||
// 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(quickStart: Boolean) {
|
||||
countDoown = if (quickStart) 1 else countDoown
|
||||
var ticks = secondsToTicks(countDoown)//30
|
||||
if(!quickStart){ team.allPlayers().forEach { openOverlay(it, 494);setInterfaceText(it, "30", 494, 0) } }
|
||||
countdownPulse = object : Pulse(1) {
|
||||
override fun pulse(): Boolean {
|
||||
if (state != BarbassaultState.STARTING) return true
|
||||
|
||||
ticks--
|
||||
|
||||
if (ticks <= 0) {
|
||||
enterArena()
|
||||
rollNewRoleCalls()
|
||||
return true
|
||||
}
|
||||
|
||||
val secondsLeft = ticksToSeconds(ticks)
|
||||
val display = secondsLeft.toString().padStart(2, '0')
|
||||
if(!quickStart) {
|
||||
team.allPlayers().forEach { setInterfaceText(it, display, 494, 0) }
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Pulser.submit(countdownPulse!!)
|
||||
}
|
||||
|
||||
private fun InitEvents() {
|
||||
eventBus.register(BarbAssEvent.NPCDied::class.java) { event ->
|
||||
val tracker = scoreManager.trackerFor(event.killer)
|
||||
val npcRoleType = event.npc.getAttribute<BarbRole>("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++
|
||||
}
|
||||
eventBus.register(BarbAssEvent.RunnerEscaped::class.java) { event ->
|
||||
val tracker = scoreManager.trackerFor(event.player)
|
||||
tracker.defenderStats.runnersPast++
|
||||
}
|
||||
}
|
||||
fun isPenanceDead(type: PenanceType): Boolean = currentNPCDeathCount[type] >= currentWaveDefinition.caps[type]
|
||||
fun isAllPenanceDead(): Boolean = PenanceType.values().all { isPenanceDead(it) }
|
||||
|
||||
fun runnerEscaped(runner: NPC) {
|
||||
val defenders = team.getPlayersByRole(BarbRole.DEFENDER)
|
||||
val penalizedPlayers = if (defenders.isEmpty()) team.allPlayers() else defenders
|
||||
penalizedPlayers.forEach { eventBus.emit(BarbAssEvent.RunnerEscaped(it)) }
|
||||
|
||||
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)) {
|
||||
type.toString()
|
||||
session.broadcast("All of the Penance ${type.name.lowercase().replaceFirstChar { it.uppercase() }}s have been killed!")
|
||||
}
|
||||
}
|
||||
|
||||
fun setCaveBlocked(node: Node, blocked: Boolean) {
|
||||
val tunnel = npcTunnel.firstOrNull { t -> base.transform(t.caveLocation) == node.location } ?: return
|
||||
|
||||
if (blocked) {
|
||||
caveBlocked[tunnel.type] = true
|
||||
} else {
|
||||
caveBlocked.remove(tunnel.type)
|
||||
}
|
||||
}
|
||||
|
||||
fun isCaveBlocked(type: PenanceType): Boolean {
|
||||
return caveBlocked[type] == true
|
||||
}
|
||||
|
||||
fun forceWaveSpawn(force: Boolean = false){
|
||||
tryPenanceSpawn(PenanceType.RANGER,force)
|
||||
tryPenanceSpawn(PenanceType.FIGHTER,force)
|
||||
tryPenanceSpawn(PenanceType.RUNNER,force)
|
||||
tryPenanceSpawn(PenanceType.HEALER,force)
|
||||
}
|
||||
|
||||
fun tryPenanceSpawn(type: PenanceType, force: Boolean = false): Boolean {
|
||||
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 = 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)
|
||||
}
|
||||
|
||||
fun tryGroundItemSpawn(){
|
||||
val groundItems = GroundItemManager.getItems()
|
||||
|
||||
arenaSpawnItems.forEach { spawnItem ->
|
||||
val spawnLoc = spawnItem.location
|
||||
val alreadyExists = groundItems.any { it.id == spawnItem.id && it.location == spawnLoc && !it.isRemoved }
|
||||
if (!alreadyExists) {
|
||||
produceGroundSpawnItem(6,Item(spawnItem.id, 1),spawnLoc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pickUpGroundItem(player: Player,node:BAGroundSpawn): Boolean {
|
||||
if (player.inventory.add(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, allowRespawn: Boolean = false){
|
||||
node.isActive = false
|
||||
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
|
||||
.asSequence()
|
||||
.map { it to distance(it.location, target) }
|
||||
.filter { (node, dist) -> node.id in LureItems && dist <= node.getLureRange() }
|
||||
.minByOrNull { (_, dist) -> dist }?.first
|
||||
}
|
||||
|
||||
fun forfeit(){ state = BarbassaultState.FORFEIT }
|
||||
fun isInBarbAssaultGame() = state == BarbassaultState.IN_ARENA
|
||||
|
||||
fun endGame(endReason: String){
|
||||
eventBus.clear()
|
||||
scoreManager.resetAll()
|
||||
BALobby.TeamToLobby(team,team.wave)
|
||||
state = BarbassaultState.PARTY_CREATION
|
||||
for(player in team.allPlayers()) {
|
||||
PulseManager.cancelDeathTask(player)
|
||||
Pulser.submit(object : Pulse(1, player) {
|
||||
override fun pulse(): Boolean {
|
||||
player.getSkills().restore()
|
||||
return true
|
||||
}
|
||||
})
|
||||
closeInterface(player)
|
||||
openOverlay(player, 256)
|
||||
//https://youtu.be/MpYZG3qkFUA?t=387
|
||||
//todo do not send message to person who exited the game.
|
||||
player.dialogueInterpreter.sendDialogue("The game ended early because one of your team-mates $endReason.")
|
||||
BarbTeamManager.updateTeam(getBASession(player)?.team!!)
|
||||
}
|
||||
}
|
||||
//MAIN GAME LOOP
|
||||
private inner class GamePulse : Pulse(1) {
|
||||
private val baseCallTicks = secondsToTicks(30)
|
||||
private var roleCallTicks = baseCallTicks
|
||||
|
||||
private var baseSpawnTicks = secondsToTicks(6)
|
||||
private var waveSpawnTicks = SpawnCaps( baseSpawnTicks, baseSpawnTicks, baseSpawnTicks, baseSpawnTicks )
|
||||
|
||||
override fun pulse(): Boolean {
|
||||
when(state){
|
||||
BarbassaultState.IN_ARENA -> {
|
||||
eventBus.processEvents()
|
||||
|
||||
roleCallTicks--
|
||||
if (roleCallTicks <= 0) { rollNewRoleCalls(); roleCallTicks = baseCallTicks }
|
||||
|
||||
for (type in PenanceType.values()) {
|
||||
waveSpawnTicks[type]--
|
||||
if (waveSpawnTicks[type] <= 0) { waveSpawnTicks[type] = if (tryPenanceSpawn(type)) baseSpawnTicks * 2 else baseSpawnTicks
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
BarbassaultState.FORFEIT -> { endGame("exited early."); return true }
|
||||
BarbassaultState.COMPLETE -> {
|
||||
log(this.javaClass, Log.FINE,state.toString())
|
||||
BALobby.TeamToLobby(team,team.wave+1)
|
||||
state = BarbassaultState.PARTY_CREATION
|
||||
for(player in team.allPlayers()) {
|
||||
PulseManager.cancelDeathTask(player)
|
||||
closeInterface(player)
|
||||
openOverlay(player, 256)
|
||||
BarbTeamManager.updateTeam(getBASession(player)?.team!!)
|
||||
}
|
||||
return true // we do not have auto start next wave in 2009
|
||||
}
|
||||
BarbassaultState.DEATH -> { endGame("died."); return true }
|
||||
BarbassaultState.END -> return true
|
||||
else -> return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun createArena() {
|
||||
region = DynamicRegion.create(BarbassaultArenaListener.BA_ARENA.MAIN)
|
||||
base = region.baseLocation
|
||||
zone.zoneType = ZoneType.SAFE.id
|
||||
region.regionZones.add(RegionZone(activity!!, region.borders)) //DONT FORGET THIS STUPID!
|
||||
region.toggleMulticombat()
|
||||
spawnEggCannons()
|
||||
zone.register(getRegionBorders(region.id))
|
||||
}
|
||||
|
||||
private fun destroyArena() {
|
||||
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,ALL_BARBASS_ITEMS)
|
||||
region.remove(player)
|
||||
team.removePlayer(player)
|
||||
player.locks.unlockTeleport()
|
||||
|
||||
player.location = waveLobbies[team.wave].randomWalkableLoc
|
||||
|
||||
/* if (team.allPlayers().isEmpty()) { // might be redundant
|
||||
player.properties.teleportLocation = Location.create(2593, 5264, 0)
|
||||
endSession()
|
||||
}*/
|
||||
}
|
||||
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> = arrayOf()
|
||||
override fun getRestrictions(): Array<ZoneRestriction> = arrayOf( ZoneRestriction.CANNON, ZoneRestriction.FIRES, ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.TELEPORT )
|
||||
|
||||
override fun areaEnter(entity: Entity) {
|
||||
val player = entity as? Player ?: return
|
||||
log(this::class.java, Log.FINE, "ENTERED Barbassault Arena")
|
||||
val waveNum = getBAWave(player)
|
||||
val interfaceId = getRoleInterfaceId(getBASession(player)!!.team.getRoleForPlayer(player))
|
||||
player.fullRestore()
|
||||
//todo consolidate logic.
|
||||
interfaceId?.let {
|
||||
sendMessage(player, "----- Wave: $waveNum -----")
|
||||
openOverlay(player, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun areaLeave(entity: Entity, logout: Boolean) {
|
||||
super.areaLeave(entity, logout)
|
||||
val player = entity as? Player ?: return
|
||||
log(this::class.java, Log.FINE, "LEFT Barbassault Arena")
|
||||
|
||||
removeTimer(player, "teleblock")
|
||||
zone.cleanItems(player,ALL_BARBASS_ITEMS)
|
||||
removeCollectorBag(player)
|
||||
clearLogoutListener(player, "ba-logout")
|
||||
player.fullRestore()
|
||||
destroyArena()
|
||||
}
|
||||
fun sessionNPCSpawn(id: Int, location: Location, direction: Direction, vararg objects: Any): NPC? = NPC.create(id, base.transform(location), direction, *objects)?.also { it.init(); sessionNpcs.add(it) }
|
||||
fun produceGroundSpawnItem(rate:Int,item: Item,location: Location): BAGroundSpawn = BAGroundSpawn(this, rate, item, base.transform(location)).also { it.init() }
|
||||
|
||||
fun spawnEggCannons() {
|
||||
eggCannonNpcWest = sessionNPCSpawn( NPCs.EGG_LAUNCHER_5026, location(21, 34, 0), Direction.NORTH )
|
||||
if (team.wave == 10) return
|
||||
eggCannonNpcEast = sessionNPCSpawn( NPCs.EGG_LAUNCHER_5026, location(40, 34, 0), Direction.NORTH )
|
||||
}
|
||||
|
||||
fun clearGroundItems(){
|
||||
BAgroundItems.forEach { item ->
|
||||
item.isActive = false
|
||||
item.setRespawnRate(-1)
|
||||
item.isAutoSpawn = false
|
||||
GroundItemManager.destroy(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun giveRoleItems(player: Player, role: BarbRole) {
|
||||
val attackerHorns = intArrayOf(Items.ATTACKER_HORN_10516,Items.ATTACKER_HORN_10517,Items.ATTACKER_HORN_10518,Items.ATTACKER_HORN_10519,Items.ATTACKER_HORN_10520)
|
||||
val healerHorns = intArrayOf(Items.HEALER_HORN_10526,Items.HEALER_HORN_10527,Items.HEALER_HORN_10528,Items.HEALER_HORN_10529,Items.HEALER_HORN_10530)
|
||||
val collectorBags = intArrayOf(Items.COLLECTION_BAG_10521,Items.COLLECTION_BAG_10522,Items.COLLECTION_BAG_10523,Items.COLLECTION_BAG_10524,Items.COLLECTION_BAG_10525)
|
||||
fun levelIndex(level: Int): Int { return (level.coerceIn(1, 5) - 1) }
|
||||
|
||||
val levels = getBALevels(player)
|
||||
val items = when (role) {
|
||||
BarbRole.ATTACKER -> intArrayOf( attackerHorns[levelIndex(levels.atk)] )
|
||||
BarbRole.DEFENDER -> intArrayOf( Items.DEFENDER_HORN_10538 )
|
||||
BarbRole.HEALER -> intArrayOf( healerHorns[levelIndex(levels.heal)] )
|
||||
BarbRole.COLLECTOR -> intArrayOf( collectorBags[levelIndex(levels.col)], Items.COLLECTOR_HORN_10560 )
|
||||
}
|
||||
|
||||
items.forEach { player.inventory.add(Item(it, 1)) }
|
||||
}
|
||||
|
||||
private fun equipBARoleIcon(player: Player, role: BarbRole) {
|
||||
val BA_ROLE_CAPE = mapOf( BarbRole.ATTACKER to 10556, BarbRole.DEFENDER to 10558, BarbRole.COLLECTOR to 10557, BarbRole.HEALER to 10559 )
|
||||
val itemId = BA_ROLE_CAPE[role] ?: return
|
||||
player.equipment.add(Item(itemId),true,false)
|
||||
}
|
||||
|
||||
fun broadcast(message: String) = team.allPlayers().forEach { sendMessage(it, message) }
|
||||
fun broadcastToRole(role: BarbRole, message: String) = team.getPlayersByRole(role).forEach { sendMessage(it, message) }
|
||||
|
||||
fun updateBarbHealerIfaceHPOfPlayer(player: Player) = team.getPlayersByRole(BarbRole.HEALER).forEach { HealerIfaceHPUpdatePlayer(it, player)}
|
||||
fun alertHealers(player:Player) = team.getPlayersByRole(BarbRole.HEALER).forEach { HealerIfaceMedicHelp(it,player) }
|
||||
|
||||
fun updateAttackerUI(player: Player, call: AttackerCall) {
|
||||
val style = call.called
|
||||
if (style == null) {
|
||||
setInterfaceText(player, "- - -", Components.BARBASSAULT_OVER_ATT_485, 4)
|
||||
setInterfaceText(player, "", Components.BARBASSAULT_OVER_ATT_485, 5)
|
||||
return
|
||||
}
|
||||
setInterfaceText(player, style.top, Components.BARBASSAULT_OVER_ATT_485, 4)
|
||||
setInterfaceText(player, style.bottom, Components.BARBASSAULT_OVER_ATT_485, 5)
|
||||
}
|
||||
fun updateOtherRoleUI(player: Player,call: RoleCall<*>,interfaceId: Int,childId: Int ) {
|
||||
val text = (call.called as? HasUIText)?.ui ?: "- - -"
|
||||
setInterfaceText(player, text, interfaceId, childId)
|
||||
}
|
||||
|
||||
fun updateRoleUI() {
|
||||
team.allPlayers().forEach { player ->
|
||||
val wave = team.wave.toString()
|
||||
val role = team.getRoleForPlayer(player)
|
||||
val call = roleCalls[role] ?: return@forEach
|
||||
|
||||
|
||||
when (role) {
|
||||
BarbRole.ATTACKER -> {
|
||||
updateAttackerUI(player, call as AttackerCall)
|
||||
setInterfaceText(player, "Wave $wave" , Components.BARBASSAULT_OVER_ATT_485, 2)
|
||||
setInterfaceText(player, call.crossRoleDisplay(), Components.BARBASSAULT_OVER_ATT_485, 7)
|
||||
}
|
||||
BarbRole.COLLECTOR -> {
|
||||
updateOtherRoleUI(player, call, Components.BARBASSAULT_OVER_COL_486, 4)
|
||||
setInterfaceText(player, "Wave $wave" , Components.BARBASSAULT_OVER_COL_486, 2)
|
||||
setInterfaceText(player, call.crossRoleDisplay(), Components.BARBASSAULT_OVER_COL_486, 6)
|
||||
}
|
||||
BarbRole.DEFENDER -> {
|
||||
updateOtherRoleUI(player, call, Components.BARBASSAULT_OVER_DEF_487, 3)
|
||||
setInterfaceText(player, "Wave $wave" , Components.BARBASSAULT_OVER_DEF_487, 1)
|
||||
setInterfaceText(player, call.crossRoleDisplay(), Components.BARBASSAULT_OVER_DEF_487, 5)
|
||||
}
|
||||
BarbRole.HEALER -> {
|
||||
updateOtherRoleUI(player, call, Components.BARBASSAULT_OVER_HEAL_488, 31)
|
||||
setInterfaceText(player, "Wave $wave" , Components.BARBASSAULT_OVER_HEAL_488, 29)
|
||||
setInterfaceText(player, call.crossRoleDisplay(), Components.BARBASSAULT_OVER_HEAL_488, 33)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getRoleInterfaceId(role: BarbRole): Int? {
|
||||
return when (role) {
|
||||
BarbRole.ATTACKER -> Components.BARBASSAULT_OVER_ATT_485
|
||||
BarbRole.COLLECTOR -> Components.BARBASSAULT_OVER_COL_486
|
||||
BarbRole.DEFENDER -> Components.BARBASSAULT_OVER_DEF_487
|
||||
BarbRole.HEALER -> Components.BARBASSAULT_OVER_HEAL_488
|
||||
}
|
||||
}
|
||||
|
||||
fun rollNewRoleCalls() {
|
||||
roleCalls[BarbRole.ATTACKER] = AttackerCall(AttackerStyle.values().random())
|
||||
roleCalls[BarbRole.HEALER] = HealerCall(PoisonFood.values().random())
|
||||
roleCalls[BarbRole.DEFENDER] = DefenderCall(LureFood.values().random())
|
||||
roleCalls[BarbRole.COLLECTOR] = CollectorCall(EggColor.values().random())
|
||||
|
||||
roleCalls[BarbRole.COLLECTOR]?.toCall = roleCalls[BarbRole.ATTACKER]?.required
|
||||
roleCalls[BarbRole.ATTACKER]?.toCall = roleCalls[BarbRole.COLLECTOR]?.required
|
||||
roleCalls[BarbRole.HEALER]?.toCall = roleCalls[BarbRole.DEFENDER]?.required
|
||||
roleCalls[BarbRole.DEFENDER]?.toCall = roleCalls[BarbRole.HEALER]?.required
|
||||
updateRoleUI()
|
||||
updateGloryHornUI()
|
||||
team.allPlayers().forEach { if(it.isArtificial){ botMakeCall(it) } }
|
||||
}
|
||||
|
||||
fun updateGloryHornUI(){
|
||||
team.allPlayers().forEach { player ->
|
||||
val atkCallText = (roleCalls[BarbRole.COLLECTOR]?.toCall as? AttackerStyle)?.let { "${it.top}${it.bottom}" } ?: GloryHorn.CallOut.defaultText
|
||||
val colCallText = (roleCalls[BarbRole.ATTACKER]?.toCall as? HasUIText)?.ui ?: GloryHorn.CallOut.defaultText
|
||||
val defCallText = (roleCalls[BarbRole.HEALER]?.toCall as? HasUIText)?.ui ?: GloryHorn.CallOut.defaultText
|
||||
val healCallText = (roleCalls[BarbRole.DEFENDER]?.toCall as? HasUIText)?.ui ?: GloryHorn.CallOut.defaultText
|
||||
|
||||
setInterfaceText(player, atkCallText, Components.BARBASSAULT_HORN_484, GloryHorn.CallOut.attacker)
|
||||
setInterfaceText(player, colCallText, Components.BARBASSAULT_HORN_484, GloryHorn.CallOut.collector)
|
||||
setInterfaceText(player, defCallText, Components.BARBASSAULT_HORN_484, GloryHorn.CallOut.defender)
|
||||
setInterfaceText(player, healCallText, Components.BARBASSAULT_HORN_484, GloryHorn.CallOut.healer)
|
||||
}
|
||||
}
|
||||
|
||||
private val hornTargets = mapOf( BarbRole.COLLECTOR to BarbRole.ATTACKER, BarbRole.ATTACKER to BarbRole.COLLECTOR ,
|
||||
BarbRole.HEALER to BarbRole.DEFENDER, BarbRole.DEFENDER to BarbRole.HEALER )
|
||||
|
||||
private fun dispatchCall(call: Any, calledValue: Any) {
|
||||
when (call) {
|
||||
is AttackerCall -> if (calledValue is AttackerStyle) call.call(calledValue)
|
||||
is HealerCall -> if (calledValue is PoisonFood) call.call(calledValue)
|
||||
is DefenderCall -> if (calledValue is LureFood) call.call(calledValue)
|
||||
is CollectorCall -> if (calledValue is EggColor) call.call(calledValue)
|
||||
}
|
||||
}
|
||||
|
||||
fun onHornCall(player: Player, calledValue: Any) {
|
||||
val callerRole = team.getRoleForPlayer(player)
|
||||
val targetRole = hornTargets[callerRole] ?: return
|
||||
val call = roleCalls[targetRole] ?: return
|
||||
|
||||
dispatchCall(call,calledValue)
|
||||
updateRoleUI()
|
||||
}
|
||||
|
||||
fun botMakeCall(bot: Player) {
|
||||
val session = getBASession(bot) ?: return
|
||||
val role = session.team.getRoleForPlayer(bot)
|
||||
|
||||
val calledValue = when (role) {
|
||||
BarbRole.ATTACKER -> session.roleCalls[BarbRole.ATTACKER]?.toCall as? EggColor
|
||||
BarbRole.COLLECTOR -> session.roleCalls[BarbRole.COLLECTOR]?.toCall as? AttackerStyle
|
||||
BarbRole.DEFENDER -> session.roleCalls[BarbRole.DEFENDER]?.toCall as? PoisonFood
|
||||
BarbRole.HEALER -> session.roleCalls[BarbRole.HEALER]?.toCall as? LureFood
|
||||
} ?: return
|
||||
|
||||
session.onHornCall(bot, calledValue)
|
||||
|
||||
val text = when (calledValue) {
|
||||
is EggColor -> calledValue.hornShout
|
||||
is PoisonFood -> calledValue.hornShout
|
||||
is LureFood -> calledValue.hornShout
|
||||
is AttackerStyle -> calledValue.hornShout
|
||||
else -> return
|
||||
}
|
||||
sendChat(bot, text)
|
||||
}
|
||||
|
||||
fun onHornGloryCall(calledValue: Any) {
|
||||
val targetRole = when (calledValue) {
|
||||
is AttackerStyle -> BarbRole.ATTACKER
|
||||
is PoisonFood -> BarbRole.HEALER
|
||||
is LureFood -> BarbRole.DEFENDER
|
||||
is EggColor -> BarbRole.COLLECTOR
|
||||
else -> return
|
||||
}
|
||||
|
||||
val call = roleCalls[targetRole] ?: return
|
||||
dispatchCall(call,calledValue)
|
||||
updateRoleUI()
|
||||
}
|
||||
|
||||
fun onAttackerHit(style: AttackerStyle) {
|
||||
val call = roleCalls[BarbRole.ATTACKER] as? AttackerCall ?: return
|
||||
call.check(style)
|
||||
}
|
||||
|
||||
val roleCalls: MutableMap<BarbRole, RoleCall<*>> = mutableMapOf()
|
||||
interface HasUIText { val ui: String; val hornShout:String }
|
||||
enum class AttackerStyle(val top: String, val bottom: String, override val hornShout:String,val attackStyle: Int):HasUIText {
|
||||
STYLE_1("Controlled/","Bronze/Wind", "Attacker: Controlled/Bronze/Wind!",STYLE_CONTROLLED),
|
||||
STYLE_2("Accurate/","Iron/Water", "Attacker: Accurate/Iron/Water!", STYLE_ACCURATE),
|
||||
STYLE_3("Aggressive/","Steel/Earth", "Attacker: Aggressive/Steel/Earth!",STYLE_AGGRESSIVE),
|
||||
STYLE_4("Defensive/","Mithril/Fire", "Attacker: Defensive/Mithril/Fire!",STYLE_DEFENSIVE);
|
||||
override val ui: String get() = top
|
||||
}
|
||||
|
||||
enum class EggColor(override val ui: String, val itemId:Int, override val hornShout:String):HasUIText {
|
||||
RED( "Red Eggs", Items.RED_EGG_10532, "Collector: Red Eggs!"),
|
||||
GREEN("Green Eggs",Items.GREEN_EGG_10531, "Collector: Green Eggs!"),
|
||||
BLUE( "Blue Eggs", Items.BLUE_EGG_10533, "Collector: Blue Eggs!")
|
||||
}
|
||||
|
||||
enum class PoisonFood(override val ui: String, val itemId:Int, override val hornShout:String):HasUIText {
|
||||
TOFU( "Pois. Tofu", Items.POISONED_TOFU_10539, "Healer: Poison tofu!"),
|
||||
WORMS("Pois. Worms",Items.POISONED_WORMS_10540,"Healer: Poison worms!"),
|
||||
MEAT( "Pois. Meat", Items.POISONED_MEAT_10541, "Healer: Poison meat!");
|
||||
}
|
||||
|
||||
enum class LureFood(override val ui: String, val itemId:Int, override val hornShout:String):HasUIText {
|
||||
TOFU( "Tofu", Items.TOFU_10514, "Defender: Drop Tofu!"),
|
||||
CRACKERS("Crackers",Items.CRACKERS_10513,"Defender: Drop Crackers!"),
|
||||
WORMS( "Worms", Items.WORMS_10515, "Defender: Drop Worms!");
|
||||
}
|
||||
|
||||
class AttackerCall( override val required: AttackerStyle ) : RoleCall<AttackerStyle>()
|
||||
class HealerCall( override val required: PoisonFood ) : RoleCall<PoisonFood>()
|
||||
class DefenderCall( override val required: LureFood ) : RoleCall<LureFood>()
|
||||
class CollectorCall( override val required: EggColor ) : RoleCall<EggColor>()
|
||||
|
||||
sealed class RoleCall<T> {
|
||||
abstract val required: T
|
||||
var called: T? = null
|
||||
private set
|
||||
var succeeded: Boolean = false
|
||||
private set
|
||||
var toCall: Any? = null
|
||||
fun call(value: T) { called = value }
|
||||
fun check(value: T): Boolean { if (value == required) { succeeded = true; return true }; return false }
|
||||
fun crossRoleDisplay(): String {
|
||||
return when (this) {
|
||||
is CollectorCall -> (toCall as? AttackerStyle)?.name?.lowercase()?.replaceFirstChar { it.uppercase() } ?: "- - -"
|
||||
else -> (toCall as? HasUIText)?.ui ?: "- - -"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import content.minigame.barbassault.getBALevels
|
||||
import core.api.sendMessage
|
||||
import core.api.sendDialogueLines
|
||||
import core.game.container.Container
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.Items
|
||||
|
||||
fun getCollectorBag(player: Player): CollectorBagManager {
|
||||
return player.getAttribute<CollectorBagManager>(CollectorBagManager.KEY) ?: CollectorBagManager(player).also { player.setAttribute(CollectorBagManager.KEY, it) }
|
||||
}
|
||||
fun removeCollectorBag(player: Player) = player.removeAttribute(CollectorBagManager.KEY)
|
||||
fun resetCollectorBag(player: Player) = player.setAttribute(CollectorBagManager.KEY,CollectorBagManager(player))
|
||||
|
||||
class CollectorBagManager(val player: Player) {
|
||||
val bag: CollectorBag = CollectorBag(getCollectorBagCapacity(getBALevels(player).col))
|
||||
|
||||
fun getCollectorBagCapacity(level: Int): Int = when (level) { 1 -> 2; 2 -> 3; 3 -> 6; 4 -> 7; 5 -> 8; else -> 2 }
|
||||
fun lookInBag() {
|
||||
val green = bag.getEggCount(Items.GREEN_EGG_10531)
|
||||
val red = bag.getEggCount(Items.RED_EGG_10532)
|
||||
val blue = bag.getEggCount(Items.BLUE_EGG_10533)
|
||||
|
||||
sendDialogueLines(player,"The collection bag contains:","$green poison eggs, $red explosive eggs","and $blue stun eggs.")
|
||||
}
|
||||
companion object {
|
||||
val VALID_EGGS = setOf(Items.RED_EGG_10532,Items.GREEN_EGG_10531,Items.BLUE_EGG_10533)
|
||||
val KEY = "collector_bag_manager"
|
||||
}
|
||||
|
||||
class CollectorBag(val capacity: Int) {
|
||||
|
||||
var container = Container(3)
|
||||
|
||||
fun totalEggs(): Int = container.toArray().filterNotNull().sumOf { it.amount }
|
||||
fun freeEggSpace(): Int = capacity - totalEggs()
|
||||
fun getEggCount(itemId: Int): Int = container.toArray().filterNotNull().filter { it.id == itemId }.sumOf { it.amount }
|
||||
|
||||
}
|
||||
|
||||
fun addToBag(node: Node): Boolean {
|
||||
if (node.id !in VALID_EGGS) return false
|
||||
if (bag.freeEggSpace() <= 0) { sendMessage(player, "Your bag is full."); return false }
|
||||
|
||||
val egg = Item(node.id, 1)
|
||||
bag.container.add(egg)
|
||||
sendMessage(player, "You put the egg in the bag.")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package content.minigame.barbassault.arena
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.api.setComponentVisibility
|
||||
import core.api.setInterfaceText
|
||||
import core.game.component.Component
|
||||
import core.game.component.ComponentDefinition
|
||||
import core.game.component.ComponentPlugin
|
||||
import core.game.node.entity.player.Player
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import org.rs09.consts.Components
|
||||
|
||||
// Todo find actual varbits for controlling the interface
|
||||
@Initializable
|
||||
class HealerInterface : ComponentPlugin() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
ComponentDefinition.forId(HealerIface.ID).plugin = this
|
||||
return this
|
||||
}
|
||||
override fun open(player: Player?, component: Component?) {
|
||||
super.open(player, component)
|
||||
player ?: return
|
||||
|
||||
setHealerTeamIfaceSlot(player,0)
|
||||
setHealerTeamIfaceSlot(player,1)
|
||||
setHealerTeamIfaceSlot(player,2)
|
||||
setHealerTeamIfaceSlot(player,3)
|
||||
|
||||
}
|
||||
|
||||
override fun handle( player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setHealerTeamIfaceSlot(player: Player,slot: Int){
|
||||
val slotIface = HealerIface.team[slot]
|
||||
val slotPlayer = getPlayerHealerIfaceSlot(player,slot)
|
||||
val slotHealth = HealerIface.formatHp(slotPlayer?.skills?.lifepoints ,slotPlayer?.skills?.maximumLifepoints)
|
||||
|
||||
//todo find a way to crop the model.
|
||||
//20578 is the correct model
|
||||
//setInterfaceModel(player, 20578, HealerIface.ID, slotIface.roleChild, HealerIface.modelZoom,572,0) // role Icon
|
||||
setInterfaceText(player, slotPlayer?.username.toString(), HealerIface.ID, slotIface.nameChild) //Name
|
||||
setInterfaceText(player, slotHealth, HealerIface.ID, slotIface.hpChild)// Health
|
||||
}
|
||||
|
||||
fun getPlayerHealerIfaceSlot(player:Player,slot: Int): Player? {
|
||||
val team = getBASession(player)?.team
|
||||
val others = team?.allPlayers()?.filter { it != player }
|
||||
return others?.getOrNull(slot)
|
||||
}
|
||||
|
||||
fun HealerIfaceMedicHelp(player: Player, other: Player, toggle: Boolean = false) {
|
||||
if (player == other) return
|
||||
|
||||
val team = getBASession(player)?.team ?: return
|
||||
val mySlot = team.slotOf(player)
|
||||
val otherSlot = team.slotOf(other)
|
||||
|
||||
val uiIndex = if (otherSlot > mySlot) otherSlot - 1 else otherSlot
|
||||
if (uiIndex !in HealerIface.team.indices) return
|
||||
|
||||
val slotIface = HealerIface.team[uiIndex]
|
||||
setComponentVisibility(player, HealerIface.ID, slotIface.helpChild, toggle)
|
||||
}
|
||||
fun HealerIfaceHPUpdatePlayer(player:Player, other:Player ){
|
||||
if (player == other) return
|
||||
|
||||
val team = getBASession(player)?.team ?: return
|
||||
val mySlot = team.slotOf(player)
|
||||
val otherSlot = team.slotOf(other)
|
||||
|
||||
val uiIndex = if (otherSlot > mySlot) otherSlot - 1 else otherSlot
|
||||
if (uiIndex !in HealerIface.team.indices) return
|
||||
setHealerTeamIfaceSlot(player,uiIndex)
|
||||
|
||||
}
|
||||
|
||||
object HealerIface {
|
||||
const val ID = Components.BARBASSAULT_OVER_HEAL_488
|
||||
val modelZoom = 2372//1940
|
||||
//these are not the correct models for this Iface, but we could use them
|
||||
val ROLE_MODEL_MAP = mapOf(BarbRole.ATTACKER to 20561, BarbRole.COLLECTOR to 20563, BarbRole.DEFENDER to 20566, BarbRole.HEALER to 20569)
|
||||
data class Slot(val roleChild: Int, val nameChild: Int, val hpChild:Int, val helpChild: Int)
|
||||
val team = listOf(
|
||||
Slot(16, 3, 4, 5),
|
||||
Slot(17, 9, 10, 8),
|
||||
Slot(18, 14, 15, 13),
|
||||
Slot(19, 19, 20, 18))
|
||||
fun formatHp(current: Int?, max: Int?) = "HP $current/$max"
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package content.minigame.barbassault.arena
|
||||
|
||||
|
||||
class WaveCompleteInterface {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[TITLE] bold/ Wave Complete!
|
||||
bold/ Reward:
|
||||
Bold/ The Queen is dead!
|
||||
|
||||
Reward:
|
||||
80 Attacker Points
|
||||
5 Defender Points
|
||||
5 Collector Points
|
||||
5 Healer Points
|
||||
The option to send your points
|
||||
for
|
||||
special armour and gambling
|
||||
options,
|
||||
which you should use before
|
||||
defeating the queen again.
|
||||
|
||||
advance break down -->
|
||||
https://youtu.be/OjkLXOQVWEQ?t=113
|
||||
https://www.youtube.com/watch?v=gpSmUZcaMwY
|
||||
|
||||
//error message if button level up, "Sorry, you don't have enough points to level up
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
package content.minigame.barbassault.arena
|
||||
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
fun getWaveDefinition(index: Int): WaveDefinition {
|
||||
return when (index) {
|
||||
10 -> waves[7]
|
||||
else -> waves[index]
|
||||
}
|
||||
}
|
||||
|
||||
data class WaveDefinition( val caps: SpawnCaps, val npcIds: Map<PenanceType, Int> )
|
||||
enum class PenanceType { HEALER, RUNNER, FIGHTER, RANGER, QUEEN }
|
||||
data class SpawnCaps(var rangers: Int, var fighters: Int, var runners: Int, var healers: Int) {
|
||||
operator fun get(type: PenanceType): Int =
|
||||
when (type) {
|
||||
PenanceType.RANGER -> rangers
|
||||
PenanceType.FIGHTER -> fighters
|
||||
PenanceType.RUNNER -> runners
|
||||
PenanceType.HEALER -> healers
|
||||
else -> {0}
|
||||
}
|
||||
operator fun set(type: PenanceType, value: Int) {
|
||||
when (type) {
|
||||
PenanceType.RANGER -> rangers = value
|
||||
PenanceType.FIGHTER -> fighters = value
|
||||
PenanceType.RUNNER -> runners = value
|
||||
PenanceType.HEALER -> healers = value
|
||||
else -> {0}
|
||||
}
|
||||
}
|
||||
}
|
||||
private val waves = listOf(
|
||||
WaveDefinition( //Wave tut
|
||||
SpawnCaps(rangers = 1, fighters = 1, runners = 1, healers = 1),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5043,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5042,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5040,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5041
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 1
|
||||
SpawnCaps(rangers = 4, fighters = 4, runners = 2, healers = 2),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5238,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5220,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5044,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5229 // missing death animation
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 2
|
||||
SpawnCaps(rangers = 4, fighters = 5, runners = 3, healers = 3),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5239,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5221,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5045,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5230
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 3
|
||||
SpawnCaps(rangers = 6, fighters = 5, runners = 4, healers = 3),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5240,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5222,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5213,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5231
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 4
|
||||
SpawnCaps(rangers = 6, fighters = 6, runners = 4, healers = 4),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5241,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5223,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5214,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5232
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 5
|
||||
SpawnCaps(rangers = 6, fighters = 6, runners = 5, healers = 5),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5242,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5224,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5215,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5233
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 6
|
||||
SpawnCaps(rangers = 7, fighters = 6, runners = 6, healers = 6),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5243,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5225,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5216,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5234
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 7 //Also used in wave 10
|
||||
SpawnCaps(rangers = 7, fighters = 7, runners = 6, healers = 7),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5244,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5226,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5217,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5235
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 8
|
||||
SpawnCaps(rangers = 8, fighters = 7, runners = 7, healers = 7),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5245,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5227,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5218,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5236
|
||||
)
|
||||
),
|
||||
WaveDefinition( //Wave 9
|
||||
SpawnCaps(rangers = 8, fighters = 8, runners = 9, healers = 8),
|
||||
mapOf(
|
||||
PenanceType.HEALER to NPCs.PENANCE_HEALER_5246,
|
||||
PenanceType.RUNNER to NPCs.PENANCE_RUNNER_5228,
|
||||
PenanceType.FIGHTER to NPCs.PENANCE_FIGHTER_5219,
|
||||
PenanceType.RANGER to NPCs.PENANCE_RANGER_5237
|
||||
)
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package content.minigame.barbassault.arena.npcs
|
||||
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
class EggCannonNPC : NPCBehavior(NPCs.EGG_LAUNCHER_5026) {
|
||||
override fun onCreation (self: NPC) {
|
||||
self.isWalks = false
|
||||
self.isNeverWalks = true
|
||||
self.walkRadius = 0
|
||||
self.dropLocation
|
||||
self.definition.combatGraphics[1] = Graphics(866, 25, 0)
|
||||
//5426 = attackanimation
|
||||
self.properties.rangeAnimation = Animation.create(5426)
|
||||
self.definition.combatDistance = 14
|
||||
self.properties.combatPulse.style = CombatStyle.RANGE
|
||||
|
||||
}
|
||||
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun tick(self: NPC): Boolean {
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
fun fireEggAt(target:String,eggColor: String){
|
||||
// RegionManager.getSurroundingNPCs()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package content.minigame.barbassault.arenas.monsters
|
||||
|
||||
import content.minigame.barbassault.arena.BACombatValidation
|
||||
import content.minigame.barbassault.arena.BarbAssEvent
|
||||
import content.minigame.barbassault.arena.PenanceType
|
||||
import content.minigame.barbassault.arena.npcs.dropPenanceEggCluster
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.api.EquipmentSlot
|
||||
import core.api.getItemFromEquipment
|
||||
import core.api.sendMessage
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
val PENANCE_FIGHTER_IDS = listOf(
|
||||
//NPCs.PENANCE_FIGHTER_5040, //tutorial
|
||||
NPCs.PENANCE_FIGHTER_5044,NPCs.PENANCE_FIGHTER_5045,NPCs.PENANCE_FIGHTER_5213,
|
||||
NPCs.PENANCE_FIGHTER_5214,NPCs.PENANCE_FIGHTER_5215,NPCs.PENANCE_FIGHTER_5216,
|
||||
NPCs.PENANCE_FIGHTER_5217,NPCs.PENANCE_FIGHTER_5218,NPCs.PENANCE_FIGHTER_5219)
|
||||
data class PenanceFighterDefinition(val id: Int,val hp: Int,val attack: Int,val strength: Int, val defence: Int, val range: Int, val magic: Int)
|
||||
|
||||
val PENANCE_FIGHTER_DEFINITIONS = listOf(
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5044, 28, 26, 26, 25, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5045, 29, 28, 29, 27, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5213, 32, 33, 32, 34, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5214, 37, 36, 38, 37, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5215, 38, 41, 43, 44, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5216, 49, 50, 48, 48, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5217, 50, 56, 55, 52, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5218, 55, 60, 61, 62, 1, 1),
|
||||
PenanceFighterDefinition(NPCs.PENANCE_FIGHTER_5219, 56, 71, 73, 66, 1, 1),
|
||||
)
|
||||
val PENANCE_FIGHTER_DEFINITIONS_BY_ID = PENANCE_FIGHTER_DEFINITIONS.associateBy { it.id }
|
||||
class PenanceFighterNPC : NPCBehavior(*PENANCE_FIGHTER_IDS.toIntArray()) {
|
||||
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
|
||||
if (attacker is Player && getItemFromEquipment(attacker, EquipmentSlot.CAPE)?.id != 10556) {
|
||||
//todo make list of not allowed weapons to attack IE: Crystal bow, Karils Crossbow
|
||||
sendMessage(attacker,"These Penance are immune to your attacks.")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun beforeDamageReceived(self: NPC, attacker: Entity, state: BattleState) {
|
||||
val player = attacker as? Player ?: return
|
||||
//if (!player.isArtificial) {
|
||||
state.estimatedHit = BACombatValidation.applyAttackValidation(self, player, state)
|
||||
//}
|
||||
}
|
||||
|
||||
override fun tick(self: NPC): Boolean {
|
||||
self.shouldPreventStacking(self)
|
||||
return super.tick(self)
|
||||
}
|
||||
|
||||
override fun onCreation (self: NPC) {
|
||||
self.setAttribute("agg_radius",6)
|
||||
self.isWalks = true
|
||||
self.properties.isNPCWalkable = false
|
||||
self.walkRadius = 24
|
||||
self.isRespawn = false
|
||||
|
||||
self.setAttribute("barbass-type", PenanceType.FIGHTER)
|
||||
|
||||
self.definition.combatDistance = 1
|
||||
self.properties.combatPulse.style = CombatStyle.MELEE
|
||||
self.isAggressive = true
|
||||
|
||||
self.properties.defenceAnimation = Animation(5096)
|
||||
self.properties.attackAnimation = Animation(5097)
|
||||
self.properties.deathAnimation = Animation(5098)
|
||||
self.properties.attackSpeed = 4
|
||||
|
||||
val definition = PENANCE_FIGHTER_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().setStaticLevel(Skills.HITPOINTS, definition.hp)
|
||||
|
||||
}
|
||||
|
||||
override fun onDeathFinished(self: NPC, killer: Entity) {
|
||||
val player = killer as? Player ?: return
|
||||
val session = getBASession(self) ?: return
|
||||
|
||||
dropPenanceEggCluster(killer,self)
|
||||
session.eventBus.emit(BarbAssEvent.NPCDied(self,player))
|
||||
killer.removeAttribute("combat-time")
|
||||
super.onDeathFinished(self, killer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Shrink death 5098
|
||||
//Fighter_Attack_5097
|
||||
//5096 take hit
|
||||
//5095_Move
|
||||
//9094_Idle
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
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.getBASession
|
||||
import core.api.forceWalk
|
||||
import core.api.hasLineOfSight
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.ImpactHandler
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.NPCs
|
||||
import kotlin.math.abs
|
||||
|
||||
val PENANCE_HEALER_IDS = intArrayOf(
|
||||
//NPCs.PENANCE_HEALER_5043,//tut
|
||||
NPCs.PENANCE_HEALER_5238,NPCs.PENANCE_HEALER_5239,NPCs.PENANCE_HEALER_5240,
|
||||
NPCs.PENANCE_HEALER_5241,NPCs.PENANCE_HEALER_5242,NPCs.PENANCE_HEALER_5243,
|
||||
NPCs.PENANCE_HEALER_5244,NPCs.PENANCE_HEALER_5245,NPCs.PENANCE_HEALER_5246
|
||||
)
|
||||
data class PenanceHealerDefinition(val id: Int,val hp: Int,val attack: Int,val strength: Int, val defence: Int, val range: Int, val magic: Int)
|
||||
|
||||
val PENANCE_HEALER_DEFINITIONS = listOf(
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5238, 27, 9, 8, 9, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5239, 32, 13, 15, 14, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5240, 37, 20, 18, 19, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5241, 43, 22, 23, 21, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5242, 49, 26, 27, 25, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5243, 55, 30, 32, 28, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5244, 60, 33, 36, 34, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5245, 67, 40, 38, 36, 1, 1 ),
|
||||
PenanceHealerDefinition(NPCs.PENANCE_HEALER_5246, 76, 40, 44, 38, 1, 1 ),
|
||||
)
|
||||
val PENANCE_HEALER_DEFINITIONS_BY_ID = PENANCE_HEALER_DEFINITIONS.associateBy { it.id }
|
||||
|
||||
class PenanceHealerNPC : NPCBehavior(*PENANCE_HEALER_IDS) {
|
||||
private enum class HealerMode { TARGET_PLAYER, TARGET_RUNNER, WANDER }
|
||||
|
||||
private companion object {
|
||||
const val MODE = "ba-healer:mode"
|
||||
const val TARGET = "ba-healer:target"
|
||||
const val WANDER_TICKS = "ba-healer:wander-ticks"
|
||||
const val WANDER_MOVE_TICKS = "ba-healer:wander-move-ticks"
|
||||
|
||||
const val VISION_RANGE = 15
|
||||
const val WANDER_AFTER_ACTION_TICKS = 4
|
||||
const val WANDER_STEP_TICKS = 5
|
||||
const val PLAYER_POISON_DAMAGE = 2
|
||||
}
|
||||
|
||||
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun onCreation (self: NPC) {
|
||||
self.setAttribute("barbass-type", PenanceType.HEALER)
|
||||
self.setAttribute(MODE, HealerMode.TARGET_PLAYER)
|
||||
self.isWalks = false
|
||||
self.walkRadius = 0
|
||||
self.isRespawn = false
|
||||
|
||||
self.properties.defenceAnimation = Animation(5105)
|
||||
self.properties.deathAnimation = Animation(5106)
|
||||
self.properties.attackAnimation = Animation(5107)
|
||||
|
||||
val definition = PENANCE_HEALER_DEFINITIONS_BY_ID[self.id] ?: return
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
override fun tick(self: NPC): Boolean {
|
||||
val session = self.getAttribute<BarbassaultSession>(BA_SESSION_KEY) ?: return false
|
||||
|
||||
if (!hasLivingRunners(session)) {
|
||||
wander(self)
|
||||
self.shouldPreventStacking(self)
|
||||
return false
|
||||
}
|
||||
|
||||
val wanderTicks = self.getAttribute(WANDER_TICKS, 0)
|
||||
if (wanderTicks > 0) {
|
||||
self.setAttribute(WANDER_TICKS, wanderTicks - 1)
|
||||
wander(self)
|
||||
self.shouldPreventStacking(self)
|
||||
return false
|
||||
}
|
||||
|
||||
when (self.getAttribute(MODE, HealerMode.TARGET_PLAYER)) {
|
||||
HealerMode.TARGET_PLAYER -> tickPlayerTarget(self, session)
|
||||
HealerMode.TARGET_RUNNER -> tickRunnerTarget(self, session)
|
||||
HealerMode.WANDER -> wander(self)
|
||||
}
|
||||
|
||||
self.shouldPreventStacking(self)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun tickPlayerTarget(self: NPC, session: BarbassaultSession) {
|
||||
val target = currentTarget<Player>(self) ?: visiblePlayer(self, session)?.also { setTarget(self, it) }
|
||||
if (target == null || !isValidPlayerTarget(self, target)) {
|
||||
clearTarget(self)
|
||||
wander(self)
|
||||
return
|
||||
}
|
||||
|
||||
if (!isCloseEnough(self, target)) {
|
||||
forceWalk(self, target.location, "DUMB")
|
||||
return
|
||||
}
|
||||
|
||||
self.resetWalk()
|
||||
self.face(target)
|
||||
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, 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
|
||||
}
|
||||
|
||||
if (!isCloseEnough(self, target)) {
|
||||
forceWalk(self, target.location, "DUMB")
|
||||
return
|
||||
}
|
||||
|
||||
self.resetWalk()
|
||||
self.face(target)
|
||||
target.skills.heal(target.skills.maximumLifepoints)
|
||||
clearTarget(self)
|
||||
self.setAttribute(MODE, HealerMode.TARGET_PLAYER)
|
||||
self.setAttribute(WANDER_TICKS, WANDER_AFTER_ACTION_TICKS)
|
||||
}
|
||||
|
||||
private fun visiblePlayer(self: NPC, session: BarbassaultSession): Player? {
|
||||
return session.team.allPlayers()
|
||||
.filter { isValidPlayerTarget(self, it) }
|
||||
.minByOrNull { it.location.getDistance(self.location) }
|
||||
}
|
||||
|
||||
private fun visibleRunner(self: NPC, session: BarbassaultSession): NPC? {
|
||||
return session.sessionNpcs
|
||||
.filter { isValidRunnerTarget(self, it) }
|
||||
.minByOrNull { it.location.getDistance(self.location) }
|
||||
}
|
||||
|
||||
private fun isValidPlayerTarget(self: NPC, player: Player): Boolean {
|
||||
return player.skills.lifepoints > 0 &&
|
||||
tileRadius(self.location, player.location) <= VISION_RANGE &&
|
||||
hasLineOfSight(self, player)
|
||||
}
|
||||
|
||||
private fun isValidRunnerTarget(self: NPC, runner: NPC): Boolean {
|
||||
return runner.getAttribute<PenanceType?>("barbass-type", null) == PenanceType.RUNNER &&
|
||||
runner.skills.lifepoints > 0 &&
|
||||
tileRadius(self.location, runner.location) <= VISION_RANGE &&
|
||||
hasLineOfSight(self, runner)
|
||||
}
|
||||
|
||||
private fun hasLivingRunners(session: BarbassaultSession): Boolean {
|
||||
return session.sessionNpcs.any {
|
||||
it.getAttribute<PenanceType?>("barbass-type", null) == PenanceType.RUNNER &&
|
||||
it.skills.lifepoints > 0
|
||||
}
|
||||
}
|
||||
|
||||
private fun wander(self: NPC) {
|
||||
val moveTicks = self.getAttribute(WANDER_MOVE_TICKS, 0) + 1
|
||||
if (moveTicks < WANDER_STEP_TICKS) {
|
||||
self.setAttribute(WANDER_MOVE_TICKS, moveTicks)
|
||||
return
|
||||
}
|
||||
|
||||
self.setAttribute(WANDER_MOVE_TICKS, 0)
|
||||
val destination = randomWalkableTile(self.location) ?: return
|
||||
forceWalk(self, destination, "DUMB")
|
||||
}
|
||||
|
||||
private fun randomWalkableTile(location: Location): Location? {
|
||||
val options = listOf(
|
||||
location.transform(0, 1, 0),
|
||||
location.transform(1, 0, 0),
|
||||
location.transform(0, -1, 0),
|
||||
location.transform(-1, 0, 0),
|
||||
).filter { RegionManager.isTeleportPermitted(it) }
|
||||
|
||||
return options.randomOrNull()
|
||||
}
|
||||
|
||||
private fun isCloseEnough(self: NPC, target: Entity): Boolean {
|
||||
return self.location == target.location || self.location.isNextTo(target)
|
||||
}
|
||||
|
||||
private fun tileRadius(a: Location, b: Location): Int {
|
||||
return maxOf(abs(a.x - b.x), abs(a.y - b.y))
|
||||
}
|
||||
|
||||
private fun setTarget(self: NPC, target: Entity) {
|
||||
self.setAttribute(TARGET, target)
|
||||
}
|
||||
|
||||
private inline fun <reified T : Entity> currentTarget(self: NPC): T? {
|
||||
return self.getAttribute<Entity?>(TARGET, null) as? T
|
||||
}
|
||||
|
||||
private fun clearTarget(self: NPC) {
|
||||
self.removeAttribute(TARGET)
|
||||
}
|
||||
|
||||
override fun onDeathFinished(self: NPC, killer: Entity) {
|
||||
super.onDeathFinished(self, killer)
|
||||
val player = killer as? Player ?: return
|
||||
val session = getBASession(player) ?: return
|
||||
|
||||
dropPenanceEggCluster(killer,self)
|
||||
session.eventBus.emit(BarbAssEvent.NPCDied(self,player))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Can only heal Penance Runners
|
||||
Can only be Poisoned by Healer roll
|
||||
Poisoned tofu/Poisoned worms/Poisoned meat announced by Defender
|
||||
|
||||
poisoned food will cause a total of 54 damage over time.
|
||||
First spawn = will target visible player then target visible Penance Runner,heal it to full health. repeat
|
||||
No runners = Randomly Roam
|
||||
|
||||
Poisoned tofu = 10539
|
||||
Poisoned worms = 10540
|
||||
Poisoned meat = 10541
|
||||
|
||||
Healer emote:
|
||||
healer_Idle_5104
|
||||
healer_hit_5105
|
||||
healer_Death_5106
|
||||
Healer_attack_5107?
|
||||
*/
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package content.minigame.barbassault.arena.npcs
|
||||
|
||||
|
||||
import content.minigame.barbassault.arena.BAGroundSpawn
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.RegionManager
|
||||
import org.rs09.consts.Items
|
||||
|
||||
/**
|
||||
* Drops a cluster of Penance eggs around a target location in Barbarian Assault.
|
||||
*
|
||||
* Eggs are distributed randomly across a 3x3 area centered on the NPC drop location,
|
||||
* or the killer's location if no NPC is provided.
|
||||
*
|
||||
* @param killer The player who triggered the egg drop (must have a BA session).
|
||||
* @param npc Optional NPC used as the center point for the drop location.
|
||||
*/
|
||||
fun dropPenanceEggCluster(killer: Player, npc: NPC? = null) {
|
||||
val center = npc?.dropLocation ?: killer.location
|
||||
val tiles = center.get3x3Tiles().shuffled()
|
||||
val session = getBASession(killer) ?: return
|
||||
|
||||
val eggs = listOf( Items.RED_EGG_10532, Items.RED_EGG_10532,
|
||||
Items.BLUE_EGG_10533, Items.BLUE_EGG_10533,
|
||||
Items.GREEN_EGG_10531, Items.GREEN_EGG_10531)
|
||||
|
||||
for (i in eggs.indices) {
|
||||
val tile = tiles[i]
|
||||
val thisGroundItem = BAGroundSpawn(session,60,Item(eggs[i],1),tile)
|
||||
thisGroundItem.init()
|
||||
}
|
||||
}
|
||||
|
||||
//GroundItemManager.create(Item(eggs[i], 1), tile).apply { forceVisible = true }
|
||||
// GroundItemManager.create(Item(Items.RED_EGG_10532, 1), tile).apply { forceVisible = true }
|
||||
// GroundItemManager.create(Item(eggs[i], 1), tile, null)
|
||||
|
||||
/**
|
||||
* Finds the closest visible player to the given NPC within a specified range.
|
||||
*
|
||||
* @param npc The NPC used as the search origin.
|
||||
* @param range Maximum distance to search for players.
|
||||
* @return The closest valid Player, or null if none are found.
|
||||
*/
|
||||
fun findClosestPlayerFromNPC(npc: NPC,range:Int = 14): Player? {
|
||||
var closest: Player? = null
|
||||
var bestDistance = Double.MAX_VALUE
|
||||
|
||||
for (player in RegionManager.getLocalPlayers(npc, range)) {
|
||||
if (player.isInvisible) continue
|
||||
|
||||
val dist = npc.location.getDistance(player.location)
|
||||
if (dist < bestDistance) {
|
||||
bestDistance = dist
|
||||
closest = player
|
||||
}
|
||||
}
|
||||
return closest
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the closest NPC matching the given target NPC within a range,
|
||||
*
|
||||
* @param targetNPC The specific NPC being searched for.
|
||||
* @param npc The source NPC performing the search.
|
||||
* @param range Maximum search radius.
|
||||
* @return The closest matching NPC if found and visible, otherwise null.
|
||||
*/
|
||||
fun findClosestTargetNPCIDFromNPC(targetNPC: Int?, npc: NPC, range: Int = 14): NPC? {
|
||||
var closest: NPC? = null
|
||||
var bestDistance = Double.MAX_VALUE
|
||||
|
||||
for (foundNpc in RegionManager.getLocalNpcs(npc, range)) {
|
||||
if (targetNPC != foundNpc.id) continue
|
||||
|
||||
val dist = npc.location.getDistance(foundNpc.location)
|
||||
if (dist < bestDistance) {
|
||||
bestDistance = dist
|
||||
closest = foundNpc
|
||||
}
|
||||
}
|
||||
return closest
|
||||
}
|
||||
/**
|
||||
* Finds the closest NPC to the given player within a specified range
|
||||
* that matches the provided NPC ID.
|
||||
*
|
||||
* @param player The player used as the search origin.
|
||||
* @param npcId The ID of the NPC to search for.
|
||||
* @param range Maximum distance to search for NPCs.
|
||||
* @return The closest matching NPC, or null if none are found.
|
||||
*/
|
||||
fun findClosestNPCIDFromPlayer(player: Player, targetNPC: Int, range: Int = 14): NPC? {
|
||||
var closest: NPC? = null
|
||||
var bestDistance = Double.MAX_VALUE
|
||||
|
||||
for (npc in RegionManager.getLocalNpcs(player, range)) {
|
||||
if (npc.id != targetNPC) continue
|
||||
|
||||
val dist = player.location.getDistance(npc.location)
|
||||
if (dist < bestDistance) {
|
||||
bestDistance = dist
|
||||
closest = npc
|
||||
}
|
||||
}
|
||||
return closest
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package content.minigame.barbassault.arena.npcs
|
||||
|
||||
import core.api.sendMessage
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
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
|
||||
|
||||
//.configureBossData()
|
||||
class PenanceQueenNPC : NPCBehavior(NPCs.PENANCE_QUEEN_5247){
|
||||
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
|
||||
if (attacker is Player ) {
|
||||
sendMessage(attacker,"Only an Omega Egg can hurt the queen!")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
queen emote:
|
||||
queen_hit_5408+
|
||||
queen_move_5409
|
||||
queen_Idle_5410
|
||||
queen_attack_5411
|
||||
queen_Death_5412
|
||||
queen_attack2_5413
|
||||
queen_Spawnin_5414
|
||||
*/
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package content.minigame.barbassault.arena.npcs
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BarbAssEvent
|
||||
import content.minigame.barbassault.arena.BACombatValidation
|
||||
import content.minigame.barbassault.arena.PenanceType
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.api.*
|
||||
import core.api.getItemFromEquipment
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.combat.BattleState
|
||||
import core.game.node.entity.combat.CombatStyle
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import org.rs09.consts.NPCs
|
||||
//20730 = rangers cast
|
||||
val PENANCE_RANGER_IDS = listOf(
|
||||
// NPCs.PENANCE_RANGER_5041, // tut
|
||||
NPCs.PENANCE_RANGER_5229,NPCs.PENANCE_RANGER_5230,NPCs.PENANCE_RANGER_5231,
|
||||
NPCs.PENANCE_RANGER_5232,NPCs.PENANCE_RANGER_5233,NPCs.PENANCE_RANGER_5234,
|
||||
NPCs.PENANCE_RANGER_5235,NPCs.PENANCE_RANGER_5236,NPCs.PENANCE_RANGER_5237
|
||||
)
|
||||
data class PenanceRangerDefinition(val id: Int,val hp: Int,val attack: Int,val strength: Int, val defence: Int, val range: Int, val magic: Int)
|
||||
|
||||
val PENANCE_RANGER_DEFINITIONS = listOf(
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5229, 20, 22, 1, 21, 23, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5230, 28, 27, 1, 29, 24, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5231, 29, 32, 1, 33, 34, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5232, 34, 41, 1, 42, 40, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5233, 41, 44, 1, 46, 45, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5234, 50, 51, 1, 54, 52, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5235, 50, 63, 1, 61, 62, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5236, 54, 69, 1, 68, 70, 1),
|
||||
PenanceRangerDefinition(NPCs.PENANCE_RANGER_5237, 58, 79, 1, 80, 78, 1),
|
||||
)
|
||||
val PENANCE_RANGER_DEFINITIONS_BY_ID = PENANCE_RANGER_DEFINITIONS.associateBy { it.id }
|
||||
|
||||
class PenanceRangerNPC : NPCBehavior(*PENANCE_RANGER_IDS.toIntArray()) {
|
||||
override fun canBeAttackedBy(self: NPC, attacker: Entity, style: CombatStyle, shouldSendMessage: Boolean): Boolean {
|
||||
if (attacker is Player && getItemFromEquipment(attacker, EquipmentSlot.CAPE)?.id != 10556) {
|
||||
//todo make list of not allowed weapons to attack IE: Crystal bow, Karils Crossbow
|
||||
sendMessage(attacker, "These Penance are immune to your attacks.")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
override fun beforeDamageReceived( self: NPC, attacker: Entity, state: BattleState) {
|
||||
attacker as Player
|
||||
// if(!attacker.isArtificial) {
|
||||
state.estimatedHit = BACombatValidation.applyAttackValidation( self, attacker, state )
|
||||
// }
|
||||
}
|
||||
|
||||
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
|
||||
return 0.0
|
||||
}
|
||||
override fun onCreation (self: NPC) {
|
||||
self.setAttribute("agg_radius",6)
|
||||
self.isWalks = true
|
||||
self.isNeverWalks = false
|
||||
self.walkRadius = 24
|
||||
self.isRespawn = false
|
||||
self.definition.combatGraphics[1] = Graphics(866, 25, 0)
|
||||
self.setAttribute("barbass-type", PenanceType.RANGER)
|
||||
|
||||
|
||||
self.definition.combatDistance = 8
|
||||
self.properties.combatPulse.style = CombatStyle.RANGE
|
||||
self.isAggressive = true
|
||||
|
||||
self.properties.defenceAnimation = Animation(5396)
|
||||
self.properties.attackAnimation = Animation(5395)
|
||||
self.properties.rangeAnimation = Animation(5395)
|
||||
self.properties.deathAnimation = Animation(5397)
|
||||
self.properties.attackSpeed = 4
|
||||
val definition = PENANCE_RANGER_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().setStaticLevel(Skills.HITPOINTS, definition.hp)
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onDeathFinished(self: NPC, killer: Entity) {
|
||||
super.onDeathFinished(self, killer)
|
||||
val player = killer as? Player ?: return
|
||||
val session = getBASession(killer) ?: return
|
||||
killer.removeAttribute("combat-time")
|
||||
dropPenanceEggCluster(killer,self)
|
||||
session.eventBus.emit(BarbAssEvent.NPCDied(self,player))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Combat-style/arrow-type/magic-spell announced by Collector
|
||||
* Controlled/Bullet/Wind
|
||||
* Accurate/Field/Water
|
||||
* Aggressive/Blunt/Earth
|
||||
* Defensive/Barbed/Fire
|
||||
* Poisons (from both weapons and green eggs)
|
||||
* Egg fired from the Egg Launcher
|
||||
* Recoil damage from any player
|
||||
*/
|
||||
|
|
@ -0,0 +1,374 @@
|
|||
package content.minigame.barbassault.arena.npcs
|
||||
|
||||
import content.minigame.barbassault.BA_SESSION_KEY
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.LureItems
|
||||
import content.minigame.barbassault.getBALevels
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import org.rs09.consts.NPCs
|
||||
import content.minigame.barbassault.arena.*
|
||||
import content.minigame.barbassault.arena.scenery.DefenderTrap
|
||||
import content.minigame.barbassault.getBASession
|
||||
|
||||
import core.api.forceWalk
|
||||
import core.api.hasLineOfSight
|
||||
import core.api.sendChat
|
||||
import core.game.node.item.GroundItemManager
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
val PENANCE_RUNNER_IDS = listOf(
|
||||
//NPCs.PENANCE_RUNNER_5042,//tut
|
||||
NPCs.PENANCE_RUNNER_5220,
|
||||
NPCs.PENANCE_RUNNER_5221,
|
||||
NPCs.PENANCE_RUNNER_5222,
|
||||
NPCs.PENANCE_RUNNER_5223,
|
||||
NPCs.PENANCE_RUNNER_5224,
|
||||
NPCs.PENANCE_RUNNER_5225,
|
||||
NPCs.PENANCE_RUNNER_5226,
|
||||
NPCs.PENANCE_RUNNER_5227,
|
||||
NPCs.PENANCE_RUNNER_5228,
|
||||
)
|
||||
class PenanceRunnerNPC : NPCBehavior(*PENANCE_RUNNER_IDS.toIntArray()) {
|
||||
val GOOD_EAT = "Chomp, chomp"
|
||||
val BAD_EAT = "Blurghh"
|
||||
val TRAP_HIT = "Urghhh!"
|
||||
val ESCAPE = "Raaa!!"
|
||||
private val defenderTrap = DefenderTrap()
|
||||
|
||||
private enum class RunnerMode { RANDOM_WALKING, HUNTING }
|
||||
|
||||
private companion object {
|
||||
const val MODE = "ba-runner:mode"
|
||||
const val MODE_TICKS = "ba-runner:mode-ticks"
|
||||
const val HUNT_TICKS = "ba-runner:hunt-ticks"
|
||||
const val TARGET = "ba-runner:target"
|
||||
const val TARGET_CYCLES = "ba-runner:target-cycles"
|
||||
const val TARGET_LAST_LOC = "ba-runner:target-last-loc"
|
||||
const val SKIP_NEXT_HUNT = "ba-runner:skip-next-hunt"
|
||||
const val BAD_FOOD_WALK_TICKS = "ba-runner:bad-food-walk-ticks"
|
||||
const val EAT_PAUSE_TICKS = "ba-runner:eat-pause-ticks"
|
||||
const val ESCAPE_REMOVE_TICKS = "ba-runner:escape-remove-ticks"
|
||||
|
||||
val HUNT_ZONE_ORDER = (0 downTo -5).flatMap { x ->
|
||||
(0 downTo -5).map { y -> x to y }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
|
||||
return 0.0
|
||||
}
|
||||
override fun onCreation(self: NPC) {
|
||||
self.isRespawn = false
|
||||
self.isWalks = false
|
||||
self.walkRadius = 0
|
||||
self.destinationFlag
|
||||
|
||||
self.setAttribute("barbass-type", PenanceType.RUNNER)
|
||||
self.setAttribute(MODE, RunnerMode.RANDOM_WALKING)
|
||||
self.setAttribute(MODE_TICKS, (0..4).random())
|
||||
self.setAttribute(HUNT_TICKS, (0..2).random())
|
||||
|
||||
self.properties.defenceAnimation = Animation(5101)
|
||||
self.properties.deathAnimation = Animation(5106)
|
||||
|
||||
self.getSkills().setStaticLevel(Skills.HITPOINTS, 5)
|
||||
}
|
||||
|
||||
override fun tick(self: NPC): Boolean {
|
||||
val session = self.getAttribute<BarbassaultSession>(BA_SESSION_KEY) ?: return false
|
||||
|
||||
if (defenderTrap.tryTriggerTrap(self)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val escapeRemoveTicks = self.getAttribute(ESCAPE_REMOVE_TICKS, 0)
|
||||
if (escapeRemoveTicks > 0) {
|
||||
self.setAttribute(ESCAPE_REMOVE_TICKS, escapeRemoveTicks - 1)
|
||||
self.resetWalk()
|
||||
if (escapeRemoveTicks <= 1) {
|
||||
session.runnerEscaped(self)
|
||||
resetAfterEscape(self)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if (isAtEscapeTunnel(session, self.location)) {
|
||||
beginEscape(self)
|
||||
return false
|
||||
}
|
||||
|
||||
val eatPauseTicks = self.getAttribute(EAT_PAUSE_TICKS, 0)
|
||||
if (eatPauseTicks > 0) {
|
||||
self.setAttribute(EAT_PAUSE_TICKS, eatPauseTicks - 1)
|
||||
self.resetWalk()
|
||||
self.shouldPreventStacking(self)
|
||||
return false
|
||||
}
|
||||
|
||||
val modeChanged = tickModeTimer(self)
|
||||
tickHuntTimer(self, session)
|
||||
|
||||
val badWalkTicks = self.getAttribute(BAD_FOOD_WALK_TICKS, 0)
|
||||
if (badWalkTicks > 0) {
|
||||
self.setAttribute(BAD_FOOD_WALK_TICKS, badWalkTicks - 1)
|
||||
walkAfterBadFood(self, session)
|
||||
self.shouldPreventStacking(self)
|
||||
return false
|
||||
}
|
||||
|
||||
val target = self.getAttribute<BAGroundSpawn?>(TARGET, null)
|
||||
if (target != null) {
|
||||
chaseFood(self, session, target)
|
||||
} else if (modeChanged && self.getAttribute(MODE, RunnerMode.RANDOM_WALKING) == RunnerMode.RANDOM_WALKING) {
|
||||
randomWalk(self, session)
|
||||
}
|
||||
|
||||
self.shouldPreventStacking(self)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun tickModeTimer(self: NPC): Boolean {
|
||||
val modeTicks = self.getAttribute(MODE_TICKS, 0) + 1
|
||||
if (modeTicks < 5) {
|
||||
self.setAttribute(MODE_TICKS, modeTicks)
|
||||
return false
|
||||
}
|
||||
|
||||
self.setAttribute(MODE_TICKS, 0)
|
||||
val nextMode = when (self.getAttribute(MODE, RunnerMode.RANDOM_WALKING)) {
|
||||
RunnerMode.RANDOM_WALKING -> RunnerMode.HUNTING
|
||||
RunnerMode.HUNTING -> RunnerMode.RANDOM_WALKING
|
||||
}
|
||||
|
||||
self.setAttribute(MODE, nextMode)
|
||||
if (nextMode == RunnerMode.HUNTING) {
|
||||
val targetCycles = self.getAttribute(TARGET_CYCLES, 0) + 1
|
||||
self.setAttribute(TARGET_CYCLES, targetCycles)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun tickHuntTimer(self: NPC, session: BarbassaultSession) {
|
||||
if (self.getAttribute(MODE, RunnerMode.RANDOM_WALKING) != RunnerMode.HUNTING) {
|
||||
return
|
||||
}
|
||||
|
||||
val huntTicks = self.getAttribute(HUNT_TICKS, 0) + 1
|
||||
if (huntTicks < 3) {
|
||||
self.setAttribute(HUNT_TICKS, huntTicks)
|
||||
return
|
||||
}
|
||||
|
||||
self.setAttribute(HUNT_TICKS, 0)
|
||||
if (self.getAttribute(SKIP_NEXT_HUNT, false)) {
|
||||
self.setAttribute(SKIP_NEXT_HUNT, false)
|
||||
clearTarget(self)
|
||||
return
|
||||
}
|
||||
|
||||
val currentTarget = self.getAttribute<BAGroundSpawn?>(TARGET, null)
|
||||
if (currentTarget != null && self.getAttribute(TARGET_CYCLES, 0) < 2 && isFoodStillActive(session, currentTarget)) {
|
||||
return
|
||||
}
|
||||
|
||||
selectFood(self, session)?.let { food ->
|
||||
self.setAttribute(TARGET, food)
|
||||
self.setAttribute(TARGET_CYCLES, 0)
|
||||
self.setAttribute(TARGET_LAST_LOC, food.location)
|
||||
}
|
||||
}
|
||||
|
||||
private fun chaseFood(self: NPC, session: BarbassaultSession, food: BAGroundSpawn) {
|
||||
val foodLocation = food.location
|
||||
if (!isFoodStillActive(session, food)) {
|
||||
clearTarget(self)
|
||||
forceWalk(self, foodLocation, "DUMB")
|
||||
return
|
||||
}
|
||||
|
||||
if (self.location == foodLocation) {
|
||||
eatFood(self, session, food)
|
||||
return
|
||||
}
|
||||
|
||||
val occupied = RegionManager.getLocalEntitys(foodLocation, 0).any { it != self && it.location == foodLocation }
|
||||
if (occupied) {
|
||||
if (!foodLocation.isNextTo(self)) {
|
||||
val adjacent = foodLocation.cardinalTiles
|
||||
.filter { RegionManager.isTeleportPermitted(it) }
|
||||
.minByOrNull { it.getDistance(self.location) }
|
||||
if (adjacent != null) {
|
||||
forceWalk(self, adjacent, "DUMB")
|
||||
}
|
||||
} else {
|
||||
self.resetWalk()
|
||||
}
|
||||
self.faceLocation(foodLocation)
|
||||
return
|
||||
}
|
||||
|
||||
forceWalk(self, foodLocation, "DUMB")
|
||||
}
|
||||
|
||||
private fun eatFood(self: NPC, session: BarbassaultSession, food: BAGroundSpawn) {
|
||||
val goodFood = food.flag == true
|
||||
sendChat(self, if (goodFood) GOOD_EAT else BAD_EAT)
|
||||
session.destroyGroundItem(food)
|
||||
clearTarget(self)
|
||||
self.resetWalk()
|
||||
|
||||
if (goodFood) {
|
||||
self.setAttribute(EAT_PAUSE_TICKS, 5)
|
||||
if (self.getAttribute(MODE, RunnerMode.RANDOM_WALKING) == RunnerMode.HUNTING) {
|
||||
self.setAttribute(MODE, RunnerMode.RANDOM_WALKING)
|
||||
self.setAttribute(MODE_TICKS, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
self.setAttribute(SKIP_NEXT_HUNT, true)
|
||||
self.setAttribute(BAD_FOOD_WALK_TICKS, 5)
|
||||
walkAfterBadFood(self, session)
|
||||
}
|
||||
|
||||
private fun selectFood(self: NPC, session: BarbassaultSession): BAGroundSpawn? {
|
||||
val radius = lureRadius(session)
|
||||
val allVisibleFood = session.BAgroundItems
|
||||
.filter { isFoodStillActive(session, it) }
|
||||
.filter { it.id in LureItems }
|
||||
.filter { hasLineOfSight(self, it) }
|
||||
|
||||
if (allVisibleFood.none { tileRadius(self.location, it.location) <= radius }) {
|
||||
return null
|
||||
}
|
||||
|
||||
for (zone in HUNT_ZONE_ORDER) {
|
||||
val food = allVisibleFood.lastOrNull { zoneFor(session, it.location) == zone }
|
||||
if (food != null) {
|
||||
return food
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun randomWalk(self: NPC, session: BarbassaultSession) {
|
||||
val location = self.location
|
||||
val destination = if (isAtSouthernWall(session, location)) {
|
||||
furthestWalkableStraight(location, 0, -1, 5) ?: escapeLocation(session)
|
||||
} else {
|
||||
when ((0..5).random()) {
|
||||
0 -> furthestWalkableStraight(location, -1, 0, 5)
|
||||
1 -> furthestWalkableStraight(location, 1, 0, 5)
|
||||
else -> furthestWalkableStraight(location, 0, -1, 5)
|
||||
}
|
||||
} ?: return
|
||||
|
||||
forceWalk(self, destination, "DUMB")
|
||||
}
|
||||
|
||||
private fun walkAfterBadFood(self: NPC, session: BarbassaultSession) {
|
||||
val directionY = if (self.location.y >= session.base.y + 42) -1 else 1
|
||||
val destination = furthestWalkableStraight(self.location, 0, directionY, 5) ?: return
|
||||
forceWalk(self, destination, "DUMB")
|
||||
}
|
||||
|
||||
private fun lureRadius(session: BarbassaultSession): Int {
|
||||
return if (session.team.getPlayersByRole(BarbRole.DEFENDER).any { getBALevels(it).def >= 2 }) 5 else 4
|
||||
}
|
||||
|
||||
private fun isFoodStillActive(session: BarbassaultSession, food: BAGroundSpawn): Boolean {
|
||||
return food.isActive && !food.isRemoved && session.BAgroundItems.contains(food) && GroundItemManager.getItems().contains(food)
|
||||
}
|
||||
|
||||
private fun clearTarget(self: NPC) {
|
||||
self.removeAttribute(TARGET)
|
||||
self.removeAttribute(TARGET_CYCLES)
|
||||
self.removeAttribute(TARGET_LAST_LOC)
|
||||
}
|
||||
|
||||
private fun zoneFor(session: BarbassaultSession, location: Location): Pair<Int, Int> {
|
||||
val relativeX = location.x - session.base.x
|
||||
val relativeY = location.y - session.base.y
|
||||
return Math.floorDiv(relativeX - 40, 8) to Math.floorDiv(relativeY - 40, 8)
|
||||
}
|
||||
|
||||
private fun tileRadius(a: Location, b: Location): Int {
|
||||
return max(abs(a.x - b.x), abs(a.y - b.y))
|
||||
}
|
||||
|
||||
private fun furthestWalkableStraight(start: Location, dx: Int, dy: Int, maxSteps: Int): Location? {
|
||||
var destination: Location? = null
|
||||
for (step in 1..maxSteps) {
|
||||
val next = start.transform(dx * step, dy * step, 0)
|
||||
if (!RegionManager.isTeleportPermitted(next)) {
|
||||
break
|
||||
}
|
||||
destination = next
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
private fun isAtSouthernWall(session: BarbassaultSession, location: Location): Boolean {
|
||||
return location.y <= session.base.y + 16
|
||||
}
|
||||
|
||||
private fun isAtEscapeTunnel(session: BarbassaultSession, location: Location): Boolean {
|
||||
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) {
|
||||
sendChat(self, ESCAPE)
|
||||
clearTarget(self)
|
||||
self.resetWalk()
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onDeathFinished(self: NPC, killer: Entity) {
|
||||
super.onDeathFinished(self, killer)
|
||||
val player = killer as? Player ?: return
|
||||
val session = getBASession(player) ?: return
|
||||
|
||||
dropPenanceEggCluster(killer,self)
|
||||
session.eventBus.emit(BarbAssEvent.NPCDied(self,player))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//good food dropped stays "good"
|
||||
//bad food dropped stays bad
|
||||
/*
|
||||
Runner emote
|
||||
Runner_death_5103
|
||||
Runner_trap_Death_ 5102
|
||||
runner_hit_5101
|
||||
runner_Move_5100
|
||||
runner_Idle 5099
|
||||
*/
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package content.minigame.barbassault.arena.npcs
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.npc.NPCBehavior
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
class PenanceSpawnNPC : NPCBehavior(NPCs.QUEEN_SPAWN_5248) {
|
||||
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
package content.minigame.barbassault.arena.scenery
|
||||
|
||||
import content.minigame.barbassault.LureItems
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BAGroundSpawn
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.npcs.PENANCE_RUNNER_IDS
|
||||
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
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
|
||||
// RUNNER_TRAP2_20135
|
||||
// RUNNER_TRAP1_20230
|
||||
// BROKEN_TRAP0_20231
|
||||
//Trap East Location.create(1901, 5474, 0)
|
||||
//trap west Location.create(1871, 5473, 0)
|
||||
|
||||
//emote 5365 maybe
|
||||
//emote 5416 long
|
||||
//emote 5416 long
|
||||
//emote 5417 block wall
|
||||
|
||||
//trap only kills if Runner eats GOOD bait.
|
||||
//If runner eats bad bait they escape
|
||||
class DefenderTrap : MapArea {
|
||||
val GOOD_EAT = "Chomp, chomp"
|
||||
val BAD_EAT = "Blurghh"
|
||||
val TRAP_HIT = "Urghhh!"
|
||||
val TRAP_EAST = Location.create(1901, 5474, 0)
|
||||
val TRAP_WEST = Location.create(1871, 5473, 0)
|
||||
val TRAP_EAST_ZONE: ZoneBorders = zoneFrom3x3(TRAP_EAST)
|
||||
val TRAP_WEST_ZONE: ZoneBorders = zoneFrom3x3(TRAP_WEST)
|
||||
val TRAPS_ZONE = arrayOf(TRAP_EAST_ZONE,TRAP_WEST_ZONE)
|
||||
val Fix_trap_IDs = intArrayOf( Scenery.RUNNER_TRAP1_20230, Scenery.BROKEN_TRAP0_20231 )
|
||||
val TRAPS = arrayOf(TRAP_WEST,TRAP_EAST)
|
||||
val TRAP_EAST_OFFSET = Location.create(45, 34, 0)
|
||||
val TRAP_WEST_OFFSET = Location.create(15, 33, 0)
|
||||
val playersInArea = mutableListOf<Player>()
|
||||
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> {
|
||||
return TRAPS_ZONE
|
||||
}
|
||||
|
||||
private fun zoneFrom3x3(center: Location): ZoneBorders {
|
||||
val tiles = center.get3x3Tiles()
|
||||
return ZoneBorders(
|
||||
tiles.minOf { it.x },
|
||||
tiles.minOf { it.y },
|
||||
tiles.maxOf { it.x },
|
||||
tiles.maxOf { it.y },
|
||||
center.z
|
||||
)
|
||||
}
|
||||
|
||||
override fun areaEnter(entity: Entity) {
|
||||
if (PENANCE_RUNNER_IDS.contains(entity.id)) {
|
||||
tryTriggerTrap(entity)
|
||||
}
|
||||
|
||||
val player = entity as? Player ?: return
|
||||
playersInArea.add(player)
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun areaLeave(entity: Entity, logout: Boolean) {
|
||||
val player = entity as? Player ?: return
|
||||
playersInArea.remove(player)
|
||||
}
|
||||
|
||||
fun tryTriggerTrap(entity: Entity): Boolean {
|
||||
if (DeathTask.isDead(entity)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val session = getBASession(entity) ?: return false
|
||||
val trapLocation = trapLocationFor(session, entity.location) ?: return false
|
||||
val scenery = getScenery(trapLocation) ?: return false
|
||||
if (scenery.id != Scenery.RUNNER_TRAP2_20135 && scenery.id != Scenery.RUNNER_TRAP1_20230) {
|
||||
return false
|
||||
}
|
||||
|
||||
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)}!")
|
||||
sendMessageArea()
|
||||
return true
|
||||
}
|
||||
|
||||
fun killRunner(entity: Entity){
|
||||
entity.sendChat(TRAP_HIT)
|
||||
entity.startDeath(entity)
|
||||
}
|
||||
|
||||
|
||||
//step on to trap area, if good food "chomp chomp" stay in location
|
||||
//set trap off
|
||||
|
||||
fun updateTrap(scenery: core.game.node.scenery.Scenery, trapLocation: Location) {
|
||||
val nextTrap = when (scenery.id) {
|
||||
Scenery.RUNNER_TRAP2_20135 -> Scenery.RUNNER_TRAP1_20230
|
||||
Scenery.RUNNER_TRAP1_20230 -> Scenery.BROKEN_TRAP0_20231
|
||||
else -> return
|
||||
}
|
||||
|
||||
animateScenery(scenery, 5076)//5076
|
||||
GameWorld.Pulser.submit(object : Pulse(3, scenery) {
|
||||
override fun pulse(): Boolean {
|
||||
replaceScenery(scenery, nextTrap, -1, trapLocation)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun goodTrapBait(session: BarbassaultSession, trapLocation: Location): BAGroundSpawn? {
|
||||
val trapTiles = trapLocation.get3x3Tiles()
|
||||
return session.BAgroundItems.firstOrNull {
|
||||
it.isActive &&
|
||||
!it.isRemoved &&
|
||||
it.id in LureItems &&
|
||||
it.flag == true &&
|
||||
trapTiles.contains(it.location)
|
||||
}
|
||||
}
|
||||
|
||||
private fun trapLocationFor(session: BarbassaultSession, location: Location): Location? {
|
||||
return listOf(
|
||||
session.base.transform(TRAP_EAST_OFFSET),
|
||||
session.base.transform(TRAP_WEST_OFFSET)
|
||||
).firstOrNull { trapLocation -> trapLocation.get3x3Tiles().contains(location) }
|
||||
}
|
||||
|
||||
private fun trapDirectionFor(session: BarbassaultSession, trapLocation: Location): String {
|
||||
return if (trapLocation == session.base.transform(TRAP_EAST_OFFSET)) "east" else "west"
|
||||
}
|
||||
|
||||
|
||||
fun sendMessageArea(){
|
||||
playersInArea.forEach { player ->
|
||||
sendMessage(player,"Entered Trap Area")
|
||||
}
|
||||
}
|
||||
}
|
||||
//player.baSession.broadcastToRole("A Penance Runner broke a trap to the east/west!")
|
||||
//sendMessage(player,"A Penance Runner broke a trap to the east/west!") //When a runner dies to trap announce to Defenders
|
||||
//replaceScenery()
|
||||
//animateScenery
|
||||
//5076
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
package content.minigame.barbassault.arena.scenery
|
||||
|
||||
import content.minigame.barbassault.BAGraphics.Blue_EGG_PROJECTILE_978
|
||||
import content.minigame.barbassault.BAGraphics.GREEN_EGG_PROJECTILE_977
|
||||
import content.minigame.barbassault.BAGraphics.RED_EGG_PROJECTILE_978
|
||||
import content.minigame.barbassault.BAGraphics.YELLOW_EGG_PROJECTILE_980
|
||||
import content.minigame.barbassault.BarbRole
|
||||
|
||||
import content.minigame.barbassault.arena.npcs.findClosestNPCIDFromPlayer
|
||||
import content.minigame.barbassault.arena.npcs.findClosestTargetNPCIDFromNPC
|
||||
import content.minigame.barbassault.arena.PenanceType
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.api.*
|
||||
import core.game.component.CloseEvent
|
||||
import core.game.component.Component
|
||||
import core.game.component.ComponentDefinition
|
||||
import core.game.component.ComponentPlugin
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import getCollectorBag
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
|
||||
//Egg hoppper scenrey item updates based on eggs in hopper
|
||||
// empty -> EGG_HOPPER_20264
|
||||
// half -> EGG_HOPPER_20265
|
||||
// full -> EGG_HOPPER_20266
|
||||
//varbit 3268
|
||||
|
||||
@Initializable
|
||||
class EggCannon : ComponentPlugin() {
|
||||
|
||||
//Easter Egg "Blinky Switch"
|
||||
private val currentSequence = mutableListOf<Int>()
|
||||
private val easterEggSequence = listOf(56, 38, 26, 26, 56, 56)
|
||||
fun checkEasterEgg(player: Player,button: Int) {
|
||||
currentSequence.add(button)
|
||||
// println("Current sequence: $currentSequence + $button")
|
||||
while(currentSequence.size > easterEggSequence.size) {
|
||||
currentSequence.removeAt(0)
|
||||
}
|
||||
if(currentSequence.takeLast(easterEggSequence.size) == easterEggSequence) {
|
||||
sendMessage(player, "[BlickySwitch] Activated!")
|
||||
currentSequence.clear()
|
||||
if (player.isAdmin) { //ADMIN ONLY!
|
||||
val eggHopper = getBASession(player)?.eggHopper
|
||||
eggHopper?.green = 99
|
||||
eggHopper?.red = 99
|
||||
eggHopper?.blue = 99
|
||||
updateCannonUI(player)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
//END BINKY//
|
||||
data class EggHopper(var red: Int = 0, var blue: Int = 0, var green: Int = 0, var yellow: Int = 0 ){
|
||||
private val maxPerColor = 5
|
||||
val eggColorMap = mapOf(Items.GREEN_EGG_10531 to "green",Items.RED_EGG_10532 to "red",Items.BLUE_EGG_10533 to "blue",Items.OMEGA_EGG_10537 to "yellow" )
|
||||
fun totalCount(): Int = red + blue + green + yellow
|
||||
fun addEggs(redToAdd: Int = 0, blueToAdd: Int = 0, greenToAdd: Int = 0, yellowToAdd: Int = 0): Map<String, Int> {
|
||||
val added = mutableMapOf<String, Int>()
|
||||
val newRed = (red + redToAdd).coerceAtMost(maxPerColor)
|
||||
added["red"] = newRed - red
|
||||
red = newRed
|
||||
|
||||
val newBlue = (blue + blueToAdd).coerceAtMost(maxPerColor)
|
||||
added["blue"] = newBlue - blue
|
||||
blue = newBlue
|
||||
|
||||
val newGreen = (green + greenToAdd).coerceAtMost(maxPerColor)
|
||||
added["green"] = newGreen - green
|
||||
green = newGreen
|
||||
|
||||
val newYellow = (yellow + yellowToAdd).coerceAtMost(maxPerColor)
|
||||
added["yellow"] = newYellow - yellow
|
||||
yellow = newYellow
|
||||
|
||||
return added
|
||||
}
|
||||
fun addEgg(itemId: Int,count: Int = 0): Map<String, Int> {
|
||||
return when (eggColorMap[itemId]) {
|
||||
"red" -> addEggs(redToAdd = count)
|
||||
"blue" -> addEggs(blueToAdd = count)
|
||||
"green" -> addEggs(greenToAdd = count)
|
||||
"yellow" -> addEggs(yellowToAdd = count)
|
||||
else -> emptyMap()
|
||||
}
|
||||
}
|
||||
fun consumeGreen(): Boolean { if (green <= 0) return false; green--; return true }
|
||||
fun consumeRed(): Boolean { if (red <= 0) return false; red--; return true }
|
||||
fun consumeBlue(): Boolean { if (blue <= 0) return false; blue--; return true }
|
||||
fun consumeYellow(): Boolean { if (yellow <= 0) return false; yellow--; return true }
|
||||
}
|
||||
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
ComponentDefinition.forId(EggTurret.ID).plugin = this
|
||||
ComponentDefinition.forId(EggTurret.ID).isWalkable = false;
|
||||
return this
|
||||
}
|
||||
///stun(entity: Entity, ticks: Int)
|
||||
// stunned monster cant take damage here?
|
||||
///isStunned(entity: Entity)
|
||||
//applyPoison (entity: Entity, source: Entity, severity: Int)
|
||||
//isPoisoned (entity: Entity) : Boolean
|
||||
//spawnProjectile
|
||||
//face()
|
||||
|
||||
override fun open(player: Player?, component: Component?) {
|
||||
super.open(player, component)
|
||||
player ?: return
|
||||
Component(EggTurret.ID).setCloseEvent(CloseEvent {p, _ -> closeTurretIface(p);return@CloseEvent true})
|
||||
updateCannonUI(player)
|
||||
}
|
||||
|
||||
//error message CHATBOX "[bold]all of the _PENANCE_ have been killed!"
|
||||
//error messageif out of range CHATBOX "There are no targetable _PENANCE_ within fireing range."
|
||||
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int ): Boolean {
|
||||
player ?: return true
|
||||
|
||||
checkEasterEgg(player, button)
|
||||
|
||||
if (button ==EggTurret.close ){ closeTurretIface(player); return true}
|
||||
shootNormalEggs(button,player)
|
||||
return true
|
||||
}
|
||||
|
||||
fun shootNormalEggs(button: Int, player: Player?) {
|
||||
player ?: return
|
||||
|
||||
val (type, eggType) = listOf(
|
||||
PenanceType.HEALER to EggTurret.pHealerBtns,
|
||||
PenanceType.RUNNER to EggTurret.pRunnerBtns,
|
||||
PenanceType.FIGHTER to EggTurret.pFighterBtns,
|
||||
PenanceType.RANGER to EggTurret.pRangerBtns,
|
||||
).firstNotNullOfOrNull { (type, colors) ->
|
||||
when (button) {
|
||||
colors.GREEN -> type to EggType.GREEN
|
||||
colors.RED -> type to EggType.RED
|
||||
colors.BLUE -> type to EggType.BLUE
|
||||
else -> type to EggType.YELLOW
|
||||
}
|
||||
} ?: if (button == EggTurret.queenBtn) {
|
||||
PenanceType.QUEEN to EggType.YELLOW
|
||||
} else return
|
||||
|
||||
sendMessage(player, "Shoot ${eggType.action} at $type.")
|
||||
fireEgg(player, type, eggType)
|
||||
updateCannonUI(player)
|
||||
}
|
||||
|
||||
fun updateCannonUI(player: Player?){
|
||||
player ?: return
|
||||
val eggHopper = getBASession(player)?.eggHopper ?: return
|
||||
val penances = listOf( EggTurret.pHealer, EggTurret.pRunner, EggTurret.pRanger, EggTurret.pFighter )
|
||||
|
||||
penances.forEach { penance ->
|
||||
val components = listOf(
|
||||
EggType.GREEN to penance.GREEN,
|
||||
EggType.RED to penance.RED,
|
||||
EggType.BLUE to penance.BLUE
|
||||
)
|
||||
|
||||
components.forEach { (eggType, componentId) ->
|
||||
val value = eggType.getCount(eggHopper)
|
||||
setInterfaceText(player, value.toString(), EggTurret.ID, componentId)
|
||||
}
|
||||
}
|
||||
setInterfaceText( player, EggType.YELLOW.getCount(eggHopper).toString(), EggTurret.ID, EggTurret.OMEGA )
|
||||
}
|
||||
|
||||
|
||||
private fun closeTurretIface(player: Player?){
|
||||
player ?: return
|
||||
player.interfaceManager.restoreTabs()
|
||||
player.interfaceManager.openTab(3,Component(149))
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ALL_EGGS = intArrayOf(Items.GREEN_EGG_10531,Items.RED_EGG_10532,Items.BLUE_EGG_10533,Items.OMEGA_EGG_10537)
|
||||
fun openTurretIface(player: Player?) {
|
||||
player ?: return
|
||||
if (getBASession(player)?.eggHopper?.totalCount() == 0) {
|
||||
sendDialogueLines(player,"There are no eggs in the hopper.")
|
||||
return
|
||||
}
|
||||
player.interfaceManager.openTab(3,Component(495))
|
||||
player.interfaceManager.setViewedTab(3)
|
||||
player.interfaceManager.removeTabs(0, 1, 2, 4, 5, 6,7,8,9,11, 12,13)
|
||||
}
|
||||
fun loadEggHopper(player: Player?){
|
||||
player ?: return
|
||||
val session = getBASession(player)
|
||||
val role =session?.team?.getRoleForPlayer(player)
|
||||
if (role != BarbRole.COLLECTOR) {sendMessage(player,"You need to be a Collector to load eggs.");return}
|
||||
ALL_EGGS.forEach { loadHopperEggs(player, it) }
|
||||
//Load hopper emote, Same as place table??
|
||||
}
|
||||
fun loadHopperEggs(player: Player?, itemId: Int) {
|
||||
player ?: return
|
||||
|
||||
val session = getBASession(player) ?: return
|
||||
val hopper = session.eggHopper
|
||||
|
||||
val color = hopper.eggColorMap[itemId] ?: return
|
||||
|
||||
val current = when (itemId) {
|
||||
Items.GREEN_EGG_10531 -> hopper.green
|
||||
Items.RED_EGG_10532 -> hopper.red
|
||||
Items.BLUE_EGG_10533 -> hopper.blue
|
||||
Items.OMEGA_EGG_10537 -> hopper.yellow
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val free = 5 - current
|
||||
if (free <= 0) { sendMessage(player, "You can't load any more $color eggs."); return }
|
||||
|
||||
var loaded = 0
|
||||
val collectorBag = getCollectorBag(player).bag
|
||||
val bagCount = collectorBag.getEggCount(itemId)
|
||||
val fromBag = minOf(free, bagCount)
|
||||
|
||||
repeat(fromBag) { collectorBag.container.remove(Item(itemId, 1)); loaded++ }
|
||||
|
||||
val remaining = free - loaded
|
||||
if (remaining > 0) {
|
||||
val invCount = amountInInventory(player, itemId)
|
||||
val fromInv = minOf(remaining, invCount)
|
||||
|
||||
if (fromInv > 0) {
|
||||
removeItem(player, Item(itemId, fromInv))
|
||||
loaded += fromInv
|
||||
}
|
||||
}
|
||||
|
||||
if (loaded <= 0) { return }
|
||||
|
||||
hopper.addEgg(itemId, loaded)
|
||||
sendMessage(player, "You load the hopper.")
|
||||
}
|
||||
fun showEggHopperCount(player: Player?){
|
||||
player ?: return
|
||||
val eggsCount = getBASession(player)?.eggHopper
|
||||
val poison = eggsCount?.green
|
||||
val explosive = eggsCount?.red
|
||||
val stun = eggsCount?.blue
|
||||
sendDialogueLines(player,"The hopper contains:","$poison poison eggs, $explosive explosive eggs","and $stun stun eggs.")
|
||||
|
||||
}
|
||||
|
||||
//error message CHATBOX "[bold]all of the _PENANCE_ have been killed!"
|
||||
fun fireEgg(player: Player, type: PenanceType, eggType: EggType){
|
||||
val session = getBASession(player)
|
||||
val npcId = session?.currentWaveDefinition?.npcIds?.get(type)
|
||||
val eggCannon = findClosestNPCIDFromPlayer(player,NPCs.EGG_LAUNCHER_5026,2)
|
||||
val target = findClosestTargetNPCIDFromNPC(npcId, eggCannon as NPC ,14)
|
||||
val hopper = session?.eggHopper ?: return
|
||||
|
||||
if (target == null) { sendDialogueLines(player,"There are no targetable Penance ${type.name.lowercase().replaceFirstChar { it.uppercase() }} within firing range.") ;return}
|
||||
if (!eggType.tryConsume(hopper)) {
|
||||
sendMessage(player, "There are no ${eggType.name.lowercase()} eggs in the hopper.")
|
||||
return
|
||||
}
|
||||
//queueScript { }
|
||||
player.animate(Animation(5428))
|
||||
eggCannon.face(target)
|
||||
eggCannon.animate(Animation(5426))
|
||||
|
||||
spawnProjectile(eggCannon,target as Entity,eggType.projectileGFX)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum class EggType(val consume: EggCannon.EggHopper.() -> Boolean, val action: String, val projectileGFX: Int, val getAmount: EggCannon.EggHopper.() -> Int) {
|
||||
GREEN({ consumeGreen() }, "poison",GREEN_EGG_PROJECTILE_977, { green }),
|
||||
RED({ consumeRed() }, "explosive", RED_EGG_PROJECTILE_978, { red }),
|
||||
BLUE({ consumeBlue() }, "stun", Blue_EGG_PROJECTILE_978, { blue }),
|
||||
YELLOW({consumeYellow()},"Omega",YELLOW_EGG_PROJECTILE_980, { yellow });
|
||||
|
||||
fun tryConsume(hopper: EggCannon.EggHopper): Boolean = hopper.consume()
|
||||
fun getCount(hopper: EggCannon.EggHopper) = hopper.getAmount()
|
||||
}
|
||||
data class EggColors(val GREEN: Int, val RED: Int, val BLUE: Int)
|
||||
object EggTurret {
|
||||
const val ID = 495
|
||||
val pHealer = EggColors(57, 58, 59)
|
||||
val pHealerBtns = EggColors(11, 12, 13)
|
||||
|
||||
val pRunner = EggColors(60, 61, 62)
|
||||
val pRunnerBtns = EggColors(24, 25, 26)
|
||||
|
||||
val pFighter = EggColors(63, 64, 65)
|
||||
val pFighterBtns = EggColors(37, 38, 39)
|
||||
|
||||
val pRanger = EggColors(66, 67, 68)
|
||||
val pRangerBtns = EggColors(50, 51, 52)
|
||||
|
||||
const val OMEGA = 69
|
||||
const val queenBtn = 56
|
||||
val close = 72
|
||||
}
|
||||
|
||||
//emote 5428 maybe
|
||||
/*
|
||||
https://youtu.be/_EipqTK3Qak?t=106
|
||||
https://www.youtube.com/watch?v=OJ2BDEM03Dw
|
||||
entity.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 12)
|
||||
entity.interfaceManager.restoreTabs()
|
||||
|
||||
//hide all tabs but invtenory bag and clan chat tab
|
||||
|
||||
//egg explosion 20727
|
||||
|
||||
shoot option when no eggs in hoper =
|
||||
MEssage chatbox-> There are no egs in the hopper.
|
||||
|
||||
Dialog message if no monsters in range
|
||||
"there are no targetable Penance Runners within firing range.
|
||||
|
||||
Look-in ->
|
||||
The hopper contains
|
||||
0 poison egs, 0 explosive eggs
|
||||
and 0 stun eggs.
|
||||
|
||||
stun eggs
|
||||
explosive eggs
|
||||
poison eggs
|
||||
messages
|
||||
You load the hopper.
|
||||
You cant load any more /Egg_type/s.
|
||||
|
||||
Picking up wrong egg, "The egg exploded" / 5 damage
|
||||
getAttribute<Player?>(self, "target", null) // you can set the NPC CANNON a target.
|
||||
|
||||
"You put the egg in the bag"
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package content.minigame.barbassault.arena.scenery
|
||||
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.BarbassaultSession.HasUIText
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.api.*
|
||||
import core.game.component.Component
|
||||
import core.game.component.ComponentDefinition
|
||||
import core.game.component.ComponentPlugin
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
@Initializable
|
||||
class HornOfGlory : ComponentPlugin() , InteractionListener {
|
||||
var hornCallLock = false
|
||||
val CallMap = mapOf(
|
||||
GloryHorn.CONTROLED_BRONZE_WIND to BarbassaultSession.AttackerStyle.STYLE_1,
|
||||
GloryHorn.ACCURATE_IRON_WATER to BarbassaultSession.AttackerStyle.STYLE_2,
|
||||
GloryHorn.AGGRISSIVE_STEEL_EARTH to BarbassaultSession.AttackerStyle.STYLE_3,
|
||||
GloryHorn.DEFENSIVE_MITHRIL_FIRE to BarbassaultSession.AttackerStyle.STYLE_4,
|
||||
GloryHorn.POISON_TOFU to BarbassaultSession.PoisonFood.TOFU ,
|
||||
GloryHorn.POISON_WORMS to BarbassaultSession.PoisonFood.WORMS,
|
||||
GloryHorn.POISON_MEAT to BarbassaultSession.PoisonFood.MEAT,
|
||||
GloryHorn.RED_EGG to BarbassaultSession.EggColor.RED,
|
||||
GloryHorn.GREEN_EGG to BarbassaultSession.EggColor.GREEN,
|
||||
GloryHorn.BLUE_EGG to BarbassaultSession.EggColor.BLUE,
|
||||
GloryHorn.FOOD_TOFU to BarbassaultSession.LureFood.TOFU,
|
||||
GloryHorn.FOOD_CRACKERS to BarbassaultSession.LureFood.CRACKERS,
|
||||
GloryHorn.FOOD_WORMS to BarbassaultSession.LureFood.WORMS
|
||||
)
|
||||
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
ComponentDefinition.forId(484).plugin = this
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?,component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int ): Boolean {
|
||||
player ?: return true
|
||||
val session = getBASession(player) ?: return true
|
||||
val toCall = CallMap[button] as HasUIText
|
||||
|
||||
if(!hornCallLock) {
|
||||
session.onHornGloryCall(toCall)
|
||||
sendChat(player, toCall.hornShout)
|
||||
player.animate(Animation(5436))
|
||||
player.lock(6)
|
||||
hornCallLock = true
|
||||
//i should replace these with script ques, yes?
|
||||
GameWorld.Pulser.submit(object : Pulse(6, player) {
|
||||
override fun pulse(): Boolean {
|
||||
player.unlock()
|
||||
hornCallLock = false
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun open(player: Player?, component: Component?) {
|
||||
super.open(player, component)
|
||||
player ?: return
|
||||
getBASession(player)?.updateGloryHornUI()
|
||||
}
|
||||
override fun defineListeners() {
|
||||
on(Scenery.HORN_OF_GLORY_20247, IntType.SCENERY, "Call") { player, _ ->
|
||||
player.interfaceManager.open(Component(GloryHorn.ID))
|
||||
return@on true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object GloryHorn {
|
||||
val ID = 484
|
||||
//collector
|
||||
val RED_EGG = 13
|
||||
val GREEN_EGG = 14
|
||||
val BLUE_EGG = 15
|
||||
//attacker
|
||||
val CONTROLED_BRONZE_WIND = 16
|
||||
val ACCURATE_IRON_WATER = 17
|
||||
val AGGRISSIVE_STEEL_EARTH = 18
|
||||
val DEFENSIVE_MITHRIL_FIRE = 19
|
||||
//defender
|
||||
val FOOD_TOFU = 20
|
||||
val FOOD_WORMS = 21
|
||||
val FOOD_CRACKERS = 22
|
||||
//healer
|
||||
val POISON_TOFU = 23
|
||||
val POISON_WORMS = 24
|
||||
val POISON_MEAT = 25
|
||||
object CallOut {
|
||||
val defaultText = "---------------------"
|
||||
const val attacker = 5
|
||||
const val defender = 6
|
||||
const val collector = 7
|
||||
const val healer = 8
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package content.minigame.barbassault.arena.scenery
|
||||
|
||||
import content.minigame.barbassault.getBALevels
|
||||
import core.api.EquipmentSlot
|
||||
import core.api.addItem
|
||||
import core.api.getItemFromEquipment
|
||||
import core.api.sendMessage
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
class ItemMachine: InteractionListener {
|
||||
//Attacker//
|
||||
val TAKE_RUNES = intArrayOf(Items.CATALYTIC_RUNE_12851,Items.ELEMENTAL_RUNE_12850)
|
||||
//suppose to use Catalyic and Elemental runes
|
||||
private val TAKE_ARROWS = intArrayOf(Items.BRONZE_ARROW_882, Items.IRON_ARROW_884, Items.STEEL_ARROW_886, Items.MITHRIL_ARROW_888)
|
||||
//private val TAKE_RUNES = intArrayOf(Items.AIR_RUNE_556, Items.WATER_RUNE_555, Items.EARTH_RUNE_557, Items.FIRE_RUNE_554, Items.MIND_RUNE_558, Items.CHAOS_RUNE_562, Items.DEATH_RUNE_560, Items.BLOOD_RUNE_565)
|
||||
//Defender//
|
||||
private val TAKE_WORMS = Items.WORMS_10515
|
||||
private val TAKE_CRACKERS = Items.CRACKERS_10513
|
||||
private val TAKE_TOFU = Items.TOFU_10514
|
||||
private val baseItems_DEF = intArrayOf(TAKE_WORMS, TAKE_CRACKERS, TAKE_TOFU)
|
||||
private val STOCK_UP_DEF = IntArray(10 * baseItems_DEF.size) { i -> baseItems_DEF[i % baseItems_DEF.size] }
|
||||
//Healer//
|
||||
private val ALL_HEALER_VAILS = intArrayOf(Items.HEALING_VIAL_10546,Items.HEALING_VIAL1_10545,Items.HEALING_VIAL2_10544,Items.HEALING_VIAL3_10543,Items.HEALING_VIAL4_10542)
|
||||
private val TAKE_VAIL = Items.HEALING_VIAL_10546
|
||||
private val TAKE_POIS_WORMS = Items.POISONED_WORMS_10540
|
||||
private val TAKE_POIS_TOFU = Items.POISONED_TOFU_10539
|
||||
private val TAKE_POIS_MEAT = Items.POISONED_MEAT_10541
|
||||
|
||||
private val baseItems_HEAL = intArrayOf(TAKE_POIS_WORMS, TAKE_POIS_TOFU, TAKE_POIS_MEAT)
|
||||
private val STOCK_UP_HEAL = IntArray(10 * baseItems_HEAL.size) { i -> baseItems_HEAL[i % baseItems_HEAL.size] }
|
||||
|
||||
private val ATTACKER_ICON = 10556
|
||||
private val DEFENDER_ICON = 10558
|
||||
private val HEALER_ICON = 10559
|
||||
private val COLLECTOR_ICON = 10557
|
||||
|
||||
override fun defineListeners() {
|
||||
//Attacker//
|
||||
on(Scenery.ATTACKER_ITEM_MACHINE_20241, IntType.SCENERY, "Take-runes") { player, node ->
|
||||
handleAddItemMachine(player, node,ATTACKER_ICON, TAKE_RUNES, 300,DispenserType.RUNES)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.ATTACKER_ITEM_MACHINE_20241, IntType.SCENERY, "Take-arrows") { player, node ->
|
||||
handleAddItemMachine(player, node,ATTACKER_ICON, TAKE_ARROWS, 300,DispenserType.ARROWS)
|
||||
return@on true
|
||||
}
|
||||
//Defender//
|
||||
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Stock-up") { player, node ->
|
||||
handleAddItemMachine(player, node,DEFENDER_ICON, STOCK_UP_DEF, 1,DispenserType.FOOD)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Take-crackers") { player, node ->
|
||||
handleAddItemMachine(player, node,DEFENDER_ICON, intArrayOf(TAKE_CRACKERS), 5,DispenserType.FOOD)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Take-tofu") { player, node ->
|
||||
handleAddItemMachine(player, node,DEFENDER_ICON, intArrayOf(TAKE_TOFU), 5,DispenserType.FOOD)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Take-worms") { player, node ->
|
||||
handleAddItemMachine(player, node,DEFENDER_ICON, intArrayOf(TAKE_WORMS), 5,DispenserType.FOOD)
|
||||
return@on true
|
||||
}
|
||||
//Healer//
|
||||
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Stock-up") { player, node ->
|
||||
var stockUp = STOCK_UP_HEAL
|
||||
if (!hasAnyVial(player)) {
|
||||
stockUp = intArrayOf(TAKE_VAIL) + STOCK_UP_HEAL
|
||||
}
|
||||
handleAddItemMachine(player, node,HEALER_ICON, stockUp, 1,DispenserType.POISONED)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-vial") { player, node ->
|
||||
if (hasAnyVial(player)) {
|
||||
sendMessage(player, "You can only carry one healing vial at a time.")
|
||||
return@on true
|
||||
}
|
||||
handleAddItemMachine(player, node,HEALER_ICON, intArrayOf(TAKE_VAIL), 1,DispenserType.VAIL)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-worms") { player, node ->
|
||||
handleAddItemMachine(player, node,HEALER_ICON, intArrayOf(TAKE_POIS_WORMS), 5,DispenserType.POISONED)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-tofu") { player, node ->
|
||||
handleAddItemMachine(player, node,HEALER_ICON, intArrayOf(TAKE_POIS_TOFU), 5,DispenserType.POISONED)
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-meat") { player, node ->
|
||||
handleAddItemMachine(player, node,HEALER_ICON, intArrayOf(TAKE_POIS_MEAT), 5,DispenserType.POISONED)
|
||||
return@on true
|
||||
}
|
||||
//Collector//
|
||||
on(Scenery.COLLECTOR_CONVERTER_21250, IntType.SCENERY, "Convert") { player, _ ->
|
||||
val collectorLevel = getBALevels(player).col
|
||||
if (!hasCape(player, COLLECTOR_ICON)) return@on true
|
||||
|
||||
//Items.RED_EGG_10532
|
||||
//Items.BLUE_EGG_10533
|
||||
//Items.GREEN_EGG_10531
|
||||
//uhhhhhh
|
||||
//more research is needed.
|
||||
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
private fun handleAddItemMachine(player: Player,node: Node,capeId: Int, items: IntArray, amount: Int,message: DispenserType = DispenserType.GENERIC)
|
||||
{
|
||||
if (!hasCape(player, capeId)) return
|
||||
player.animate(Animation(5419))
|
||||
player.lock(5)
|
||||
// theres two emotes for the machine and lock duration
|
||||
GameWorld.Pulser.submit(object : Pulse(3, player) {
|
||||
override fun pulse(): Boolean {
|
||||
addArrayOfItems(player,items,amount)
|
||||
sendMessage(player, message.message)
|
||||
player.unlock()
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
private fun addArrayOfItems(player: Player, ids: IntArray, amount: Int) {
|
||||
ids.forEach { id -> addItem(player,id,amount) }
|
||||
}
|
||||
private fun hasAnyVial(player: Player): Boolean {
|
||||
return ALL_HEALER_VAILS.any { player.inventory.contains(it,1) }
|
||||
}
|
||||
fun hasCape(player: Player, capeId: Int): Boolean {
|
||||
return getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == capeId
|
||||
}
|
||||
private enum class DispenserType(val message: String) {
|
||||
ARROWS("You take a selection of arrows from the dispenser."),
|
||||
RUNES("You take a selection of runes from the dispenser."),
|
||||
FOOD("You fill up your inventory with food from the dispenser."),
|
||||
POISONED("You fill up your inventory with poisoned food from the dispenser."),
|
||||
VAIL("You take a vial from the dispenser."),
|
||||
GENERIC("You take items from the dispenser.")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
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
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
|
||||
class AttackerBehavior : RoleBehavior {
|
||||
|
||||
override fun tick(ctx: BABotContext) {
|
||||
|
||||
val bot = ctx.bot
|
||||
|
||||
ctx.insultDefender()
|
||||
useCalledAttackStyle(bot)
|
||||
if (attackPenance(ctx)) return
|
||||
if (ctx.poolIdle("BA-Attacker: Idling at pool")) return
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun useCalledAttackStyle(bot: Player) {
|
||||
val baSession = getBASession(bot) ?: return
|
||||
val called = (baSession.roleCalls[BarbRole.ATTACKER]?.called ?: AttackerStyle.values().random() ) as AttackerStyle
|
||||
if (bot.properties.attackStyle.style == called.attackStyle) return
|
||||
|
||||
bot.properties.attackStyle = AttackStyle(called.attackStyle, BONUS_SLASH)
|
||||
}
|
||||
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
|
||||
}
|
||||
private fun findTargets(entity: Entity): List<Entity> = getBASession(entity)?.sessionNpcs?.filter { checkValidTargets(it) }?.sortedBy { it.location.getDistance(entity.location) }?.take(5)?: emptyList()
|
||||
|
||||
fun attackPenance(ctx: BABotContext): Boolean {
|
||||
val bot = ctx.bot
|
||||
if (bot.inCombat()) return true
|
||||
var target = ctx.currentTarget as? Entity
|
||||
|
||||
if (target != null && !checkValidTargets(target as NPC)) { ctx.currentTarget = null; target = null }
|
||||
|
||||
if (target == null) {
|
||||
target = findTargets(bot).firstOrNull { !it.inCombat() }?: findTargets(bot).firstOrNull()
|
||||
if (target == null) return false
|
||||
ctx.currentTarget = target
|
||||
}
|
||||
|
||||
bot.attack(target)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
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
|
||||
|
||||
|
||||
|
||||
class BABotContext( val bot: Player,val api: ScriptAPI ) {
|
||||
var currentTarget: Node? = null
|
||||
var script: Script? = null
|
||||
var session: BarbassaultSession? = null
|
||||
var role: BarbRole? = null
|
||||
|
||||
private var delayTicks = 0
|
||||
private var defenderInsultNextTick = 0
|
||||
|
||||
var tick: Int = 0
|
||||
|
||||
fun tickDelay(ticks: Int) { delayTicks = ticks }
|
||||
|
||||
fun processDelay(): Boolean {
|
||||
if (delayTicks > 0) {
|
||||
delayTicks--
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun clickDialogueOption(buttonId: Int): Boolean {
|
||||
val chatbox = bot.interfaceManager.chatbox ?: return false
|
||||
|
||||
val action = bot.dialogueInterpreter.actions.removeFirstOrNull()
|
||||
if (action != null) {
|
||||
action.handle(bot, buttonId)
|
||||
bot.interfaceManager.closeChatbox()
|
||||
bot.dialogueInterpreter.close()
|
||||
return true
|
||||
}
|
||||
|
||||
if (bot.dialogueInterpreter.dialogue != null) {
|
||||
bot.dialogueInterpreter.handle(chatbox.id, buttonId)
|
||||
return true
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
bot.customState = state
|
||||
api.walkTo(base.transform(25, 17, 0))
|
||||
return true
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
val defenderInsults = listOf(
|
||||
"You defend like Ryan codes Barbass",
|
||||
"R u asleep?",
|
||||
"Get szued",
|
||||
"I've seen better defense from a broken gate",
|
||||
"Do you even see the runners?",
|
||||
"My grandma can do better then that!",
|
||||
|
||||
"Runner escaped. Again.",
|
||||
"Nice lure, shame it did nothing.",
|
||||
"Did you place the food in Lumbridge?",
|
||||
"The runners thank you for your service.",
|
||||
"Wrong food, wrong place, classic.",
|
||||
"You had one job.",
|
||||
"The runners are speedrunning because of you.",
|
||||
"I've seen level 5s defend better.",
|
||||
"Did you forget to pick a call?",
|
||||
"The runners are literally laughing at you.",
|
||||
"Blink twice if you're AFK.",
|
||||
"That runner just waved as it passed.",
|
||||
"Maybe try feeding them the right bait?",
|
||||
"You're defending their right to escape.",
|
||||
"At this rate we'll finish next week.",
|
||||
"The healer is doing your job too.",
|
||||
"Even the collector is judging you.",
|
||||
"Attacker called. Wants their role back.",
|
||||
"No wonder nobody picks Defender.",
|
||||
"This is why Defender is always last.",
|
||||
"You make runners look smart.",
|
||||
"The trap isn't decorative, you know.",
|
||||
"Another runner escaped. Impressive.",
|
||||
"The runners have achieved freedom.",
|
||||
"I think the runners own the arena now.",
|
||||
"Outstanding performance. For the runners.",
|
||||
"The queen will hatch before you finish.",
|
||||
"Did you learn Defender from YouTube shorts?",
|
||||
"You lure like a drunk goblin.",
|
||||
"Food goes on the ground, not in your pocket.",
|
||||
"The runners aren't supposed to reach the cave.",
|
||||
"This wave is sponsored by missed runners.",
|
||||
"Your lure path looks like modern art.",
|
||||
"The runners are farming YOU for points.",
|
||||
"Defender? More like Spectator.",
|
||||
"I've seen bots defend better.",
|
||||
"The horn gave a call. Did you miss it?",
|
||||
"Wrong bait any% speedrun.",
|
||||
"You're boosting the runners' confidence.",
|
||||
"Defender is not a cosmetic role.",
|
||||
"Every escaped runner adds 5 minutes.",
|
||||
"The runners have filed for citizenship.",
|
||||
"You couldn't defend a sandwich from seagulls.",
|
||||
"The cave entrance misses you.",
|
||||
"Maybe the runners are the defenders now.",
|
||||
"The runners are following YOU.",
|
||||
"I can hear the healers crying.",
|
||||
"This is why quick-starts fail.",
|
||||
"The runner path is not a suggestion.",
|
||||
"Congratulations, you've unlocked free-range runners.",
|
||||
"One more escape and they get a pension.",
|
||||
"Your trap placement scares nobody.",
|
||||
"Did the runners bribe you?",
|
||||
"The runners are playing on easy mode.",
|
||||
"You're the reason Defender guides exist.",
|
||||
"At least you're consistently bad.",
|
||||
"The runners have stopped respecting you.",
|
||||
"Even the penance know you're lost."
|
||||
)
|
||||
api.sendChat(defenderInsults.random())
|
||||
defenderInsultNextTick = tick + (8..20).random()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +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 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 session = ctx.session ?: return
|
||||
ctx.script?.preventRandomIdle = true
|
||||
|
||||
ctx.insultDefender()
|
||||
if (isHopperFull(session)) {
|
||||
bot.customState = "BA-Collector: Hopper full, idling at cannon"
|
||||
idleAtCannon(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
if (hasLoadableCarriedEggs(ctx, session)) {
|
||||
if (loadHopper(ctx)) return
|
||||
}
|
||||
|
||||
val calledEgg = getCalledEgg(session) ?: run {
|
||||
bot.customState = "BA-Collector: Waiting for attacker call"
|
||||
idleAtCannon(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +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 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 session = ctx.session ?: return
|
||||
ctx.script?.preventRandomIdle = true
|
||||
|
||||
if (session.isPenanceDead(PenanceType.RUNNER)) {
|
||||
if (ctx.poolIdle("BA-Defender: Idling at pool")) return
|
||||
bot.customState = "BA-Defender: Idle at pool"
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
package content.minigame.barbassault.bots.roles
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.npcs.PENANCE_HEALER_IDS
|
||||
import content.minigame.barbassault.bots.RoleBehavior
|
||||
import content.minigame.barbassault.bots.core.BABotContext
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListeners
|
||||
import core.game.node.entity.combat.DeathTask
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
class HealerBehavior : RoleBehavior {
|
||||
|
||||
override fun tick(ctx: BABotContext) {
|
||||
val bot = ctx.bot
|
||||
val session = ctx.session ?: return
|
||||
|
||||
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
|
||||
|
||||
bot.customState = "BA-Healer: Idle at pool"
|
||||
}
|
||||
|
||||
private fun healTeamMate(ctx: BABotContext, session: BarbassaultSession): Boolean {
|
||||
val bot = ctx.bot
|
||||
val target = session.team.allPlayers()
|
||||
.filter { it != bot && healthPercent(it) <= TEAM_HEAL_PERCENT && it.skills.lifepoints > 0 }
|
||||
.minByOrNull { healthPercent(it) }
|
||||
?: return false
|
||||
|
||||
val vial = getBestUsableVial(bot) ?: return false
|
||||
bot.customState = "BA-Healer: Healing ${target.username} (${target.skills.lifepoints}/${target.skills.maximumLifepoints})"
|
||||
InteractionListeners.run(vial, target, IntType.PLAYER, bot)
|
||||
ctx.tickDelay(3)
|
||||
return true
|
||||
}
|
||||
private fun healAnyTeammate(ctx: BABotContext, session: BarbassaultSession): Boolean {
|
||||
val bot = ctx.bot
|
||||
|
||||
val target = session.team.allPlayers()
|
||||
.filter { it != bot && it.skills.lifepoints > 0 }
|
||||
.minByOrNull { healthPercent(it) }
|
||||
?: return false
|
||||
|
||||
val vial = getBestUsableVial(bot) ?: return false
|
||||
if (healthPercent(target) >= 0.95) return false
|
||||
|
||||
bot.customState = "BA-Healer: Idle-heal ${target.username}"
|
||||
InteractionListeners.run(vial, target, IntType.PLAYER, bot)
|
||||
ctx.tickDelay(2)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun stockUp(ctx: BABotContext): Boolean {
|
||||
val bot = ctx.bot
|
||||
|
||||
if (hasAnyVial(bot) && POISON_FOODS.any { bot.inventory.containsAtLeastOneItem(it) }) {
|
||||
return false
|
||||
}
|
||||
|
||||
val machine = ctx.api.getNearestNode(Scenery.HEALER_ITEM_MACHINE_20243, true) ?: return false
|
||||
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
|
||||
}
|
||||
|
||||
private fun fillVial(ctx: BABotContext): Boolean {
|
||||
val bot = ctx.bot
|
||||
|
||||
if (!hasAnyVial(bot) || bot.inventory.containsAtLeastOneItem(Items.HEALING_VIAL4_10542)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val spring = ctx.api.getNearestNode(Scenery.HEALER_SPRING_20150, true) ?: return false
|
||||
bot.customState = "BA-Healer: Filling vial"
|
||||
ctx.api.interact(bot, spring, "Take-from")
|
||||
ctx.tickDelay(4)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun healSelf(ctx: BABotContext): Boolean {
|
||||
val bot = ctx.bot
|
||||
|
||||
if (healthPercent(bot) > SELF_HEAL_PERCENT) return false
|
||||
|
||||
val spring = ctx.api.getNearestNode(Scenery.HEALER_SPRING_20150, true) ?: return false
|
||||
bot.customState = "BA-Healer: Drinking from spring"
|
||||
ctx.api.interact(bot, spring, "Drink-from")
|
||||
ctx.tickDelay(5)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun poisonPenanceHealer(ctx: BABotContext, session: BarbassaultSession): Boolean {
|
||||
val bot = ctx.bot
|
||||
val poison = (session.roleCalls[BarbRole.HEALER] as? BarbassaultSession.HealerCall)?.called
|
||||
?: return false
|
||||
|
||||
if (!bot.inventory.containsAtLeastOneItem(poison.itemId)) {
|
||||
val machine = ctx.api.getNearestNode(Scenery.HEALER_ITEM_MACHINE_20243, true) ?: return false
|
||||
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
|
||||
}
|
||||
|
||||
val target = session.sessionNpcs
|
||||
.filter { isValidPenanceHealer(it) }
|
||||
.minByOrNull { it.location.getDistance(bot.location) }
|
||||
?: return false
|
||||
|
||||
bot.customState = "BA-Healer: Poisoning ${target.name} with ${poison.ui}"
|
||||
ctx.api.useWith(bot, poison.itemId, target)
|
||||
ctx.tickDelay(3)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getBestUsableVial(player: Player): Item? {
|
||||
return USABLE_HEALING_VIALS
|
||||
.firstOrNull { player.inventory.containsAtLeastOneItem(it) }
|
||||
?.let { player.inventory.getItem(Item(it)) }
|
||||
}
|
||||
|
||||
private fun hasAnyVial(player: Player): Boolean {
|
||||
return ALL_HEALING_VIALS.any { player.inventory.containsAtLeastOneItem(it) }
|
||||
}
|
||||
|
||||
private fun healthPercent(player: Player): Double {
|
||||
val max = player.skills.maximumLifepoints
|
||||
if (max <= 0) return 1.0
|
||||
return player.skills.lifepoints.toDouble() / max.toDouble()
|
||||
}
|
||||
|
||||
private fun isValidPenanceHealer(npc: NPC): Boolean {
|
||||
return npc.id in PENANCE_HEALER_IDS &&
|
||||
npc.isActive &&
|
||||
npc.skills.lifepoints > 0 &&
|
||||
!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
|
||||
|
||||
private val ALL_HEALING_VIALS = intArrayOf(
|
||||
Items.HEALING_VIAL_10546,
|
||||
Items.HEALING_VIAL1_10545,
|
||||
Items.HEALING_VIAL2_10544,
|
||||
Items.HEALING_VIAL3_10543,
|
||||
Items.HEALING_VIAL4_10542
|
||||
)
|
||||
|
||||
private val USABLE_HEALING_VIALS = intArrayOf(
|
||||
Items.HEALING_VIAL4_10542,
|
||||
Items.HEALING_VIAL3_10543,
|
||||
Items.HEALING_VIAL2_10544,
|
||||
Items.HEALING_VIAL1_10545
|
||||
)
|
||||
|
||||
private val POISON_FOODS = intArrayOf(
|
||||
Items.POISONED_TOFU_10539,
|
||||
Items.POISONED_WORMS_10540,
|
||||
Items.POISONED_MEAT_10541
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package content.minigame.barbassault.bots
|
||||
|
||||
import content.minigame.barbassault.arena.BarbassaultState
|
||||
import content.minigame.barbassault.bots.core.BABotContext
|
||||
import content.minigame.barbassault.getBASession
|
||||
|
||||
import content.minigame.barbassault.lobby.BALobby
|
||||
import content.minigame.barbassault.lobby.BALobby.Companion.QUICK_START
|
||||
import core.game.world.map.Location
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
|
||||
class LobbyBehavior : RoleBehavior {
|
||||
private enum class LobbyState { GET_TO_BA, FINDING_ROOM, WAITING_IN_ROOM,IN_ARENA }
|
||||
|
||||
|
||||
override fun tick(ctx: BABotContext) {
|
||||
|
||||
val state = state(ctx)
|
||||
ctx.bot.customState = "BA-Lobby: $state"
|
||||
ctx.bot.debug("$state")
|
||||
|
||||
when (state) {
|
||||
LobbyState.GET_TO_BA -> getToBA(ctx)
|
||||
LobbyState.FINDING_ROOM -> enterRoom(ctx)
|
||||
LobbyState.WAITING_IN_ROOM -> waitingInRoom(ctx)
|
||||
LobbyState.IN_ARENA -> return
|
||||
}
|
||||
}
|
||||
|
||||
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}")
|
||||
|
||||
return when {
|
||||
(session?.state == BarbassaultState.IN_ARENA) -> LobbyState.IN_ARENA
|
||||
(session?.state == BarbassaultState.END) -> LobbyState.IN_ARENA
|
||||
(session?.state == BarbassaultState.COMPLETE) -> LobbyState.IN_ARENA
|
||||
isWaitingQuick(loc) -> LobbyState.WAITING_IN_ROOM
|
||||
isWaitingArea(loc) && (session != null) -> LobbyState.WAITING_IN_ROOM
|
||||
isInHalls(loc) -> LobbyState.FINDING_ROOM
|
||||
|
||||
else -> LobbyState.GET_TO_BA
|
||||
}
|
||||
}
|
||||
|
||||
private fun waitingInRoom(ctx: BABotContext) {
|
||||
if (ctx.tick % 12 == 0 && !ctx.bot.walkingQueue.isMoving) {
|
||||
ctx.api.walkTo(QUICK_START.randomWalkableLoc)
|
||||
ctx.tickDelay(3)
|
||||
return
|
||||
}
|
||||
|
||||
if (ctx.tick % 150 == 0) {
|
||||
ctx.api.sendChat("Cmon, we need more people!!")
|
||||
}
|
||||
}
|
||||
private fun getToBA(ctx: BABotContext) {
|
||||
ctx.bot.teleport(BALobby.MAIN_LOBBY.randomWalkableLoc)
|
||||
ctx.tickDelay(4)
|
||||
}
|
||||
|
||||
private fun enterRoom(ctx: BABotContext) {
|
||||
if (ctx.bot.interfaceManager.hasChatbox()) {
|
||||
ctx.clickDialogueOption(6)
|
||||
ctx.tickDelay(8)
|
||||
return
|
||||
}
|
||||
val quickDoor = ctx.api.getNearestNode(Scenery.DOOR_20209, true)
|
||||
ctx.api.interact(ctx.bot, quickDoor, "Pass")
|
||||
ctx.tickDelay(16)
|
||||
|
||||
}
|
||||
|
||||
private fun isInHalls(location: Location): Boolean {
|
||||
return BALobby.isInHalls(location)
|
||||
}
|
||||
|
||||
private fun isWaitingQuick(location: Location): Boolean {
|
||||
return QUICK_START.insideBorder(location)
|
||||
}
|
||||
private fun isWaitingArea(location: Location): Boolean {
|
||||
return BALobby.isWaitingArea(location)
|
||||
}
|
||||
|
||||
}
|
||||
100
Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt
Normal file
100
Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package content.minigame.barbassault.bots
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BarbassaultState
|
||||
import content.minigame.barbassault.bots.core.BABotContext
|
||||
import content.minigame.barbassault.bots.roles.AttackerBehavior
|
||||
import content.minigame.barbassault.bots.roles.CollectorBehavior
|
||||
import content.minigame.barbassault.bots.roles.DefenderBehavior
|
||||
import content.minigame.barbassault.bots.roles.HealerBehavior
|
||||
import content.minigame.barbassault.getBARoleForPlayer
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.game.bots.AIPlayer
|
||||
import core.game.bots.CombatBotAssembler
|
||||
import core.game.bots.PvMBots
|
||||
import core.game.bots.Script
|
||||
import core.game.bots.ScriptAPI
|
||||
import core.game.container.impl.EquipmentContainer
|
||||
import core.game.global.action.EquipHandler
|
||||
import core.game.world.map.Location
|
||||
|
||||
interface RoleBehavior {
|
||||
fun tick(ctx: BABotContext)
|
||||
}
|
||||
|
||||
private class SmartBABotBrain(private val ctx: BABotContext) {
|
||||
private val lobby = LobbyBehavior()
|
||||
private val attacker = AttackerBehavior()
|
||||
private val collector = CollectorBehavior()
|
||||
private val defender = DefenderBehavior()
|
||||
private val healer = HealerBehavior()
|
||||
|
||||
private var tickTimer = 0
|
||||
|
||||
fun tick() {
|
||||
tickTimer++
|
||||
ctx.tick = tickTimer
|
||||
|
||||
if (ctx.processDelay()) return
|
||||
|
||||
ctx.session = getBASession(ctx.bot)
|
||||
|
||||
if (ctx.session?.state == BarbassaultState.IN_ARENA) {
|
||||
ctx.role = getBARoleForPlayer(ctx.bot)
|
||||
when (ctx.role) {
|
||||
BarbRole.ATTACKER -> attacker.tick(ctx)
|
||||
BarbRole.COLLECTOR -> collector.tick(ctx)
|
||||
BarbRole.DEFENDER -> defender.tick(ctx)
|
||||
BarbRole.HEALER -> healer.tick(ctx)
|
||||
null -> return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
lobby.tick(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
class SmartBABot(l: Location) : PvMBots(l) {
|
||||
private val ctx = BABotContext(this, ScriptAPI(this))
|
||||
private val brain = SmartBABotBrain(ctx)
|
||||
|
||||
init {
|
||||
(this as AIPlayer).fullRestore()
|
||||
CombatBotAssembler().gearPCiMeleeBot(this)
|
||||
|
||||
val cape = equipment.get(EquipmentContainer.SLOT_CAPE)
|
||||
if (cape != null) {
|
||||
EquipHandler.unequip(this, EquipmentContainer.SLOT_CAPE, cape.id)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
brain.tick()
|
||||
super.tick()
|
||||
}
|
||||
}
|
||||
|
||||
class SmartBAPlayerScript : Script() {
|
||||
private lateinit var brain: SmartBABotBrain
|
||||
|
||||
init {
|
||||
endDialogue = false
|
||||
preventRandomIdle = true
|
||||
}
|
||||
|
||||
override fun init(isPlayer: Boolean) {
|
||||
super.init(isPlayer)
|
||||
val ctx = BABotContext(bot, scriptAPI)
|
||||
ctx.script = this
|
||||
brain = SmartBABotBrain(ctx)
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
brain.tick()
|
||||
}
|
||||
|
||||
override fun newInstance(): Script {
|
||||
return SmartBAPlayerScript().also { it.bot = this.bot }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
package content.minigame.barbassault.bots.oldbot
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BarbassaultState
|
||||
import content.minigame.barbassault.getBARoleForPlayer
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.lobby.BALobby
|
||||
import content.minigame.barbassault.lobby.BarbassQuickWaveActivity
|
||||
import core.api.forceMove
|
||||
import core.api.getRegionBorders
|
||||
import core.api.log
|
||||
import core.game.bots.AIPlayer
|
||||
import core.game.bots.CombatBotAssembler
|
||||
import core.game.bots.PvMBots
|
||||
import core.game.bots.ScriptAPI
|
||||
import core.game.global.action.EquipHandler
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.Location
|
||||
import core.tools.Log
|
||||
import org.rs09.consts.Scenery
|
||||
|
||||
class BABot(l: Location) : PvMBots(legitimizeLocation(l)) {
|
||||
|
||||
init {
|
||||
(this as AIPlayer).fullRestore()
|
||||
CombatBotAssembler().gearPCiMeleeBot(this)
|
||||
|
||||
val cape: Item? = equipment.get(1)
|
||||
if (cape != null) {
|
||||
EquipHandler.Companion.unequip(this, 1, cape.id)
|
||||
}
|
||||
}
|
||||
|
||||
private val combatHandler = BACombatState(this)
|
||||
private var tickTimer = 0
|
||||
private var moveTimer = 0
|
||||
var hasVendingItems = false
|
||||
var scriptAPI: ScriptAPI? = null
|
||||
|
||||
enum class State { GET_TO_BA, OUTSIDE_ROOM, ENTER_ROOM, WAITING_IN_ROOM, PLAY_GAME }
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
tickTimer++
|
||||
moveTimer--
|
||||
|
||||
customState = state.name
|
||||
|
||||
if (moveTimer > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
when (state) {
|
||||
State.GET_TO_BA -> getToBA()
|
||||
State.OUTSIDE_ROOM -> outsideRoom()
|
||||
State.ENTER_ROOM -> enterRoom()
|
||||
State.WAITING_IN_ROOM -> waitingInRoom()
|
||||
State.PLAY_GAME -> playGame()
|
||||
}
|
||||
}
|
||||
|
||||
private val state: State
|
||||
get() {
|
||||
val session = getBASession(this)
|
||||
|
||||
if (session?.state == BarbassaultState.IN_ARENA) {
|
||||
return State.PLAY_GAME
|
||||
}
|
||||
if (isWaitingArea(location)) {
|
||||
return State.WAITING_IN_ROOM
|
||||
}
|
||||
|
||||
if (getClosestNodeWithEntry(2, Scenery.DOOR_20209) != null) {
|
||||
return State.ENTER_ROOM
|
||||
}
|
||||
if (isInLobbyOnly(location)) {
|
||||
return State.OUTSIDE_ROOM
|
||||
}
|
||||
return State.GET_TO_BA
|
||||
}
|
||||
|
||||
private fun getToBA() {
|
||||
teleport(BALobby.Companion.MAIN_LOBBY.randomWalkableLoc)
|
||||
moveTimer = 3
|
||||
}
|
||||
|
||||
fun useRoleVendingMachine() {
|
||||
if (hasVendingItems) return
|
||||
val roleMachine = scriptAPI?.getNearestNode(getBARoleForPlayer(this)!!.machineId, true)
|
||||
if (roleMachine?.id == Scenery.COLLECTOR_CONVERTER_21250) return
|
||||
scriptAPI?.interact(this, roleMachine, "Stock-up")
|
||||
|
||||
}
|
||||
|
||||
private fun outsideRoom() {
|
||||
val quickDoor = getClosestNodeWithEntry(60, Scenery.DOOR_20209) ?: return
|
||||
quickDoor.interaction.handle(this, quickDoor.interaction[0])
|
||||
moveTimer = 2
|
||||
}
|
||||
|
||||
|
||||
private fun enterRoom() {
|
||||
val quickDoor = getClosestNodeWithEntry(2, Scenery.DOOR_20209) ?: return
|
||||
|
||||
quickDoor.interaction.handle(this, quickDoor.interaction[0])
|
||||
|
||||
forceMove(this, location, location.transform(0, -1, 0), 25, 60, null, 819) {
|
||||
BarbassQuickWaveActivity.Companion.addToQueue(this, null)
|
||||
combatHandler.walkTo(BALobby.Companion.QUICK_START.randomWalkableLoc)
|
||||
}
|
||||
|
||||
moveTimer = 4
|
||||
}
|
||||
|
||||
private fun waitingInRoom() {
|
||||
if (tickTimer % 50 == 0) {
|
||||
combatHandler.chatter()
|
||||
}
|
||||
}
|
||||
|
||||
private fun playGame() {
|
||||
when (getBARoleForPlayer(this)) {
|
||||
BarbRole.ATTACKER -> combatHandler.fightNPCs()
|
||||
BarbRole.DEFENDER -> combatHandler.handleDefender()
|
||||
BarbRole.COLLECTOR -> combatHandler.handleCollector()
|
||||
BarbRole.HEALER -> combatHandler.handleHealer()
|
||||
null -> return
|
||||
}
|
||||
}
|
||||
|
||||
fun isInLobbyOnly(location: Location): Boolean {
|
||||
return getRegionBorders(10322).insideBorder(location)
|
||||
&& BALobby.Companion.waveLobbies.none {
|
||||
it != BALobby.Companion.MAIN_LOBBY
|
||||
&& it != BALobby.Companion.QUICK_START
|
||||
&& it.insideBorder(location)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isWaitingArea(location: Location): Boolean {
|
||||
hasVendingItems = false
|
||||
return BALobby.Companion.QUICK_START.insideBorder(location) || BALobby.Companion.waveLobbies.any { it.insideBorder(location) && it != BALobby.Companion.MAIN_LOBBY }
|
||||
}
|
||||
|
||||
fun debugthis(info : Any) {
|
||||
log(this.javaClass, Log.FINE, state.toString())
|
||||
}
|
||||
|
||||
override fun AttackNpcsInRadius(bot: Player, radius: Int): Boolean {
|
||||
if (bot.inCombat()) return true
|
||||
|
||||
val creatures = FindTargets(bot, radius)
|
||||
if (creatures.isEmpty()) return false
|
||||
|
||||
for (npc in creatures) {
|
||||
if (!npc.inCombat()) {
|
||||
bot.attack(npc)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun FindTargets(entity: Entity, radius: Int): MutableList<Entity> {
|
||||
val localNPCs = getBASession(entity)?.sessionNpcs ?: return mutableListOf()
|
||||
|
||||
return localNPCs
|
||||
.asSequence()
|
||||
.filter(::checkValidTargets)
|
||||
.sortedBy { it.location.getDistance(entity.location) }
|
||||
.take(5)
|
||||
.toMutableList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun legitimizeLocation(l: Location): Location {
|
||||
return l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package content.minigame.barbassault.bots.oldbot
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.getBARoleForPlayer
|
||||
import content.minigame.barbassault.getBASession
|
||||
import core.game.interaction.MovementPulse
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.tools.RandomFunction
|
||||
|
||||
class BACombatState(private val bot: BABot) {
|
||||
|
||||
fun fightNPCs() {
|
||||
bot.customState = "Fight NPCs"
|
||||
bot.hasVendingItems = true
|
||||
bot.AttackNpcsInRadius(bot,25)
|
||||
//use Called AttackStyle
|
||||
val baSession = getBASession(bot) ?: return
|
||||
val called = (baSession.roleCalls[BarbRole.ATTACKER]?.called ?: BarbassaultSession.AttackerStyle.values().random() ) as BarbassaultSession.AttackerStyle
|
||||
bot.properties.attackStyle = WeaponInterface.AttackStyle(called.attackStyle, WeaponInterface.BONUS_SLASH)
|
||||
|
||||
}
|
||||
|
||||
fun handleDefender() {
|
||||
bot.customState = "Lure Runners"
|
||||
bot.useRoleVendingMachine()
|
||||
|
||||
val session = getBASession(bot) ?: return
|
||||
|
||||
randomWalk(session.region.borders.randomWalkableLoc, 3)
|
||||
//used Called Lure
|
||||
}
|
||||
|
||||
fun handleCollector() {
|
||||
bot.customState = "Collecting Eggs"
|
||||
bot.hasVendingItems = true
|
||||
val session = getBASession(bot) ?: return
|
||||
|
||||
randomWalk(session.region.borders.randomWalkableLoc, 3)
|
||||
//only target Called Eggs
|
||||
}
|
||||
|
||||
fun handleHealer() {
|
||||
bot.customState = "Healing"
|
||||
bot.useRoleVendingMachine()
|
||||
val session = getBASession(bot) ?: return
|
||||
//if healing vial Empty Go fill.
|
||||
randomWalk(session.region.borders.randomWalkableLoc, 2)
|
||||
//Only use Called poisonFood.
|
||||
}
|
||||
|
||||
fun chatter() {
|
||||
val role = getBARoleForPlayer(bot)
|
||||
val messages = when (role) {
|
||||
BarbRole.ATTACKER -> listOf("Call pls","Wrong style?","Attacking!")
|
||||
BarbRole.HEALER -> listOf("Need poison","Healing!","Healer here","Call pls")
|
||||
BarbRole.DEFENDER -> listOf("Dropping food","Come here runners","Call pls")
|
||||
BarbRole.COLLECTOR -> listOf("Eggs!","Wrong egg?","Call pls")
|
||||
else -> listOf("Lag...","Nice","Oops")
|
||||
}
|
||||
|
||||
bot.sendChat(messages.random())
|
||||
}
|
||||
|
||||
fun randomWalk(center: Location, radius: Int) {
|
||||
if (!bot.hasVendingItems) return
|
||||
if (bot.walkingQueue.isMoving) return
|
||||
|
||||
|
||||
val destination = center.transform(
|
||||
RandomFunction.random(-radius, radius),
|
||||
RandomFunction.random(-radius, radius),
|
||||
0
|
||||
)
|
||||
|
||||
walkTo(destination)
|
||||
}
|
||||
|
||||
fun walkTo(destination: Location) {
|
||||
|
||||
val diffX = destination.x - bot.location.x
|
||||
val diffY = destination.y - bot.location.y
|
||||
|
||||
GameWorld.Pulser.submit(
|
||||
object : MovementPulse(
|
||||
bot,
|
||||
bot.location.transform(diffX, diffY, 0),
|
||||
Pathfinder.SMART
|
||||
) {
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
package content.minigame.barbassault.lobby
|
||||
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.getBAWave
|
||||
import content.minigame.barbassault.lobby.BarbTeamManager.abandonTeam
|
||||
import content.minigame.barbassault.lobby.BarbTeamManager.joinTeam
|
||||
import core.api.closeInterface
|
||||
import core.api.sendMessage
|
||||
import core.api.setInterfaceText
|
||||
import core.game.component.Component
|
||||
import core.game.component.ComponentDefinition
|
||||
import core.game.component.ComponentPlugin
|
||||
import core.game.node.entity.player.Player
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
|
||||
@Initializable
|
||||
class AcceptRoleInterface : ComponentPlugin() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
ComponentDefinition.forId(AcceptRole.ID).plugin = this
|
||||
return this
|
||||
}
|
||||
override fun handle(player: Player,component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int ): Boolean {
|
||||
when (button) {
|
||||
AcceptRole.AcceptButton, AcceptRole.AcceptButtonText -> { handleAccept(player); return true }
|
||||
AcceptRole.DeclineButton, AcceptRole.DeclineButtonText -> { handleDecline(player); return true }
|
||||
}
|
||||
|
||||
val slotIndex = AcceptRole.team.indexOfFirst { it.remove == button }
|
||||
if (slotIndex != -1) { handleRemove(player!!, slotIndex); return true }
|
||||
|
||||
return true
|
||||
}
|
||||
override fun open(player: Player?, component: Component?) {
|
||||
super.open(player, component)
|
||||
var isopen = true
|
||||
player ?: return
|
||||
val team = getBASession(player)?.team
|
||||
val recruit = team?.recruit?.player
|
||||
component?.setCloseEvent{ _, _ -> if (recruit != null && isopen) { closeInterface(recruit); isopen = false }; return@setCloseEvent true }
|
||||
|
||||
for (slotIndex in 0 until BarbTeam.MAX_SLOTS) {
|
||||
val uiSlot = AcceptRole.team[slotIndex]
|
||||
val partySlot: PartySlot? = team?.getSlot(slotIndex)
|
||||
val slotPlayer: Player? = partySlot?.player
|
||||
|
||||
if (slotPlayer != null) {
|
||||
val formattedRole = getBASession(player)?.team?.getRoleForPlayer(slotPlayer)?.toString()?.lowercase()?.replaceFirstChar { it.uppercase() }?: AcceptRole.defaultText
|
||||
val wave = getBAWave(slotPlayer)
|
||||
setInterfaceText(player, slotPlayer.name.capitalizeWords(), AcceptRole.ID, uiSlot.name )
|
||||
setInterfaceText(player, formattedRole, AcceptRole.ID, uiSlot.role )
|
||||
setInterfaceText(player, wave.toString(), AcceptRole.ID, uiSlot.wave )
|
||||
} else {
|
||||
setInterfaceText(player, AcceptRole.defaultText, AcceptRole.ID,uiSlot.name )
|
||||
setInterfaceText(player, AcceptRole.defaultText, AcceptRole.ID,uiSlot.role )
|
||||
setInterfaceText(player, "0", AcceptRole.ID,uiSlot.wave )
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun handleAccept(player: Player) {
|
||||
val team = getBASession(player)?.team
|
||||
val recruit = team?.recruit
|
||||
if (!recruit?.accept!!) {
|
||||
sendMessage(player,"The other player hasn't confirmed their role yet.")
|
||||
return
|
||||
}
|
||||
|
||||
val selectedRole = recruit.role ?: return
|
||||
val roleName = selectedRole.name.lowercase().replaceFirstChar { it.uppercase() }
|
||||
val rPlayer = recruit.player
|
||||
if (joinTeam(rPlayer, selectedRole)) {
|
||||
rPlayer.sendMessage("You have joined as ${roleName}.")
|
||||
team.recruit = null
|
||||
closeInterface(player)
|
||||
}
|
||||
return
|
||||
}
|
||||
private fun handleDecline(player: Player?) {
|
||||
closeInterface(player!!)
|
||||
/**
|
||||
val leader = player.baSession?.team?.getLeader()?.player
|
||||
if (leader != null && leader != player) {
|
||||
closeInterface(leader)
|
||||
}**/
|
||||
}
|
||||
private fun handleRemove(player: Player, slotIndex: Int){
|
||||
val team = getBASession(player)?.team
|
||||
val follower = team?.getSlot(slotIndex)?.player ?: return
|
||||
val uiSlot = AcceptRole.team[slotIndex]
|
||||
|
||||
sendMessage(player,"You removed the person from the team.")
|
||||
setInterfaceText(player, AcceptRole.defaultText, AcceptRole.ID,uiSlot.name )
|
||||
setInterfaceText(player, AcceptRole.defaultText, AcceptRole.ID,uiSlot.role )
|
||||
setInterfaceText(player, "0", AcceptRole.ID,uiSlot.wave )
|
||||
|
||||
abandonTeam(follower)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun updateRecruitData(player: Player){
|
||||
val team = getBASession(player)?.team
|
||||
val leader = team?.getLeader()?.player ?: return
|
||||
val recruit = team.recruit
|
||||
val displayName = recruit?.role?.name?.lowercase()?.replaceFirstChar { it.uppercase() } ?: "Unknown"
|
||||
val level = recruit?.roleLevel()
|
||||
setInterfaceText(leader, displayName, AcceptRole.ID,AcceptRole.Status.selectedRole )
|
||||
setInterfaceText(leader, level.toString(), AcceptRole.ID,AcceptRole.Status.levelRole )
|
||||
}
|
||||
fun resetWaitingStatus(player: Player){
|
||||
val leader = getBASession(player)?.team?.getLeader()?.player
|
||||
setInterfaceText(leader!!, AcceptRole.waiting, AcceptRole.ID,AcceptRole.Status.selectedRole )
|
||||
setInterfaceText(leader, AcceptRole.waiting, AcceptRole.ID,AcceptRole.Status.levelRole )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object AcceptRole {
|
||||
const val ID = 492
|
||||
const val defaultText = "none set"
|
||||
const val waiting = "Waiting ..."
|
||||
const val AcceptButtonText = 4
|
||||
const val DeclineButtonText = 2
|
||||
const val AcceptButton = 35
|
||||
const val DeclineButton = 3
|
||||
|
||||
data class Slot(val name: Int, val role: Int,val remove: Int, val wave: Int)
|
||||
|
||||
val team = listOf(
|
||||
Slot(15,20,-1,26),
|
||||
Slot(16,21,47,31),
|
||||
Slot(17,22,27,32),
|
||||
Slot(18,23,28,33),
|
||||
Slot(19,24,29,34),
|
||||
)
|
||||
object Status {
|
||||
const val selectedRole = 6
|
||||
const val levelRole = 46
|
||||
}
|
||||
}
|
||||
393
Server/src/main/content/minigame/barbassault/lobby/BALobby.kt
Normal file
393
Server/src/main/content/minigame/barbassault/lobby/BALobby.kt
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
package content.minigame.barbassault.lobby
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.arena.BarbassaultState
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.getBAWave
|
||||
import content.minigame.barbassault.lobby.BarbTeamManager.abandonTeam
|
||||
import content.minigame.barbassault.lobby.BarbTeamManager.createTeam
|
||||
import content.minigame.barbassault.lobby.BarbTeamManager.disbandTeam
|
||||
import content.minigame.barbassault.lobby.BarbassQuickWaveActivity.Companion.addToQueue
|
||||
import content.minigame.barbassault.setBASession
|
||||
import content.minigame.barbassault.setBAWave
|
||||
import core.api.*
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListener
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.impl.PulseManager
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.game.world.map.zone.ZoneRestriction
|
||||
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 BALobby : InteractionListener, MapArea {
|
||||
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> {
|
||||
return areaBorders
|
||||
}
|
||||
override fun getRestrictions(): Array<ZoneRestriction> {
|
||||
return arrayOf(ZoneRestriction.CANNON, ZoneRestriction.FIRES, ZoneRestriction.FOLLOWERS)
|
||||
}
|
||||
override fun areaEnter(entity: Entity) {
|
||||
PulseManager.cancelDeathTask(entity)
|
||||
val enteredZone = areaBorders.firstOrNull { it.insideBorder(entity.location) }
|
||||
if (enteredZone == QUICK_START) { return }
|
||||
if (enteredZone == REGION_10322) { return }
|
||||
|
||||
//updatePlayerWave(entity)
|
||||
openOverlay(entity as Player, 256)
|
||||
}
|
||||
|
||||
override fun areaLeave(entity: Entity, logout: Boolean) {
|
||||
if (entity is Player) {
|
||||
entity.interfaceManager.closeOverlay()
|
||||
}
|
||||
}
|
||||
//was used in early development.
|
||||
fun updatePlayerWave(entity: Entity) {
|
||||
val player = entity as? Player ?: return
|
||||
val location = player.location
|
||||
|
||||
if (QUICK_START.insideBorder(location)) {
|
||||
setBAWave(entity,1)
|
||||
return
|
||||
}
|
||||
for ((index, lobby) in waveLobbies.withIndex()) {
|
||||
if (lobby.insideBorder(location)) {
|
||||
if (lobby != MAIN_LOBBY) { // MAIN_LOBBY should not assign a wave number
|
||||
setBAWave(entity,index)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun capeCheck(player: Player): Boolean {
|
||||
val wornCape = getItemFromEquipment(player, EquipmentSlot.CAPE)?.id ?: -1
|
||||
if (wornCape != -1) {
|
||||
//todo find authentic "no capes allowed" message
|
||||
sendMessage(player,"Capes are not permitted.")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
//attacker 20561 : ch8
|
||||
//defender 20566 : ch10
|
||||
//collector 20563 : ch13
|
||||
//healer 20569 : ch14
|
||||
override fun defineListeners() {
|
||||
onUseWithPlayer(Items.SCROLL_10512) { leader, _, node ->
|
||||
val follower = node.asPlayer()
|
||||
val session = getBASession(leader)
|
||||
val team = session?.team
|
||||
|
||||
if (team == null) {
|
||||
leader.debug("[DEBUG] No active session found.")
|
||||
return@onUseWithPlayer false
|
||||
}
|
||||
|
||||
getBASession(follower)?.let { return@onUseWithPlayer false } // already on a team
|
||||
|
||||
team.recruit = PendingRecruit(follower)
|
||||
setBASession(follower, session)
|
||||
//leader.sendMessage(team.recruit?.player?.username ?: "null")
|
||||
// joinTeam(follower,BarbRole.DEFENDER)
|
||||
|
||||
openInterface(follower, 493)
|
||||
openInterface(leader, 492)
|
||||
|
||||
return@onUseWithPlayer true
|
||||
}
|
||||
on(Items.SCROLL_10512, IntType.ITEM, "Read") { player, _ ->
|
||||
//https://youtu.be/GYh6JPKNOSA?t=233 -- I know 2017, but only example for read scroll iv found.
|
||||
// ima cry, that YT account got deleted.
|
||||
waveAdvance(player)
|
||||
|
||||
return@on true
|
||||
}
|
||||
on(Items.SCROLL_10512, IntType.ITEM, "Write-Role") { player, _ ->
|
||||
sendDialogueOptions(player, "Which role would you like to perform?","Attacker", "Defender","Collector","Healer","Cancel")
|
||||
addDialogueAction(player) { _ , buttonId -> writeRole(player,buttonId) }
|
||||
return@on true
|
||||
}
|
||||
on(Items.SCROLL_10512, IntType.ITEM, "Clear") { player, _ ->
|
||||
if (getBASession(player)?.team != null) return@on true
|
||||
createTeam(player)
|
||||
return@on true
|
||||
}
|
||||
on(Items.SCROLL_10512, IntType.ITEM, "Destroy") { player, item ->
|
||||
player.dialogueInterpreter.sendDestroyItem(item.id, item.name)
|
||||
addDialogueAction(player) { _, button ->
|
||||
if (button == 3) {
|
||||
if (removeItem(player, item)) {
|
||||
playAudio(player, Sounds.DESTROY_OBJECT_2381)
|
||||
abandonTeam(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.LADDER_20193, IntType.SCENERY, "Climb-down") { player, _ ->
|
||||
val session = getBASession(player)
|
||||
val team = session?.team
|
||||
if (session == null) { player.debug("[DEBUG] You are not in a session!"); return@on true }
|
||||
if (team?.isLeader(player) == false) return@on true
|
||||
//todo uncomment when goes to test
|
||||
//if (team?.isFull() == false) return@on true
|
||||
if (session.state != BarbassaultState.PARTY_CREATION) { player.debug("[DEBUG] Your team is already starting or in the arena!"); return@on true }
|
||||
|
||||
closeOverlay(player) // close party
|
||||
openOverlay(player, 494) // open countdown
|
||||
|
||||
session.beginStartingPhase()
|
||||
return@on true
|
||||
}
|
||||
on(Scenery.DOOR_20209, IntType.SCENERY, "Pass") { player, node ->
|
||||
if (!capeCheck(player)) return@on false
|
||||
|
||||
// todo Not allowed to enter QuickStart with Scroll
|
||||
if (!QUICK_START.insideBorder(player.location)) {
|
||||
|
||||
if (getBAWave(player) != 1) {
|
||||
sendDialogueOptions(player,"Are you sure you wish to reset your wave progress??","Yes","No")
|
||||
addDialogueAction(player) { _, buttonId ->
|
||||
if (buttonId == 2) {
|
||||
setBAWave(player, 1)
|
||||
|
||||
handlePlayerOptionDoor(player) { role ->
|
||||
handleWaveDoor(player, node, 489)
|
||||
addToQueue(player, role)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handlePlayerOptionDoor(player) { role ->
|
||||
handleWaveDoor(player, node, 489)
|
||||
addToQueue(player, role)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handleWaveDoor(player, node, 489)
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(BARBDOORS, IntType.SCENERY, "Pass") { player, node ->
|
||||
//todo find authentic message no capes
|
||||
if (!capeCheck(player)) { sendMessage(player,"You are not allowed to wear capes."); return@on true }
|
||||
handleWaveDoor(player, node,256)
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.SCROLL_TABLE_20149, IntType.SCENERY, "Take-from") { player, _ ->
|
||||
//https://www.youtube.com/watch?v=bFw2os1aRvk
|
||||
// okay we dont create a session untill we write our name on the scroll.
|
||||
if(!player.inventory.containsItem(Item(Items.SCROLL_10512, 1)) ) {
|
||||
//do you wish to take a scroll? yes ? no
|
||||
sendDialogueOptions(player, "Take a recruitment scroll?", "Yes", "No")
|
||||
addDialogueAction(player) { _, buttonId ->
|
||||
when (buttonId) {
|
||||
2 -> {
|
||||
if (player.inventory.add(Item(Items.SCROLL_10512, 1))) {
|
||||
player.sendMessage("You take scroll from table")
|
||||
} else {
|
||||
player.sendMessage("You dont have enough inventory space")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.sendMessage("You already have a scroll")
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
//DOOR_20209
|
||||
// [Title][red] "Which role would you like to perform?"
|
||||
// [0] "Attacker"
|
||||
// [1] "Defender"
|
||||
// [2] "Collector"
|
||||
// [3] "Healer"
|
||||
// [4] "I'll be any role!"
|
||||
|
||||
|
||||
fun getRoleFromButton(button: Int): BarbRole? {
|
||||
return when (button) {
|
||||
2 -> BarbRole.ATTACKER
|
||||
3 -> BarbRole.DEFENDER
|
||||
4 -> BarbRole.COLLECTOR
|
||||
5 -> BarbRole.HEALER
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun writeRole(player: Player, buttonId: Int) {
|
||||
if (buttonId == 6) return
|
||||
val playerRole = getRoleFromButton(buttonId) ?: return
|
||||
|
||||
if (getBASession(player) == null) {createTeam(player)}
|
||||
|
||||
val team = getBASession(player)?.team ?: return
|
||||
team.setRoleForPlayer(player, playerRole)
|
||||
BarbTeamManager.updateTeam(team)
|
||||
sendMessage(player, "You've set your role to ${playerRole.name.lowercase().replaceFirstChar { it.uppercase() }}")
|
||||
|
||||
}
|
||||
|
||||
fun handlePlayerOptionDoor(player: Player, roomRoleOptions:(BarbRole?) -> Unit){
|
||||
sendDialogueOptions(player,"Which role would you like to perform?","Attacker", "Defender","Collector","Healer","I'll be any role!")
|
||||
addDialogueAction(player) { _, buttonId -> roomRoleOptions(getRoleFromButton(buttonId)) }
|
||||
}
|
||||
|
||||
fun handleWaveDoor(player: Player, node: Node,iface: Int){
|
||||
val doorLoc = node.location
|
||||
val playerLoc = player.location
|
||||
|
||||
if (getBAWave(player) != BARBWAVEDOOR[node.id]) return
|
||||
|
||||
val insideRoom = isWaitingArea(playerLoc)
|
||||
val moveY = if (insideRoom) 1 else -1
|
||||
//ToDo fix walking trough wall when Using door from side.
|
||||
forceMove(player, playerLoc, playerLoc.transform(0, moveY, 0), 25, 60, null, 819) {
|
||||
if (insideRoom) {
|
||||
//player.baSession?.cancleStartingPhase()
|
||||
abandonTeam(player)
|
||||
closeOverlay(player)
|
||||
if (node.id == Scenery.DOOR_20209) { BarbassQuickWaveActivity.removeQuickQue(player) } // needs to happen sooner
|
||||
} else {
|
||||
openOverlay(player, iface)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun isWaitingArea(location: Location): Boolean {
|
||||
return QUICK_START.insideBorder(location) || waveLobbies.any { it.insideBorder(location) && it != MAIN_LOBBY }
|
||||
}
|
||||
fun isInHalls(location: Location): Boolean {
|
||||
return getRegionBorders(10322).insideBorder(location) &&
|
||||
!QUICK_START.insideBorder(location) &&
|
||||
waveLobbies.none {
|
||||
it != MAIN_LOBBY && it.insideBorder(location)
|
||||
}
|
||||
}
|
||||
|
||||
fun TeamToLobby(team: BarbTeam, wave: Int) {
|
||||
if (wave in 0..waveLobbies.size) {
|
||||
val targetLobby = waveLobbies[wave]
|
||||
for (player in team.allPlayers()) {
|
||||
PulseManager.cancelDeathTask(player)
|
||||
teleport(player, targetLobby.randomWalkableLoc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun waveAdvance(player: Player) {
|
||||
val wave = getBAWave(player)
|
||||
if (wave in 1..waveLobbies.size) {
|
||||
if (wave == 10) {setBAWave(player,1)}
|
||||
} else {
|
||||
sendMessage(player,"Invalid wave number: $wave. PLEASE REPORT THIS!")
|
||||
}
|
||||
}
|
||||
|
||||
// Locations
|
||||
val QUICK_START: ZoneBorders = ZoneBorders(2595, 5278, 2610, 5271, 0)
|
||||
val MAIN_LOBBY: ZoneBorders = ZoneBorders(2588, 5266, 2597, 5261, 0)
|
||||
|
||||
val WAVE_LOBBY1: ZoneBorders = ZoneBorders(2576, 5298, 2583, 5291, 0)
|
||||
val WAVE_LOBBY2: ZoneBorders = ZoneBorders(2584, 5298, 2591, 5291, 0)
|
||||
|
||||
val WAVE_LOBBY3: ZoneBorders = ZoneBorders(2595, 5298, 2602, 5291, 0)
|
||||
val WAVE_LOBBY4: ZoneBorders = ZoneBorders(2603, 5298, 2610, 5291, 0)
|
||||
|
||||
|
||||
val WAVE_LOBBY5: ZoneBorders = ZoneBorders(2576, 5288, 2583, 5281, 0)
|
||||
val WAVE_LOBBY6: ZoneBorders = ZoneBorders(2584, 5288, 2591, 5281, 0)
|
||||
|
||||
val WAVE_LOBBY7: ZoneBorders = ZoneBorders(2595, 5288, 2602, 5281, 0)
|
||||
val WAVE_LOBBY8: ZoneBorders = ZoneBorders(2603, 5288, 2610, 5281, 0)
|
||||
|
||||
val WAVE_LOBBY9: ZoneBorders = ZoneBorders(2576, 5278, 2583, 5271, 0)
|
||||
val WAVE_LOBBY10: ZoneBorders = ZoneBorders(2584, 5278, 2591, 5271, 0)
|
||||
private val REGION_10322 = getRegionBorders(10322)
|
||||
|
||||
val areaBorders = arrayOf(
|
||||
QUICK_START,
|
||||
WAVE_LOBBY1,
|
||||
WAVE_LOBBY2,
|
||||
WAVE_LOBBY3,
|
||||
WAVE_LOBBY4,
|
||||
WAVE_LOBBY5,
|
||||
WAVE_LOBBY6,
|
||||
WAVE_LOBBY7,
|
||||
WAVE_LOBBY8,
|
||||
WAVE_LOBBY9,
|
||||
WAVE_LOBBY10,
|
||||
REGION_10322
|
||||
)
|
||||
val waveLobbies = listOf(
|
||||
MAIN_LOBBY,WAVE_LOBBY1, WAVE_LOBBY2, WAVE_LOBBY3, WAVE_LOBBY4,
|
||||
WAVE_LOBBY5, WAVE_LOBBY6, WAVE_LOBBY7, WAVE_LOBBY8,
|
||||
WAVE_LOBBY9, WAVE_LOBBY10
|
||||
)
|
||||
|
||||
val BARBDOORS = intArrayOf(
|
||||
Scenery.DOOR_20199,
|
||||
Scenery.DOOR_20200,
|
||||
Scenery.DOOR_20201,
|
||||
Scenery.DOOR_20202,
|
||||
Scenery.DOOR_20203,
|
||||
Scenery.DOOR_20204,
|
||||
Scenery.DOOR_20205,
|
||||
Scenery.DOOR_20206,
|
||||
Scenery.DOOR_20207,
|
||||
Scenery.DOOR_20208,
|
||||
)
|
||||
}
|
||||
val BARBWAVEDOOR = hashMapOf(
|
||||
20199 to 1,
|
||||
20200 to 2,
|
||||
20201 to 3,
|
||||
20202 to 4,
|
||||
20203 to 5,
|
||||
20204 to 6,
|
||||
20205 to 7,
|
||||
20206 to 8,
|
||||
20207 to 9,
|
||||
20208 to 10,
|
||||
20209 to 1)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
PRIVATE_PALDO_5031 -- Big axe barb at entrance to main lobby
|
||||
PRIVATE_PALDON_5034 -- sword -- Above wave 7 and 8 Source:https://youtu.be/VPlIYB1h9KM?t=340
|
||||
PRIVATE_PENDRON_5032 -- Mace -- Above arrow Guessing
|
||||
PRIVATE_PIERREB_5033 -- bowman -- Above wave 9 and 10 Source:https://youtu.be/XHp7g7dz12M?t=83
|
||||
|
||||
|
||||
DOOR_20209
|
||||
[Title][red] "Which role would you like to perform?"
|
||||
[0] "Attacker"
|
||||
[1] "Defender"
|
||||
[2] "Collector"
|
||||
[3] "Healer"
|
||||
[4] "I'll be any role!"
|
||||
SCROLL_10512 -- LeaderScroll
|
||||
QUEEN_HELP_BOOK_10562 -- Get from cain and POH bookcase
|
||||
1889 5407 - Barb assualt QUEEN area
|
||||
1891 5465 - barb assualt AREA under
|
||||
*/
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
package content.minigame.barbassault.lobby
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.lobby.BarbTeamManager.createTeam
|
||||
import content.minigame.barbassault.setBASession
|
||||
import core.api.*
|
||||
import core.game.activity.ActivityManager
|
||||
import core.game.activity.ActivityPlugin
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.game.world.map.zone.ZoneRestriction
|
||||
import core.plugin.Initializable
|
||||
import core.tools.Log
|
||||
import org.rs09.consts.Items
|
||||
|
||||
private var activity: BarbassQuickWaveActivity? = null
|
||||
|
||||
data class WaitingPlayer(val player: Player, val role: BarbRole?,val joinTime: Long = System.currentTimeMillis())
|
||||
private val waitingPlayers = mutableListOf<WaitingPlayer>()
|
||||
|
||||
private val waitingRoleCounts = mutableMapOf<BarbRole, Int>().withDefault { 0 }
|
||||
private var waitingAnyCount = 0
|
||||
|
||||
|
||||
@Initializable
|
||||
open class BarbassQuickWaveActivity : ActivityPlugin("BarbassQuickWave",false, false, true,
|
||||
ZoneRestriction.CANNON, ZoneRestriction.FIRES, ZoneRestriction.FOLLOWERS, ZoneRestriction.RANDOM_EVENTS), MapArea {
|
||||
|
||||
init { activity = this; this.safeRespawn = Location.create(2593, 5264, 0) }
|
||||
|
||||
private fun tryCreateTeamFromQueue(): Boolean {
|
||||
|
||||
if (waitingPlayers.size < 5) return false
|
||||
|
||||
val remaining = waitingPlayers.sortedBy { it.joinTime }.toMutableList()
|
||||
|
||||
val selected = mutableListOf<WaitingPlayer>()
|
||||
|
||||
fun takeForRole(role: BarbRole): WaitingPlayer? {
|
||||
val exact = remaining.firstOrNull { it.role == role }
|
||||
if (exact != null) {
|
||||
remaining.remove(exact)
|
||||
return exact
|
||||
}
|
||||
|
||||
val any = remaining.firstOrNull { it.role == null }
|
||||
if (any != null) {
|
||||
remaining.remove(any)
|
||||
return any.copy(role = role)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
for (role in BarbRole.values()) {
|
||||
val picked = takeForRole(role) ?: return false
|
||||
selected.add(picked)
|
||||
}
|
||||
|
||||
val fifth = remaining.firstOrNull() ?: return false
|
||||
remaining.remove(fifth)
|
||||
val assignedFifth = if (fifth.role == null) { fifth.copy(role = BarbRole.ATTACKER) } else fifth
|
||||
selected.add(assignedFifth)
|
||||
|
||||
createQuickTeam(selected)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun giveScroll(player: Player): Boolean {
|
||||
if (!player.inventory.containsItem(Item(Items.SCROLL_10512, 1))) {
|
||||
return player.inventory.add(Item(Items.SCROLL_10512, 1))
|
||||
}
|
||||
return true
|
||||
}
|
||||
//todo Make Game Start Faster once a team is created.
|
||||
private fun createQuickTeam(players: List<WaitingPlayer>) {
|
||||
// if(player == null) {removeQuickQue(player);return}
|
||||
var teamLeader: Player? = null
|
||||
for (wp in players) {
|
||||
if(wp.player.isArtificial) continue //only players can lead a party.
|
||||
if (giveScroll(wp.player)) {
|
||||
teamLeader = wp.player
|
||||
break
|
||||
}
|
||||
}
|
||||
//IF BY CHANCE no one had free inventory space KICK THEM ALL FROM QuickLobby!
|
||||
// I should just return them to the que, at the end instead
|
||||
if (teamLeader == null) {
|
||||
players.forEach {
|
||||
sendMessage(it.player, "You could not hold a Scroll and have been removed from queue")
|
||||
it.player.teleport(Location.create(2602, 5279, 0))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (createTeam(teamLeader)){
|
||||
players.forEach { removeQuickQue(it.player) }
|
||||
|
||||
val session = getBASession(teamLeader)
|
||||
val team = session?.team ?: return
|
||||
|
||||
players.forEachIndexed { index, wrapper ->
|
||||
wrapper.let { playerWrapper ->
|
||||
if (wrapper.player != teamLeader) {
|
||||
setBASession(playerWrapper.player,session)
|
||||
team.addPlayer(playerWrapper.player)
|
||||
}
|
||||
playerWrapper.role?.let { role ->
|
||||
team.setRoleForPlayer(playerWrapper.player, role)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session.beginStartingPhase(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure() {
|
||||
GameWorld.Pulser.submit(
|
||||
object : Pulse(25) {
|
||||
override fun pulse(): Boolean {
|
||||
if (waitingPlayers.isNotEmpty()) {
|
||||
tryCreateTeamFromQueue()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
override fun death(e: Entity?, killer: Entity?): Boolean {
|
||||
val ename = e?.name
|
||||
log(this.javaClass, Log.FINE,"$ename has died in Barbass Lobby, HOW? killer:${killer?.name}")
|
||||
e!!.getProperties().setTeleportLocation(null)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun newInstance(p: Player?): ActivityPlugin {
|
||||
ActivityManager.register(this)
|
||||
return this
|
||||
}
|
||||
//override when !2265 passes (void recovery)
|
||||
fun recover(player: Player){
|
||||
//do nothing, not lost
|
||||
}
|
||||
|
||||
override fun getSpawnLocation(): Location {
|
||||
return Location.create(2593, 5264, 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun removeQuickQue(player: Player){
|
||||
val toRemove = waitingPlayers.filter { it.player == player }
|
||||
waitingPlayers.removeAll(toRemove)
|
||||
|
||||
toRemove.forEach { wp ->
|
||||
if (wp.role == null) waitingAnyCount--
|
||||
else waitingRoleCounts[wp.role] = waitingRoleCounts.getValue(wp.role) - 1
|
||||
}
|
||||
|
||||
refreshQuickWaveOverlay()
|
||||
}
|
||||
|
||||
fun addToQueue(player: Player, role: BarbRole?) {
|
||||
waitingPlayers.add(WaitingPlayer(player, role))
|
||||
|
||||
if (role == null) waitingAnyCount++
|
||||
else waitingRoleCounts[role] = waitingRoleCounts.getValue(role) + 1
|
||||
|
||||
//todo find authentic message for Quick Start Wave BarbAssault, If there even is one.
|
||||
val roleText = role?.name ?: "ANY"
|
||||
sendMessage(player, "You've joined the queue as ${roleText.lowercase().replaceFirstChar { it.uppercase() }}.")
|
||||
refreshQuickWaveOverlay()
|
||||
}
|
||||
private fun refreshQuickWaveOverlay() {
|
||||
waitingPlayers.forEach {
|
||||
val itplayer = it.player
|
||||
setInterfaceText(itplayer, (waitingRoleCounts[BarbRole.ATTACKER] ?: 0).toString(), 489, 6)
|
||||
setInterfaceText(itplayer, (waitingRoleCounts[BarbRole.DEFENDER] ?: 0).toString(), 489, 7)
|
||||
setInterfaceText(itplayer, (waitingRoleCounts[BarbRole.COLLECTOR] ?: 0).toString(), 489, 8)
|
||||
setInterfaceText(itplayer, (waitingRoleCounts[BarbRole.HEALER] ?: 0).toString(), 489, 9)
|
||||
setInterfaceText(itplayer, waitingAnyCount.toString(), 489, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* override fun areaEnter(entity: Entity) {
|
||||
enter(entity)
|
||||
}
|
||||
|
||||
override fun areaLeave(entity: Entity, logout: Boolean) {
|
||||
leave(entity,logout)
|
||||
super.areaLeave(entity, logout)
|
||||
}
|
||||
|
||||
override fun enter(e: Entity?): Boolean {
|
||||
return super.enter(e)
|
||||
}
|
||||
|
||||
override fun leave(e: Entity?, logout: Boolean): Boolean {
|
||||
return super.leave(e, logout)
|
||||
}*/
|
||||
override fun defineAreaBorders(): Array<ZoneBorders> {
|
||||
return arrayOf(getRegionBorders(10322))
|
||||
}
|
||||
}
|
||||
169
Server/src/main/content/minigame/barbassault/lobby/BATeam.kt
Normal file
169
Server/src/main/content/minigame/barbassault/lobby/BATeam.kt
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
package content.minigame.barbassault.lobby
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.BAActivity
|
||||
import content.minigame.barbassault.arena.BarbassaultSession
|
||||
import content.minigame.barbassault.arena.BarbassaultState
|
||||
import content.minigame.barbassault.getBALevels
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.getBAWave
|
||||
import content.minigame.barbassault.setBASession
|
||||
import core.api.sendMessage
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.map.Location
|
||||
|
||||
data class PartySlot( val index: Int, val player: Player, var role: BarbRole? = null )
|
||||
data class PendingRecruit( var player: Player, var role: BarbRole? = null,var accept:Boolean = false ) {
|
||||
fun roleLevel(): Int = when (role) {
|
||||
BarbRole.ATTACKER -> getBALevels(player).atk
|
||||
BarbRole.COLLECTOR -> getBALevels(player).col
|
||||
BarbRole.DEFENDER -> getBALevels(player).def
|
||||
BarbRole.HEALER -> getBALevels(player).heal
|
||||
null -> 1
|
||||
}
|
||||
}
|
||||
|
||||
private val PartySpawns = arrayOf(30 to 18, 29 to 17, 31 to 17, 28 to 16, 32 to 16)
|
||||
|
||||
class BarbTeam(val session: BarbassaultSession, leader: Player) {
|
||||
companion object {
|
||||
const val MAX_SLOTS = 5
|
||||
const val LEADER_SLOT = 0
|
||||
}
|
||||
var wave = 1
|
||||
var recruit: PendingRecruit? = null
|
||||
private val slots: Array<PartySlot?> = arrayOfNulls(MAX_SLOTS)
|
||||
|
||||
init { slots[LEADER_SLOT] = PartySlot(LEADER_SLOT, leader); wave = getBAWave(leader)!! }
|
||||
|
||||
fun slotOf(player: Player): Int = slots.indexOfFirst { it?.player == player }
|
||||
fun getSlot(index: Int): PartySlot? = slots.getOrNull(index)
|
||||
fun allPlayers(): List<Player> = slots.filterNotNull().map { it.player }
|
||||
fun isLeader(player: Player): Boolean = slotOf(player) == LEADER_SLOT
|
||||
fun isHealer(player: Player): Boolean = getRoleForPlayer(player) == BarbRole.HEALER
|
||||
fun isFull(): Boolean = slots.all { it != null }
|
||||
|
||||
fun addPlayer(player: Player): Boolean {
|
||||
if (slotOf(player) != -1) return false
|
||||
|
||||
val freeIndex = slots.indexOfFirst { it == null }
|
||||
if (freeIndex == -1) return false
|
||||
|
||||
slots[freeIndex] = PartySlot(freeIndex, player)
|
||||
return true
|
||||
}
|
||||
|
||||
fun removePlayer(player: Player) {
|
||||
val idx = slotOf(player)
|
||||
if (idx == -1) return
|
||||
slots[idx] = null
|
||||
}
|
||||
|
||||
fun setRoleForPlayer(player: Player, role: BarbRole): Boolean {
|
||||
val idx = slotOf(player)
|
||||
if (idx == -1) return false
|
||||
|
||||
slots[idx]?.role = role
|
||||
allPlayers().forEach { updateRoleAvailabilityFor(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
fun getPlayersByRole(barbRole: BarbRole): List<Player> = slots.filterNotNull().map { it.player }.filter { getRoleForPlayer(it) == barbRole }
|
||||
fun getRoleForPlayer(player: Player): BarbRole = slots.getOrNull(slotOf(player))?.role!!
|
||||
fun getLeader(): PartySlot? = slots[0]
|
||||
|
||||
fun roleCounts(): RoleCounts {
|
||||
var counts = RoleCounts(0, 0, 0, 0)
|
||||
|
||||
slots.forEach { slot ->
|
||||
when (slot?.role) {
|
||||
BarbRole.ATTACKER -> counts.att++
|
||||
BarbRole.DEFENDER -> counts.def++
|
||||
BarbRole.COLLECTOR -> counts.coll++
|
||||
BarbRole.HEALER -> counts.heal++
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
|
||||
return RoleCounts(counts.att, counts.def, counts.coll, counts.heal)
|
||||
}
|
||||
fun updateRoleAvailabilityFor(player: Player) = updateRoleAvailability(roleCounts(),assignedRoleCount(),player )
|
||||
fun assignedRoleCount(): Int = slots.count { it?.role != null }
|
||||
|
||||
fun spawnLocationFor(player: Player): Location {
|
||||
val (x, y) = PartySpawns[slotOf(player)]
|
||||
return session.base.transform(x, y, 0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class RoleCounts(var att: Int, var def: Int, var coll: Int, var heal: Int )
|
||||
object BarbTeamManager {
|
||||
fun createTeam(leader: Player): Boolean {
|
||||
val session = BAActivity.createSession(leader)
|
||||
val team = BarbTeam(session, leader)
|
||||
session.team = team
|
||||
|
||||
leader.debug("[DEBUG] TeamCreated")
|
||||
updateTeam(team)
|
||||
return true
|
||||
}
|
||||
|
||||
fun disbandTeam(session: BarbassaultSession) {
|
||||
val team = session.team
|
||||
|
||||
team.allPlayers().forEach {
|
||||
it.sendMessage("Your leader has left the room and therefore cleared the team!")
|
||||
it.removeAttribute("ba-session")
|
||||
updateCurrentTeam(it)
|
||||
//todo Do not forget to remove this latter.
|
||||
if (session.state == BarbassaultState.STARTING) {
|
||||
it.properties.teleportLocation = Location.create(2593, 5264, 0)
|
||||
}
|
||||
}
|
||||
session.endSession()
|
||||
}
|
||||
|
||||
fun joinTeam(player: Player, role: BarbRole): Boolean {
|
||||
val session = getBASession(player) ?: return false
|
||||
val team = session.team
|
||||
team.recruit = null
|
||||
if (!team.addPlayer(player)) {
|
||||
player.debug("[DEBUG] That party is full.")
|
||||
return false
|
||||
}
|
||||
team.setRoleForPlayer(player, role)
|
||||
team.allPlayers().forEach {
|
||||
updateCurrentTeam(it)
|
||||
if (it != player)
|
||||
it.sendMessage("Your application has been accepted")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun abandonTeam(player: Player) {
|
||||
val session = getBASession(player) ?: return
|
||||
val team = session.team
|
||||
if (team.isLeader(player)) {
|
||||
disbandTeam(session)
|
||||
return
|
||||
}
|
||||
team.removePlayer(player)
|
||||
setBASession(player,null)
|
||||
updateCurrentTeam(player)
|
||||
updateTeam(team)
|
||||
//session.cancleStartingPhase()
|
||||
}
|
||||
|
||||
fun updateTeam(team: BarbTeam) = team.allPlayers().forEach { updateCurrentTeam(it) }
|
||||
|
||||
}
|
||||
|
||||
//Leader leaving room and causing disband "Your leader has left the room and therefore cleared the team!"
|
||||
// //"Your recruiter exited the room."
|
||||
//Accpting invite text " Your application has been accepted"
|
||||
//The applicant declined your offer.
|
||||
|
||||
//the other player hasn't confirmed their role yet.
|
||||
//the applicant has chosen a role.0
|
||||
//You removed the person from the team.
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package content.minigame.barbassault.lobby
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.lobby.CurrentTeam.ROLE_MODEL_MAP
|
||||
import content.minigame.barbassault.lobby.CurrentTeam.modelZoom
|
||||
import core.api.setInterfaceModel
|
||||
import core.api.setInterfaceText
|
||||
import core.game.component.Component
|
||||
import core.game.component.ComponentDefinition
|
||||
import core.game.component.ComponentPlugin
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
import org.rs09.consts.Items
|
||||
|
||||
@Initializable
|
||||
//not used delete this plugin latter
|
||||
class CurrentTeamInterface : ComponentPlugin() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
ComponentDefinition.forId(CurrentTeam.ID).plugin = this
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?,component: Component?,opcode: Int,button: Int,slot: Int,itemId: Int ): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun open(player: Player?, component: Component?) {
|
||||
super.open(player, component)
|
||||
player ?: return
|
||||
if(player.inventory.containsItem(Item(Items.SCROLL_10512, 1)) ) {
|
||||
// setInterfaceText(player, player.username, CurrentTeam.ID, CurrentTeam.team[0].name)
|
||||
//we dont become leaders if we own a scroll , we become one when we write our name on scroll.
|
||||
}
|
||||
}
|
||||
}
|
||||
fun updateCurrentTeam(player: Player) {
|
||||
val team = getBASession(player)?.team
|
||||
|
||||
for (slotIndex in 0 until BarbTeam.MAX_SLOTS) {
|
||||
val uiSlot = CurrentTeam.team[slotIndex]
|
||||
val partySlot = team?.getSlot(slotIndex)
|
||||
val slotPlayer = partySlot?.player
|
||||
val slotRole = partySlot?.role
|
||||
|
||||
val nameText = slotPlayer?.username?.capitalizeWords() ?: CurrentTeam.defaultText
|
||||
val model = slotRole?.let { ROLE_MODEL_MAP[it] } ?: -1
|
||||
setInterfaceText(player, nameText, CurrentTeam.ID, uiSlot.name)
|
||||
setInterfaceModel(player, model, CurrentTeam.ID, uiSlot.role, modelZoom)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun String.capitalizeWords(): String = split('_').joinToString("_") { it.replaceFirstChar { c -> c.uppercaseChar() } }
|
||||
|
||||
object CurrentTeam {
|
||||
const val ID = 256
|
||||
val defaultText = "-----"
|
||||
val modelZoom = 2372
|
||||
val ROLE_MODEL_MAP = mapOf(BarbRole.ATTACKER to 20561,BarbRole.COLLECTOR to 20563,BarbRole.DEFENDER to 20566,BarbRole.HEALER to 20569)
|
||||
data class Slot(val role: Int, val name: Int)
|
||||
val team = listOf(
|
||||
Slot(16, 6),
|
||||
Slot(17, 7),
|
||||
Slot(18, 8),
|
||||
Slot(19, 9),
|
||||
Slot(20, 10)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package content.minigame.barbassault
|
||||
|
||||
import core.api.animate
|
||||
import core.api.sendMessage
|
||||
import core.game.dialogue.DialoguePlugin
|
||||
import core.game.dialogue.FacialExpression
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.plugin.Initializable
|
||||
import core.tools.END_DIALOGUE
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
@Initializable
|
||||
class PrivatesDialogues(player: Player? = null) : DialoguePlugin(player){
|
||||
|
||||
val NPCtoDialogStage = mapOf(
|
||||
NPCs.PRIVATE_PALDON_5034 to 1,
|
||||
NPCs.PRIVATE_PALDO_5031 to 6,
|
||||
NPCs.PRIVATE_PIERREB_5033 to 11,
|
||||
NPCs.PRIVATE_PENDRON_5032 to 20,
|
||||
|
||||
)
|
||||
val PRIVATES: IntArray = NPCtoDialogStage.keys.toIntArray()
|
||||
|
||||
override fun newInstance(player: Player?): DialoguePlugin {
|
||||
return PrivatesDialogues(player)
|
||||
}
|
||||
|
||||
override fun open(vararg args: Any?): Boolean {
|
||||
val currentNPC = args[0] as NPC
|
||||
npc = currentNPC
|
||||
stage = NPCtoDialogStage[currentNPC.id] ?: -1
|
||||
sendMessage(player, stage.toString())
|
||||
handle(0,0)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override fun handle(componentID: Int, buttonID: Int): Boolean {
|
||||
when (stage) {
|
||||
//PRIVATE_PALDON
|
||||
1 -> playerl(FacialExpression.FRIENDLY, "Hi.").also { stage++ }
|
||||
2 -> npcl(FacialExpression.ANNOYED, "Shhh. Don't talk to me.").also { stage++ }
|
||||
3 -> playerl(FacialExpression.THINKING, "What? Why?").also { stage++ }
|
||||
4 -> npcl(FacialExpression.AFRAID, "If I'm seen slacking off by talking to you, I'll be in deep trouble!").also { stage++ }
|
||||
5 -> playerl(FacialExpression.WORRIED, "Oh... Sorry.").also { stage = END_DIALOGUE}
|
||||
//PRIVATE_PALDO
|
||||
6 -> playerl(FacialExpression.FRIENDLY, "Hi, soldier..").also { stage++ }
|
||||
7 -> npcl(FacialExpression.FRIENDLY, "Why, hello there!").also { stage++ }
|
||||
8 -> playerl(FacialExpression.THINKING, "You seem like a jolly chap.").also { stage++ }
|
||||
9 -> npcl(FacialExpression.FRIENDLY, "And why not? 'Tis a greeeaat day!").also { stage++ }
|
||||
10 -> playerl(FacialExpression.FRIENDLY, "Well, I suppose it is.").also { stage = END_DIALOGUE }
|
||||
//PRIVATE_PIERREB
|
||||
11 -> playerl(FacialExpression.ASKING, "Hello. So you're just a private?").also { stage++ }
|
||||
12 -> npcl(FacialExpression.ANGRY, "Show some respect! It's more than you'll achieve.").also { stage++}
|
||||
13 -> playerl(FacialExpression.ANNOYED, "I beg to differ. I'm in perfect shape!").also { stage++ }
|
||||
14 -> npcl(FacialExpression.ANGRY, "Prove it!").also { stage++}
|
||||
15 -> playerl(FacialExpression.ASKING, "How?").also { stage++ }
|
||||
16 -> npcl(FacialExpression.ANGRY, "Give me five star-jumps!").also {
|
||||
animate(player, Animation(2761))
|
||||
stage++
|
||||
}
|
||||
17 -> npcl(FacialExpression.ANGRY, "Five sit-ups.").also {
|
||||
animate(player, Animation(2763))
|
||||
stage++
|
||||
}
|
||||
18 -> npcl(FacialExpression.ANGRY, "Run on the spot!").also {
|
||||
animate(player, Animation(2764))
|
||||
stage++
|
||||
}
|
||||
19 -> npcl(FacialExpression.THINKING, "Okay. Maybe you have what it takes. Best you speak with the captain.").also { stage = END_DIALOGUE }
|
||||
//PRIVATE_PENDRON
|
||||
20 -> playerl(FacialExpression.FRIENDLY, "Hi there.").also { stage++ }
|
||||
21 -> npcl(FacialExpression.ASKING, "Don't suppose you've seen a battleaxe around here?").also { stage++ }
|
||||
22 -> playerl(FacialExpression.FRIENDLY, "A battleaxe? Nope, afraid not.").also { stage++ }
|
||||
23 -> npcl(FacialExpression.WORRIED, "the captain is going to kill me if he finds out I've lost my weapon.").also { stage = END_DIALOGUE }
|
||||
}
|
||||
return true
|
||||
}
|
||||
override fun getIds(): IntArray {
|
||||
return PRIVATES
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
package content.minigame.barbassault.lobby
|
||||
|
||||
import content.minigame.barbassault.BarbRole
|
||||
import content.minigame.barbassault.getBASession
|
||||
import content.minigame.barbassault.setBASession
|
||||
import core.api.*
|
||||
import core.game.component.Component
|
||||
import core.game.component.ComponentDefinition
|
||||
import core.game.component.ComponentPlugin
|
||||
import core.game.node.entity.player.Player
|
||||
import core.plugin.Initializable
|
||||
import core.plugin.Plugin
|
||||
|
||||
@Initializable
|
||||
class RoleSelectInterface : ComponentPlugin() {
|
||||
override fun open(player: Player?, component: Component?) {
|
||||
super.open(player, component)
|
||||
var isopen = true
|
||||
player ?: return
|
||||
val team = getBASession(player)?.team;
|
||||
if (team != null) { team.updateRoleAvailabilityFor(player) }
|
||||
|
||||
component?.setCloseEvent { player, c ->
|
||||
val leader = team?.getLeader()?.player;
|
||||
|
||||
if (leader != null && leader != player && isopen) {
|
||||
isopen = false
|
||||
closeInterface(leader)
|
||||
//if team.recruit not on team, team.recruit?.player?.baSession = null
|
||||
(team.recruit?.player )?.let { setBASession(it ,null) }
|
||||
team.recruit = null
|
||||
}
|
||||
return@setCloseEvent true
|
||||
}
|
||||
|
||||
val leaderData = getBASession(player)?.team?.getLeader() ?: run {
|
||||
player.sendMessage("No leader found for your team.")
|
||||
return
|
||||
}
|
||||
setInterfaceText(player, leaderData!!.player.name.capitalizeWords(),SelectRole.ID,SelectRole.Leader.name)
|
||||
setInterfaceText(player, leaderData.role.toString(),SelectRole.ID,SelectRole.Leader.role)
|
||||
setInterfaceText(player,"0",SelectRole.ID,SelectRole.Leader.wave)
|
||||
|
||||
}
|
||||
|
||||
var selectedButton = -1
|
||||
val roleButtons = mapOf( SelectRole.Att to listOf(8, 9), SelectRole.Def to listOf(10, 11), SelectRole.Col to listOf(12, 13),SelectRole.Heal to listOf(14,15) )
|
||||
val buttonRoleMap = roleButtons.flatMap { (role, buttons) -> buttons.map { it to role }}.toMap()
|
||||
val selectRoleToBarbRole = mapOf(SelectRole.Att to BarbRole.ATTACKER,SelectRole.Def to BarbRole.DEFENDER, SelectRole.Col to BarbRole.COLLECTOR, SelectRole.Heal to BarbRole.HEALER )
|
||||
|
||||
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
|
||||
if (player == null) return true
|
||||
val team = getBASession(player)?.team;
|
||||
val pending = team?.recruit ?: return true
|
||||
var waitingSelected: BarbRole? = null
|
||||
|
||||
when (button) {
|
||||
SelectRole.AcceptButton, SelectRole.AcceptButtonText -> {
|
||||
val selectedRole = pending.role
|
||||
val selectedRoleName = selectedRole?.name?.lowercase()?.replaceFirstChar { it.uppercase() }
|
||||
if (selectedRole != null) {
|
||||
waitingSelected = selectedRole
|
||||
AcceptRoleInterface.updateRecruitData(player)
|
||||
if (!pending.accept) {team.getLeader()?.player?.sendMessages("The applicant has chosen $selectedRoleName")}
|
||||
pending.accept = true
|
||||
} else {
|
||||
player.sendMessage("You must select a role first!")
|
||||
}
|
||||
return true
|
||||
}
|
||||
SelectRole.DeclineButton, SelectRole.DeclineButtonText -> {
|
||||
handleDecline(player)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
val clickedSelectRole = buttonRoleMap[button]
|
||||
if (clickedSelectRole != null && clickedSelectRole.isActive) {
|
||||
pending.role = selectRoleToBarbRole[clickedSelectRole]
|
||||
if (pending.role != waitingSelected ) {
|
||||
pending.accept = false
|
||||
AcceptRoleInterface.resetWaitingStatus(player)
|
||||
}
|
||||
|
||||
val displayName = pending.role?.name?.capitalizeWords() ?: "Unknown"
|
||||
setInterfaceText(player, displayName, SelectRole.ID, SelectRole.Status.CurrentRole)
|
||||
selectedButton = button
|
||||
} else {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
ComponentDefinition.forId(SelectRole.ID).plugin = this
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
fun updateRoleAvailability( counts: RoleCounts, partySize: Int, player: Player ) {
|
||||
fun canAdd(current: Int, missingRoles: Int): Boolean {
|
||||
if (partySize >= 5) return false
|
||||
if (current >= 2) return false
|
||||
|
||||
val remainingSlots = 5 - (partySize + 1)
|
||||
return remainingSlots >= missingRoles
|
||||
}
|
||||
|
||||
val missingRoles = listOf(counts.att, counts.def, counts.coll, counts.heal ).count { it == 0 }
|
||||
|
||||
setRoleActive( SelectRole.Att, canAdd( counts.att, if ( counts.att == 0) maxOf(0, missingRoles - 1) else missingRoles ), player )
|
||||
setRoleActive( SelectRole.Def, canAdd( counts.def, if ( counts.def == 0) maxOf(0, missingRoles - 1) else missingRoles ), player )
|
||||
setRoleActive( SelectRole.Col, canAdd( counts.coll,if (counts.coll == 0) maxOf(0, missingRoles - 1) else missingRoles ), player )
|
||||
setRoleActive(SelectRole.Heal, canAdd( counts.heal,if (counts.heal == 0) maxOf(0, missingRoles - 1) else missingRoles ), player )
|
||||
}
|
||||
|
||||
private fun setRoleActive(role: SelectRole.Role, active: Boolean, player: Player) {
|
||||
role.setActive(active)
|
||||
setInterfaceModel(player,role.model,SelectRole.ID,role.componentId,0)
|
||||
setComponentVisibility(player,SelectRole.ID,role.activeChild,!role.isActive)
|
||||
}
|
||||
private fun handleAccept(player: Player){
|
||||
return
|
||||
}
|
||||
private fun handleDecline(player: Player) {
|
||||
val leader = getBASession(player)?.team?.getLeader()?.player
|
||||
sendMessage(leader!!, "The applicant declined your offer.")
|
||||
closeInterface(player)
|
||||
}
|
||||
|
||||
|
||||
object SelectRole {
|
||||
const val ID = 493
|
||||
const val AcceptButton = 16
|
||||
const val AcceptButtonText = 17
|
||||
const val DeclineButton = 18
|
||||
const val DeclineButtonText = 7
|
||||
|
||||
|
||||
class Role(val roleName: String, val componentId: Int, val activeModel: Int, val inactiveModel: Int, val activeChild: Int) {
|
||||
var isActive: Boolean = false; private set
|
||||
fun setActive(active: Boolean) { isActive = active }
|
||||
val model: Int get() = if (isActive) activeModel else inactiveModel
|
||||
}
|
||||
|
||||
val Att = Role("Attacker",8, 20561, 20560, 20)
|
||||
val Def = Role("Defender",10, 20566, 20567, 55)
|
||||
val Col = Role("Collector",13, 20563, 20564, 54)
|
||||
val Heal = Role("Healer", 14, 20569, 20570, 53)
|
||||
|
||||
data class Slot(val name: Int, val role: Int, val wave: Int)
|
||||
val Leader = Slot(28, 33, 39)
|
||||
val Followers = listOf(
|
||||
Slot(29, 34, 40),
|
||||
Slot(30, 35, 41),
|
||||
Slot(31, 36, 42),
|
||||
Slot(32, 37, 43),
|
||||
)
|
||||
|
||||
object Status {
|
||||
const val CurrentRole = 19
|
||||
const val WaitingForAccept = 22
|
||||
}
|
||||
}
|
||||
|
|
@ -65,7 +65,16 @@ class FOGRewardsInterface : ComponentPlugin(){
|
|||
return this
|
||||
}
|
||||
|
||||
private fun handleOpcode(item: ShopItem, opcode: Int, player: Player){
|
||||
private fun handleOpcode(item: ShopItem, opcode: Int, player: Player) {
|
||||
if (item.id in shopsaleone) {
|
||||
handleSaleOneOpcode(item,opcode, player)
|
||||
} else {
|
||||
handleOGOpcode(item,opcode, player)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun handleOGOpcode(item: ShopItem, opcode: Int, player: Player){
|
||||
when(opcode){
|
||||
155 -> player.sendMessage("${ItemDefinition.forId(item.id).name.replace("100","")}: costs ${item.price} tokens.")
|
||||
196 -> handleBuyOption(item,1,player)
|
||||
|
|
@ -75,6 +84,14 @@ class FOGRewardsInterface : ComponentPlugin(){
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleSaleOneOpcode(item: ShopItem, opcode: Int, player: Player) {
|
||||
when (opcode) {
|
||||
155 -> player.sendMessage("${ItemDefinition.forId(item.id).name.replace("100","")}: costs ${item.price} tokens.")
|
||||
196 -> handleBuyOption(item,1,player)
|
||||
124 -> player.sendMessage(ItemDefinition.forId(item.id).examine.replace("100",""))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBuyOption(item: ShopItem, amount: Int, player: Player){
|
||||
val neededTokens = Item(12852,item.price * amount)
|
||||
if(player.inventory.containsItem(neededTokens)){
|
||||
|
|
@ -88,39 +105,41 @@ class FOGRewardsInterface : ComponentPlugin(){
|
|||
}
|
||||
|
||||
|
||||
val Druidic_Mage_Top = (ShopItem(12894, 300, 1))
|
||||
val Druidic_Mage_Hood = (ShopItem(12887, 100, 1))
|
||||
val Druidic_Mage_Bottom = (ShopItem(12901, 200, 1))
|
||||
val Combat_Robe_Top = (ShopItem(12971, 150, 1))
|
||||
val Combat_Robe_Hood = (ShopItem(12964, 50, 1))
|
||||
val Combat_Robe_Bottom = (ShopItem(12978, 100, 1))
|
||||
val Battle_Robe_Hood = (ShopItem(12866, 250, 1))
|
||||
val Battle_Robe_Top = (ShopItem(12873, 1500, 1))
|
||||
val Battle_Robe_Bottom = (ShopItem(12880, 1000, 1))
|
||||
val Green_Coif = (ShopItem(12936, 150, 1))
|
||||
val Blue_Coif = (ShopItem(12943, 200, 1))
|
||||
val Red_Coif = (ShopItem(12950, 300, 1))
|
||||
val Black_Coif = (ShopItem(12957, 500, 1))
|
||||
val Bronze_Gaunt = (ShopItem(12985, 15, 1))
|
||||
val Iron_Gaunt = (ShopItem(12988, 30, 1))
|
||||
val Steel_Gaunt = (ShopItem(12991, 50, 1))
|
||||
val Black_Gaunt = (ShopItem(12994, 75, 1))
|
||||
val Mithril_Gaunt = (ShopItem(12997, 100, 1))
|
||||
val Adamant_Gaunt = (ShopItem(13000, 150, 1))
|
||||
val Rune_Gaunt = (ShopItem(13003, 200, 1))
|
||||
val Dragon_Gaunt = (ShopItem(13006, 300, 1))
|
||||
val Addy_Spike = (ShopItem(12908, 50, 1))
|
||||
val Addy_Beserk = (ShopItem(12915, 100, 1))
|
||||
val Rune_Spike = (ShopItem(12922, 200, 1))
|
||||
val Rune_Beserk = (ShopItem(12929, 300, 1))
|
||||
val Air_Gloves = (ShopItem(12863, 75, 1))
|
||||
val Water_Gloves = (ShopItem(12864, 75, 1))
|
||||
val Earth_Gloves = (ShopItem(12865, 75, 1))
|
||||
val Irit_Gloves = (ShopItem(12856, 75, 1))
|
||||
val Avantoe_Gloves = (ShopItem(12857, 100, 1))
|
||||
val Kwuarm_Gloves = (ShopItem(12858, 200, 1))
|
||||
val Cadantine_Gloves = (ShopItem(12859, 200, 1))
|
||||
val Swordfish_Gloves = (ShopItem(12860, 200, 1))
|
||||
val Shark_Gloves = (ShopItem(12861, 200, 1))
|
||||
val Dragon_Gloves = (ShopItem(12862, 200, 1))
|
||||
val Druidic_Mage_Top = (ShopItem(12894, 300, 1))
|
||||
val Druidic_Mage_Hood = (ShopItem(12887, 100, 1))
|
||||
val Druidic_Mage_Bottom = (ShopItem(12901, 200, 1))
|
||||
val Combat_Robe_Top = (ShopItem(12971, 150, 1))
|
||||
val Combat_Robe_Hood = (ShopItem(12964, 50, 1))
|
||||
val Combat_Robe_Bottom = (ShopItem(12978, 100, 1))
|
||||
val Battle_Robe_Hood = (ShopItem(12866, 250, 1))
|
||||
val Battle_Robe_Top = (ShopItem(12873, 1500, 1))
|
||||
val Battle_Robe_Bottom = (ShopItem(12880, 1000, 1))
|
||||
val Green_Coif = (ShopItem(12936, 150, 1))
|
||||
val Blue_Coif = (ShopItem(12943, 200, 1))
|
||||
val Red_Coif = (ShopItem(12950, 300, 1))
|
||||
val Black_Coif = (ShopItem(12957, 500, 1))
|
||||
val Bronze_Gaunt = (ShopItem(12985, 15, 1))
|
||||
val Iron_Gaunt = (ShopItem(12988, 30, 1))
|
||||
val Steel_Gaunt = (ShopItem(12991, 50, 1))
|
||||
val Black_Gaunt = (ShopItem(12994, 75, 1))
|
||||
val Mithril_Gaunt = (ShopItem(12997, 100, 1))
|
||||
val Adamant_Gaunt = (ShopItem(13000, 150, 1))
|
||||
val Rune_Gaunt = (ShopItem(13003, 200, 1))
|
||||
val Dragon_Gaunt = (ShopItem(13006, 300, 1))
|
||||
val Addy_Spike = (ShopItem(12908, 50, 1))
|
||||
val Addy_Beserk = (ShopItem(12915, 100, 1))
|
||||
val Rune_Spike = (ShopItem(12922, 200, 1))
|
||||
val Rune_Beserk = (ShopItem(12929, 300, 1))
|
||||
val Air_Gloves = (ShopItem(12863, 75, 1))
|
||||
val Water_Gloves = (ShopItem(12864, 75, 1))
|
||||
val Earth_Gloves = (ShopItem(12865, 75, 1))
|
||||
val Irit_Gloves = (ShopItem(12856, 75, 1))
|
||||
val Avantoe_Gloves = (ShopItem(12857, 100, 1))
|
||||
val Kwuarm_Gloves = (ShopItem(12858, 200, 1))
|
||||
val Cadantine_Gloves = (ShopItem(12859, 200, 1))
|
||||
val Swordfish_Gloves = (ShopItem(12860, 200, 1))
|
||||
val Shark_Gloves = (ShopItem(12861, 200, 1))
|
||||
val Dragon_Gloves = (ShopItem(12862, 200, 1))
|
||||
|
||||
val shopsaleone = setOf(12863,12864,12865,12856,12857,12858,12859,12860,12861,12862)
|
||||
}
|
||||
|
|
@ -70,8 +70,8 @@ public class CrateCutscenePlugin extends CutscenePlugin {
|
|||
|
||||
@Override
|
||||
public Location getStartLocation() {
|
||||
return base.transform(18, 25, 0);
|
||||
}
|
||||
return base.transform(26, 47, 0);
|
||||
}// old 18 25
|
||||
|
||||
@Override
|
||||
public Location getSpawnLocation() {
|
||||
|
|
@ -80,13 +80,13 @@ public class CrateCutscenePlugin extends CutscenePlugin {
|
|||
|
||||
@Override
|
||||
public void configure() {
|
||||
region = DynamicRegion.create(12609);
|
||||
region = DynamicRegion.create(11161);
|
||||
setRegionBase();
|
||||
registerRegion(region.getId());
|
||||
SceneryBuilder.add(new Scenery(65, base.transform(18, 25, 0), 0, 0));
|
||||
SceneryBuilder.add(new Scenery(65, base.transform(19, 25, 0), 0, 4));
|
||||
SceneryBuilder.add(new Scenery(65, base.transform(18, 24, 0), 0, 1));
|
||||
SceneryBuilder.add(new Scenery(65, base.transform(18, 26, 0), 0, 3));
|
||||
//SceneryBuilder.add(new Scenery(65, base.transform(18, 25, 0), 0, 0));
|
||||
//SceneryBuilder.add(new Scenery(65, base.transform(19, 25, 0), 0, 4));
|
||||
//SceneryBuilder.add(new Scenery(65, base.transform(18, 24, 0), 0, 1));
|
||||
//SceneryBuilder.add(new Scenery(65, base.transform(18, 26, 0), 0, 3));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ import core.game.world.map.Direction
|
|||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.RegionManager.getRegionChunk
|
||||
import core.game.world.map.path.ClipMaskSupplier
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.game.world.map.zone.MapZone
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
|
|
@ -1459,7 +1460,8 @@ fun reinitVarps (player: Player) {
|
|||
*/
|
||||
fun forceWalk(entity: Entity, dest: Location, type: String) {
|
||||
if (type == "clip") {
|
||||
ForceMovement(entity, dest, 10, 10).run()
|
||||
val NO_CLIP = ClipMaskSupplier { _, _, _ -> 0 }
|
||||
Pathfinder.find(entity.location,entity.size(),dest,true,Pathfinder.SMART,NO_CLIP ).walk(entity)
|
||||
return
|
||||
}
|
||||
val pathfinder = when (type) {
|
||||
|
|
@ -1758,6 +1760,23 @@ fun setInterfaceText(player: Player, string: String, iface: Int, child: Int) {
|
|||
player.packetDispatch.sendString(string, iface, child)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a model to a specific interface child
|
||||
* @param player the player to send the packet to
|
||||
* @param modelId the modelId to send to the child
|
||||
* @param iface the ID of the interface to use
|
||||
* @param child the index of the child
|
||||
* @param zoom the zoom of the model
|
||||
* @param pitch optional pitch angle
|
||||
* @param yaw optional yaw angle
|
||||
*/
|
||||
fun setInterfaceModel( player: Player, modelId: Int, iface: Int, child: Int, zoom: Int, pitch: Int? = null, yaw: Int? = null) {
|
||||
player.packetDispatch.sendModelOnInterface(modelId, iface, child, zoom)
|
||||
if (pitch != null && yaw != null) {
|
||||
player.packetDispatch.sendAngleOnInterface(iface, child, zoom, pitch, yaw)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to hide or show specific children in an interface
|
||||
* @param player the player to send the packet to
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class GeneralBotCreator {
|
|||
return false
|
||||
|
||||
val idleRoll = RandomFunction.random(10)
|
||||
if(idleRoll == 2 && botScript !is Idler){
|
||||
if(idleRoll == 2 && botScript !is Idler && !botScript.preventRandomIdle){
|
||||
randomDelay += RandomFunction.random(20,50)
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ public abstract class Script {
|
|||
public boolean running = true;
|
||||
public boolean endDialogue = true;
|
||||
|
||||
public boolean preventRandomIdle = false;
|
||||
|
||||
public void init(boolean isPlayer)
|
||||
{
|
||||
//bot.init();
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ class ScriptAPI(private val bot: Player) {
|
|||
|
||||
val item = bot.inventory.getItem(Item(itemId))
|
||||
|
||||
val childNode = node.asScenery()?.getChild(bot)
|
||||
//val childNode = node.asScenery()?.getChild(bot)
|
||||
val childNode = if (node is Scenery) node.getChild(bot) else null
|
||||
|
||||
if (InteractionListeners.run(item, node, type, bot))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core.game.node.entity.combat;
|
||||
|
||||
import content.data.EnchantedJewellery;
|
||||
import content.minigame.barbassault.arena.BarbassaultSession;
|
||||
import core.game.container.impl.EquipmentContainer;
|
||||
import core.game.node.entity.skill.Skills;
|
||||
import content.global.skill.summoning.familiar.Familiar;
|
||||
|
|
@ -203,6 +204,14 @@ public final class ImpactHandler {
|
|||
if (p.getAttribute("godMode", false)) {
|
||||
p.getSkills().heal(10000);
|
||||
}
|
||||
if (hit > 0) {
|
||||
BarbassaultSession session = p.getAttribute("ba-session");
|
||||
if (session != null) {
|
||||
if (session.isInBarbAssaultGame()) {
|
||||
session.updateBarbHealerIfaceHPOfPlayer(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Impact impact = new Impact(source, hit, style, type);
|
||||
impactQueue.add(impact);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
|
||||
import static core.api.ContentAPIKt.setVarbit;
|
||||
import static core.api.ContentAPIKt.setVarp;
|
||||
|
||||
/**
|
||||
* Represents a managing class of a players spell book.
|
||||
|
|
@ -45,6 +46,8 @@ public final class SpellBookManager {
|
|||
public void update(Player player) {
|
||||
player.getInterfaceManager().openTab(new Component(spellBook));
|
||||
setVarbit(player, 357, Objects.requireNonNull(SpellBook.forInterface(spellBook)).ordinal());
|
||||
// Allows Catalytic and Elemental runes to be show as useable runes.
|
||||
setVarp(player,1331, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
package core.game.node.entity.player.link.prayer;
|
||||
|
||||
import content.data.Quests;
|
||||
import core.game.node.entity.player.link.diary.DiaryType;
|
||||
import content.minigame.barbassault.arena.BarbassaultSession;
|
||||
import core.game.node.entity.skill.SkillBonus;
|
||||
import core.game.node.entity.skill.Skills;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.audio.Audio;
|
||||
import core.game.world.map.zone.ZoneBorders;
|
||||
import core.tools.StringUtils;
|
||||
import core.game.event.*;
|
||||
import org.rs09.consts.Sounds;
|
||||
|
|
@ -222,6 +221,14 @@ public enum PrayerType {
|
|||
* @return <code>True</code> if it is permitted.
|
||||
*/
|
||||
public boolean permitted(final Player player) {
|
||||
BarbassaultSession session = player.getAttribute("ba-session");
|
||||
if (session != null) {
|
||||
if (session.isInBarbAssaultGame()) {
|
||||
sendMessage(player, "The barbarians forbid the use of prayer in their arena as they don't ~ value such methods!");
|
||||
toggle(player,false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!hasLevelStat(player, Skills.PRAYER, level) || !hasLevelStat(player, Skills.DEFENCE, defenceReq)) {
|
||||
sendDialogue(player, "You need a <col=08088A>" + (!hasLevelStat(player, Skills.PRAYER, level) ? "Prayer level of " + level + (!hasLevelStat(player, Skills.DEFENCE, defenceReq) ? " and a " : "") : "") + (!hasLevelStat(player, Skills.DEFENCE, defenceReq) ? "Defence level of " + defenceReq : "") + " to use " + StringUtils.formatDisplayName(name().toLowerCase().replace("_", " ")) + ".");
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue