Barb Assault:

Reward Interface ( no gamble )
Blackboard Interface
Queen help book
Commander_Connad Dialog
Penance Statues Dialog
Private's Dialog
Functioning Item Vending Machines
Horns cause player to TELL!/Say
Penance creatures Started
Penance creature configs added
Tutorial started ( Needs lots of work )
Game Arena Started ( Needs lots of work )

ContentAPI: added setInterfaceModel
This commit is contained in:
Tooze 2025-07-05 03:14:34 -04:00
parent 7cf5049687
commit f2c25bc7ed
33 changed files with 3266 additions and 37 deletions

View file

@ -45536,8 +45536,6 @@
"death_animation": "5937",
"name": "Penance Ranger",
"defence_level": "1",
"safespot": null,
"lifepoints": "10",
"strength_level": "1",
"id": "5229",
"aggressive": "true",
@ -45550,7 +45548,23 @@
"melee_animation": "5395",
"respawn_delay": "60",
"defence_animation": "5396",
"death_animation": "5937",
"death_animation": "5397",
"name": "Penance Ranger",
"defence_level": "1",
"lifepoints": "10",
"strength_level": "1",
"id": "5230",
"aggressive": "true",
"range_level": "1",
"attack_level": "1"
},
{
"examine": "Shooty-shooty.",
"combat_style": "1",
"melee_animation": "5395",
"respawn_delay": "60",
"defence_animation": "5396",
"death_animation": "5397",
"name": "Penance Ranger",
"defence_level": "1",
"safespot": null,
@ -81008,11 +81022,25 @@
},
{
"name": "Penance Fighter",
"id": "5044"
"id": "5044",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Fighter",
"id": "5045"
"id": "5045",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Jack",
@ -81328,131 +81356,287 @@
},
{
"name": "Penance Fighter",
"id": "5213"
"id": "5213",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Fighter",
"id": "5214"
"id": "5214",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Fighter",
"id": "5215"
"id": "5215",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Fighter",
"id": "5216"
"id": "5216",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Fighter",
"id": "5217"
"id": "5217",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Fighter",
"id": "5218"
"id": "5218",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Fighter",
"id": "5219"
"id": "5219",
"combat_audio": "670,672,671",
"melee_animation": "5097",
"range_animation": "5097",
"attack_speed": "4",
"defence_animation": "5096",
"magic_animation": "5097",
"death_animation": "5098"
},
{
"name": "Penance Runner",
"id": "5220"
"id": "5220",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5221"
"id": "5221",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5222"
"id": "5222",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5223"
"id": "5223",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5224"
"id": "5224",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5225"
"id": "5225",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5226"
"id": "5226",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5227"
"id": "5227",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Runner",
"id": "5228"
"id": "5228",
"defence_animation": "5101",
"death_animation": "5106"
},
{
"name": "Penance Ranger",
"id": "5230"
"id": "5230",
"combat_style": "1",
"melee_animation": "5395",
"defence_animation": "5396",
"death_animation": "5397",
"aggressive": "true"
},
{
"name": "Penance Ranger",
"id": "5231"
"id": "5231",
"combat_style": "1",
"melee_animation": "5395",
"defence_animation": "5396",
"death_animation": "5397",
"aggressive": "true"
},
{
"name": "Penance Ranger",
"id": "5232"
"id": "5232",
"combat_style": "1",
"melee_animation": "5395",
"defence_animation": "5396",
"death_animation": "5397",
"aggressive": "true"
},
{
"name": "Penance Ranger",
"id": "5233"
"id": "5233",
"combat_style": "1",
"melee_animation": "5395",
"defence_animation": "5396",
"death_animation": "5397",
"aggressive": "true"
},
{
"name": "Penance Ranger",
"id": "5234"
"id": "5234",
"combat_style": "1",
"melee_animation": "5395",
"defence_animation": "5396",
"death_animation": "5397",
"aggressive": "true"
},
{
"name": "Penance Ranger",
"id": "5235"
"id": "5235",
"combat_style": "1",
"melee_animation": "5395",
"defence_animation": "5396",
"death_animation": "5397",
"aggressive": "true"
},
{
"name": "Penance Ranger",
"id": "5236"
"id": "5236",
"combat_style": "1",
"melee_animation": "5395",
"defence_animation": "5396",
"death_animation": "5397",
"aggressive": "true"
},
{
"name": "Penance Healer",
"id": "5238"
"id": "5238",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5239"
"id": "5239",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5240"
"id": "5240",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5241"
"id": "5241",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5242"
"id": "5242",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5243"
"id": "5243",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5244"
"id": "5244",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5245"
"id": "5245",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Penance Healer",
"id": "5246"
"id": "5246",
"defence_animation": "5105",
"death_animation": "5106",
"melee_animation": "5107",
"range_animation": "5107",
"attack_speed": "4",
"magic_animation": "5107"
},
{
"name": "Locust rider",

View file

@ -0,0 +1,378 @@
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 = player.getBarbPoints()
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 -> { player.increaseBarbRoleLevel(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 = player.getBarbLevels()
val hasQueenKill = player.hasQueenKill()
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 = player.getBarbPoints()
val hasQueenKill = player.hasQueenKill()
val barbLevels = player.getBarbLevels()
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 = player.getBarbLevels()
val resolvedCost = reward.cost.resolve(barbLevels)
when (resolvedCost) {
is RewardCost.AllRoles -> {
if (reward.queenKillText != null) { setAttribute(player,"barbass:queen-kill", 0)}
player.removeBarbPoints(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 -> player.removeBarbPoints(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
),
)

View file

@ -0,0 +1,129 @@
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 - "
}
BarbRole.COLLECTOR -> when (level) { //is this the right info for 2009?
1 -> "Bag holds 4 eggs"
2 -> "Bag holds 6 eggs"
3 -> "Bag holds 7 eggs"
4 -> "Bag holds 8 eggs"
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) {
val wave = player.getAttribute("barbass:wave", 1)
player.interfaceManager.open(Component(Components.BARBASSAULT_PLAYERSTAT_490))
setInterfaceText(player, player.username, Components.BARBASSAULT_PLAYERSTAT_490, PLAYER_NAME)
setInterfaceText(player, wave.toString(), Components.BARBASSAULT_PLAYERSTAT_490, CURRENT_WAVE)
val playerLevel = player.getBarbLevels()
val playerPoints = player.getBarbPoints()
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)
}
}
}
}

View file

@ -0,0 +1,77 @@
package content.minigame.barbassault
import core.api.sendMessage
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.plugin.Initializable
import org.rs09.consts.Items
@Initializable
class BarbassDevHelper : CommandSet(Privilege.ADMIN) {
override fun defineCommands() {
define ("maxbarbpts") { player,_ ->
player.addBarbPoints(BarbAssaultPoints(500, 500, 500,500))
}
define ("rstbarbpts") { player,_ ->
player.setBarbPoints(BarbAssaultPoints(0, 0, 0,0))
}
define ("rstbarblvl") { player,_ ->
player.setBarbLevels(BarbAssaultLevels(0, 0, 0,0))
}
define("barbgame"){ player,_->
player.teleport(Location.create(1886, 5467, 0))
}
define("barbqueen"){ player,_->
player.teleport(Location.create(1885, 5403, 0))
}
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.")
}
}
}

View file

@ -0,0 +1,176 @@
package content.minigame.barbassault
import core.game.node.entity.player.Player
enum class BarbRole { ATTACKER, DEFENDER, COLLECTOR, HEALER }
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) )
}
/**
* Retrieves the player's current Barbarian Assault points.
*
* @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 = player.getBarbPoints()
* println("Attacker points: ${points.atk}")
* ```
*/
fun Player.getBarbPoints(): BarbAssaultPoints = BarbAssaultPoints(
getAttribute("barbass:atk-points", 0),
getAttribute("barbass:col-points", 0),
getAttribute("barbass:def-points", 0),
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 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)
* player.setBarbPoints(newPoints)
* ```
*/
fun Player.setBarbPoints(points: BarbAssaultPoints) {
val rolePoints = points.clamped()
setAttribute("/save:barbass:atk-points", rolePoints.atk)
setAttribute("/save:barbass:col-points", rolePoints.col)
setAttribute("/save:barbass:def-points", rolePoints.def)
setAttribute("/save:barbass:heal-points", rolePoints.heal)
}
/**
* Adds Barbarian Assault points to the 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
* player.addBarbPoints(BarbAssaultPoints(atk = 30, col = 10, def = 0, heal = 0))
* ```
*/
fun Player.addBarbPoints(additional: BarbAssaultPoints) {
setBarbPoints(getBarbPoints() + additional)
}
/**
* Removes Barbarian Assault points from the 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
* player.removeBarbPoints(BarbAssaultPoints(atk = 15, col = 0, def = 5, heal = 0))
* ```
*/
fun Player.removeBarbPoints(toRemove: BarbAssaultPoints) {
setBarbPoints(getBarbPoints() - toRemove)
}
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 Player.hasQueenKill(): Boolean = getAttribute("barbass:queen-kill", 0) > 0
/**
* Retrieves the player's Barbarian Assault role levels from their saved attributes.
* Defaults to level 1 for any role if not previously set.
*
* @return [BarbAssaultLevels] containing the level for each role:
* - `atk`: Attacker level
* - `col`: Collector level
* - `def`: Defender level
* - `heal`: Healer level
*
* Example usage:
* ```
* val levels = player.getBarbLevels()
* println("Attacker Level: ${levels.atk}")
* ```
*/
fun Player.getBarbLevels(): BarbAssaultLevels = BarbAssaultLevels(
getAttribute("barbass:atk-level", 1),
getAttribute("barbass:col-level", 1),
getAttribute("barbass:def-level", 1),
getAttribute("barbass:heal-level", 1)
)
/**
* Sets the player's Barbarian Assault role levels and saves them to persistent attributes.
*
* @param levels The [BarbAssaultLevels] object containing levels for each role:
* - `atk`: Attacker level (15)
* - `col`: Collector level (15)
* - `def`: Defender level (15)
* - `heal`: Healer level (15)
*
* Example usage:
* ```
* val newLevels = BarbAssaultLevels(atk = 2, col = 1, def = 3, heal = 1)
* player.setBarbLevels(newLevels)
* ```
*/
fun Player.setBarbLevels(levels: BarbAssaultLevels) {
setAttribute("/save:barbass:atk-level", levels.atk)
setAttribute("/save:barbass:col-level", levels.col)
setAttribute("/save:barbass:def-level", levels.def)
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 role The [BarbRole] to increase the level of. Must be one of:
* - `BarbRole.ATTACKER`
* - `BarbRole.COLLECTOR`
* - `BarbRole.DEFENDER`
* - `BarbRole.HEALER`
*
* Example usage:
* ```
* player.increaseBarbRoleLevel(BarbRole.ATTACKER)
* ```
*/
fun Player.increaseBarbRoleLevel(role: BarbRole) {
val current = getBarbLevels()
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()
setBarbLevels(newLevels)
}
fun BarbAssaultLevels.getLevel(role: BarbRole): Int = when (role) {
BarbRole.ATTACKER -> atk
BarbRole.COLLECTOR -> col
BarbRole.DEFENDER -> def
BarbRole.HEALER -> heal
}
fun BarbAssaultPoints.getPoints(role: BarbRole): Int = when (role) {
BarbRole.ATTACKER -> atk
BarbRole.COLLECTOR -> col
BarbRole.DEFENDER -> def
BarbRole.HEALER -> heal
}

View file

@ -0,0 +1,143 @@
package content.minigame.barbassault
import content.minigame.barbassault.BarbassBlackBoard.Companion.updateBlackBoard
import core.api.*
import core.game.component.Component
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.interaction.InterfaceListener
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
const val BARBASSAULT_ACCEPT_ROLE_492 = 492
const val BARBASSAULT_SELECT_ROLE_493 = 493
class BarbassaultListeners : InteractionListener {
//CommandSet(Privilege.ADMIN)
override fun defineListeners() {
on(Scenery.LADDER_20226, IntType.SCENERY, "Climb-down") { player, _ ->
// if (GameWorld.settings?.enable_barbassault != true) return@on false
if (joinError(player)) return@on true
val loc = Location(2593 , 5261 )
teleport(player, loc) // find ladder code latter
return@on true
}
on(Scenery.LADDER_20227, IntType.SCENERY, "Climb-up") { player, _ ->
//Remove Roster/scroll
val loc = Location(2535 , 3572 )
teleport(player, loc) // find ladder code latter
return@on true
}
on(Scenery.BLACKBOARD_20134, IntType.SCENERY, "Read") { player, _ ->
//emote 5354
//Remove Roster/scroll
// openOverlay(player, Components.BARBASSAULT_PLAYERSTAT_490)
updateBlackBoard(player)
return@on true
}
on(NPCs.COMMANDER_CONNAD_5029, IntType.NPC, "Get-rewards") { player, _ ->
setVarbit(player, 3256, 200)
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 capeCheck(player: Player): String? {
val wornCape = getItemFromEquipment(player, EquipmentSlot.CAPE)?.id ?: -1
if (wornCape != -1) return "No CAPES!!!" // find correct message
return null
}
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
//add food
//add ammo
)
for (item in player.inventory.toArray()) {
if (item != null) {
if (item.id in forbiddenRunes) {
return "no outside runes"
}
}
}
return null
}
private fun familiarCheck(player: Player): String? {
// if has pet or familiar, not allowed to enter.
return null
}
private fun joinError(player: Player): Boolean {
val errorMessage = capeCheck(player) ?: 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
}
}
}
*/

View file

@ -0,0 +1,54 @@
package content.minigame.barbassault
import core.api.produceGroundItem
import core.game.node.entity.npc.NPC
import core.game.node.item.GroundItem
import core.game.node.item.GroundItemManager
import core.game.world.map.Direction
import core.game.world.map.Location
import org.rs09.consts.Items
import org.rs09.consts.NPCs
class BarbassaultTut {
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]
*/

View file

@ -0,0 +1,112 @@
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 {
//todo check if completed tut with Captain
stage = 5
handle(0,0)
return true
}
override fun handle(componentID: Int, buttonID: Int): Boolean {
val barbasspoints = player.getBarbPoints()
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(player,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 ${player!!.getAttribute<Int>("barbass:wave")}.",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(player: Player, 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 {
val currentWave = player!!.getAttribute<Int>("barbass:wave")
if (currentWave != 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

View file

@ -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
}
}
}

View file

@ -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

View file

@ -0,0 +1,249 @@
package content.minigame.barbassault.arena
import core.api.*
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.Entity
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 core.game.world.update.flag.context.Animation
import core.tools.Log
import org.rs09.consts.Components
import org.rs09.consts.Items
import org.rs09.consts.Scenery
//HAMMER_2347
//LOGS_11760 use these loggs
//1889 5407 - Barb assualt QUEEN area -- 7508
//1891 5465 - barb assualt AREA under
//queen spawn in Location.create(1884, 5405, 0)
//No prayers
//sendMessage(player,"The barbarians forbid the use of prayer in their arena as they don't ~ value such methods!")
//should be multicombat
class BarbassaultGameArea : InteractionListener, MapArea {
val ATTACKER_ICON = 10556
val DEFENDER_ICON = 10558
val COLLECTOR_ICON = 10557
val HEALER_ICON = 10559
val ROLE_ICON = intArrayOf(ATTACKER_ICON,DEFENDER_ICON,COLLECTOR_ICON,HEALER_ICON)
override fun defineAreaBorders(): Array<ZoneBorders> {
//block standard teleports.
return arrayOf(getRegionBorders(7509))
}
override fun areaEnter(entity: Entity) {
val player = entity as? Player ?: return
val wornIconId = getItemFromEquipment(player, EquipmentSlot.CAPE)?.id
val interfaceId = getIconInterfaceId(wornIconId ?: -1)
if (interfaceId != null) {
//sendMessage(player,----- Wave: $Num -----")
openOverlay(player, interfaceId)
}
/*BarbassaultTut.BarbassTutNPCs.forEach {
npc -> npc.init()
npc.isWalks = false
}
BarbassaultTut.spawnItems()
*/
}
override fun areaLeave(entity: Entity, logout: Boolean) {
val player = entity as? Player ?: return
closeOverlay(player)
exitMiniGame(player)
log(this::class.java, Log.FINE, "EXITED BARBASS")
}
override fun defineListeners() {
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) {
//endGame
teleport(player, Location(2593 , 5261 ))
}
}
return@on true
}
on(Scenery.HEALER_SPRING_20150, IntType.SCENERY, "Drink-from") { player, _ ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10559) {
player.animate(Animation(5407))
player.lock(5)
GameWorld.Pulser.submit(object : Pulse(3, player) {
override fun pulse(): Boolean {
heal(player, 25)
player.unlock()
sendMessage(player,"You've been healed \$Healed hitpoints.")
return true
}
})
}
return@on true
}
on(Scenery.HEALER_SPRING_20150, IntType.SCENERY, "Take-from") { player, _ ->
//emote 5400
/* HEALING_VIAL_10546 -- empty
HEALING_VIAL1_10545 // 1
HEALING_VIAL2_10544
HEALING_VIAL3_10543
HEALING_VIAL4_10542 // 4
*/
return@on true
}
//CATALYTIC_RUNE_12851, ELEMENTAL_RUNE_12850
onUnequip(ROLE_ICON) { player, _ ->
defineAreaBorders().forEach { border ->
if (border.insideBorder(player)) {
sendMessage(player, "You can't remove that!") // is there a proper message for this?
return@onUnequip false
}
}
return@onUnequip true
}
onEquip(ROLE_ICON) { player, _ ->
defineAreaBorders().forEach { border ->
if (border.insideBorder(player)) {
sendMessage(player, "You can't remove that!")
// return@onUnequip false
}
}
return@onEquip true
}
}
private fun exitMiniGame(player: Player) {
openOverlay(player,493) // work around to actually close interfaces.
player.interfaceManager.closeOverlay()//maybe im doing this wrong.
removeTimer(player, "teleblock")
val barbassItems = arrayListOf(
Items.WORMS_10515,Items.CRACKERS_10513,Items.TOFU_10514,Items.LOGS_11760,Items.LOGS_11760,Items.HAMMER_2347,Items.DEFENDER_HORN_10538, //Defender Inv Items
Items.HEALING_VIAL_10546,Items.HEALING_VIAL1_10545,Items.HEALING_VIAL2_10544,Items.HEALING_VIAL3_10543,Items.HEALING_VIAL4_10542, //Healer Inv Items
Items.HEALER_HORN_10526,Items.HEALER_HORN_10527,Items.HEALER_HORN_10528,Items.HEALER_HORN_10529,Items.HEALER_HORN_10530,
Items.POISONED_WORMS_10540,Items.POISONED_TOFU_10539,Items.POISONED_MEAT_10541,
)
removeAll(player, barbassItems)
//todo should probably make sure familiars can't smuggle items out
//(player.familiarManager.familiar as? BurdenBeast)?.container?.removeAll(barbassItems)//just in case someone smuggles a pet in.
//award points, set Tp location to next wave
//or lost game Send back to wave room
}
fun removeAll(player: Player, items: List<Int>, container: Container = Container.INVENTORY): Boolean {
var removedAny = false
items.forEach { id ->
if (removeAll(player, id, container)) {
removedAny = true
}
}
return removedAny
}
fun getIconInterfaceId(itemId: Int): Int? {
return when (itemId) {
ATTACKER_ICON -> Components.BARBASSAULT_OVER_ATT_485
COLLECTOR_ICON -> Components.BARBASSAULT_OVER_COL_486
DEFENDER_ICON -> Components.BARBASSAULT_OVER_DEF_487
HEALER_ICON -> Components.BARBASSAULT_OVER_HEAL_488
else -> null
}
}
fun spawnPartyMembers(){
//1
//2 //3
//5 //4
// party slot effects where you start/spawn
val RedLeader1 = Location.create(1886, 5458, 0)
val RedLeader2 = Location.create(1885, 5457, 0)
val RedLeader3 = Location.create(1887, 5457, 0)
val RedLeader4 = Location.create(1884, 5456, 0)
val RedLeader5 = Location.create(1888, 5456, 0)
}
}
/*
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!
* */

View file

@ -0,0 +1,59 @@
package content.minigame.barbassault.arena
import core.api.*
import core.game.node.entity.player.Player
import org.rs09.consts.Items
object HornHelper {
fun getAttackerHorn(player: Player): AttackerHorn? {
return AttackerHorn.values().firstOrNull { inInventory(player, it.itemId) }
}
fun getHealerHorn(player: Player): HealerHorn? {
return HealerHorn.values().firstOrNull { inInventory(player, it.itemId) }
}
fun getCollectorBag(player: Player): CollectionBag? {
return CollectionBag.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]
}
}
enum class HealerHorn(val itemId: Int) {
LEVEL_ONE(Items.HEALER_HORN_10526),
LEVEL_TWO(Items.HEALER_HORN_10527),
LEVEL_THREE(Items.HEALER_HORN_10528),
LEVEL_FOUR(Items.HEALER_HORN_10529),
LEVEL_FIVE(Items.HEALER_HORN_10530);
companion object {
private val map = values().associateBy(HealerHorn::itemId)
fun fromId(id: Int): HealerHorn? = map[id]
}
}
enum class CollectionBag(val itemId: Int) {
LEVEL_ONE(Items.COLLECTION_BAG_10521),
LEVEL_TWO(Items.COLLECTION_BAG_10522),
LEVEL_THREE(Items.COLLECTION_BAG_10523),
LEVEL_FOUR(Items.COLLECTION_BAG_10524),
LEVEL_FIVE(Items.COLLECTION_BAG_10525);
companion object {
private val map = values().associateBy(CollectionBag::itemId)
fun fromId(id: Int): CollectionBag? = map[id]
}
}

View file

@ -0,0 +1,103 @@
package content.minigame.barbassault.arena
import core.api.sendChat
import core.api.sendMessage
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import org.rs09.consts.Items
class HornListeners : InteractionListener {
val ATTACKER_HORNS = intArrayOf(Items.ATTACKER_HORN_10516,Items.ATTACKER_HORN_10517,Items.ATTACKER_HORN_10518,Items.ATTACKER_HORN_10519,Items.ATTACKER_HORN_10520)
val TELL_RED = "Collector: Red Eggs!"
val TELL_GREEN = "Collector: Green Eggs!"
val TELL_BLUE = "Collector: Blue Eggs!"
val TELL_PTOFU = "Healer: Poison tofo!"
val TELL_PWORMS = "Healer: Poison worms!"
val TELL_PMEAT = "Healer: Poison meat!"
val TELL_STYLE1 = "Attacker: Controlled/Bronze/Wind!"
val TELL_STYLE2 = "Attacker: Accurate/Iron/Water!"
val TELL_STYLE3 = "Attacker: Aggressive/Steel/Earth!"
val TELL_STYLE4 = "Attacker: Defensive/Mithril/Fire!"
val HEALER_HORNS = intArrayOf(Items.HEALER_HORN_10526,Items.HEALER_HORN_10527,Items.HEALER_HORN_10528,Items.HEALER_HORN_10529,Items.HEALER_HORN_10530 )
val TELL_TOFU = "Defender: Drop Tofu!"
val TELL_CRACKERS= "Defender: Drop Crackers!"
val TELL_WORMS = "Defender: Drop Worms!"
val ALL_HORNS = intArrayOf(Items.COLLECTOR_HORN_10560,Items.DEFENDER_HORN_10538) + HEALER_HORNS + ATTACKER_HORNS
val TELL_MEDIC = "Medic!!"
override fun defineListeners() {
on(ALL_HORNS, IntType.ITEM, "Medic") { player, _ ->
sendChat(player,TELL_MEDIC)
return@on true
}
on(ALL_HORNS, IntType.ITEM, "Drop") { player, _ ->
sendMessage(player,"I need that!") // not authentic
return@on false
}
//ATTACKER
on(ATTACKER_HORNS, IntType.ITEM, "Tell-red") { player, _ ->
sendChat(player,TELL_RED)
return@on true
}
on(ATTACKER_HORNS, IntType.ITEM, "Tell-green") { player, _ ->
sendChat(player,TELL_GREEN)
return@on true
}
on(ATTACKER_HORNS, IntType.ITEM, "Tell-blue") { player, _ ->
sendChat(player,TELL_BLUE)
return@on true
}
//DEFENDER
on(Items.DEFENDER_HORN_10538, IntType.ITEM, "Tell-tofu") { player, _ ->
sendChat(player,TELL_PTOFU)
return@on true
}
on(Items.DEFENDER_HORN_10538, IntType.ITEM, "Tell-worms") { player, _ ->
sendChat(player,TELL_PWORMS)
return@on true
}
on(Items.DEFENDER_HORN_10538, IntType.ITEM, "Tell-meat") { player, _ ->
sendChat(player,TELL_PMEAT)
return@on true
}
//COLLECTOR
on(Items.COLLECTOR_HORN_10560, IntType.ITEM, "Tell-style1") { player, _ ->
sendChat(player,TELL_STYLE1)
return@on true
}
on(Items.COLLECTOR_HORN_10560, IntType.ITEM, "Tell-style2") { player, _ ->
sendChat(player,TELL_STYLE2)
return@on true
}
on(Items.COLLECTOR_HORN_10560, IntType.ITEM, "Tell-style3") { player, _ ->
sendChat(player,TELL_STYLE3)
return@on true
}
on(Items.COLLECTOR_HORN_10560, IntType.ITEM, "Tell-style4") { player, _ ->
sendChat(player,TELL_STYLE4)
return@on true
}
//HEALER
on(HEALER_HORNS, IntType.ITEM, "Tell-tofu") { player, _ ->
sendChat(player,TELL_TOFU)
return@on true
}
on(HEALER_HORNS, IntType.ITEM, "Tell-crackers") { player, _ ->
sendChat(player,TELL_CRACKERS)
return@on true
}
on(HEALER_HORNS, IntType.ITEM, "tell-worms") { player, _ ->
sendChat(player,TELL_WORMS)
return@on true
}
}
}

View file

@ -0,0 +1,32 @@
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
*/

View file

@ -0,0 +1,40 @@
package content.minigame.barbassault.arena.machines
import core.api.EquipmentSlot
import core.api.getItemFromEquipment
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import org.rs09.consts.Items
import org.rs09.consts.Scenery
import core.api.sendMessage
class AttackerMachine: InteractionListener {
val TAKE_ARROWS = intArrayOf(Items.BRONZE_ARROW_882, Items.IRON_ARROW_884,Items.STEEL_ARROW_886,Items.MITHRIL_ARROW_888)
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)
//val TAKE_RUNES = intArrayOf(Items.CATALYTIC_RUNE_12851,Items.ELEMENTAL_RUNE_12850)
//suppose to use Catalyic and Elemental runes
//should probably make sure familiars can't smuggle items out
override fun defineListeners() {
on(Scenery.ATTACKER_ITEM_MACHINE_20241, IntType.SCENERY, "Take-runes") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10556) {
ItemMachine.handleAddItemMachine(player, node, TAKE_RUNES, 300)
sendMessage(player,"You take a selection of runes from the dispenser.")
}
return@on true
}
on(Scenery.ATTACKER_ITEM_MACHINE_20241, IntType.SCENERY, "Take-arrows") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10556) {
ItemMachine.handleAddItemMachine(player, node, TAKE_ARROWS, 300)
sendMessage(player,"You take a selection of arrows from the dispenser.")
}
return@on true
}
}
}

View file

@ -0,0 +1,23 @@
package content.minigame.barbassault.arena.machines
import core.api.EquipmentSlot
import core.api.getItemFromEquipment
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import org.rs09.consts.Scenery
class CollectorMachine : InteractionListener {
override fun defineListeners() {
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Convert") { player, _ ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10557) {
//Items.RED_EGG_10532
//Items.BLUE_EGG_10533
//Items.GREEN_EGG_10531
//uhhhhhh
//more research is needed.
}
return@on true
}
}
}

View file

@ -0,0 +1,53 @@
package content.minigame.barbassault.arena.machines
import core.api.EquipmentSlot
import core.api.getItemFromEquipment
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import org.rs09.consts.Items
import org.rs09.consts.Scenery
class DefenderMachine :InteractionListener {
val TAKE_WORMS = Items.WORMS_10515
val TAKE_CRACKERS = Items.CRACKERS_10513
val TAKE_TOFU = Items.TOFU_10514
val baseItems = intArrayOf(TAKE_WORMS, TAKE_CRACKERS, TAKE_TOFU)
val STOCK_UP = IntArray(11 * baseItems.size) { i -> baseItems[i % baseItems.size] }
override fun defineListeners() {
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Stock-up") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10558) {
ItemMachine.handleAddItemMachine(player, node, STOCK_UP, 1)
}
return@on true
}
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Take-crackers") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10558) {
ItemMachine.handleAddItemMachine(player, node, intArrayOf(TAKE_CRACKERS), 5)
}
return@on true
}
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Take-tofu") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10558) {
ItemMachine.handleAddItemMachine(player, node, intArrayOf(TAKE_TOFU), 5)
}
return@on true
}
on(Scenery.DEFENDER_ITEM_MACHINE_20242, IntType.SCENERY, "Take-worms") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10558) {
ItemMachine.handleAddItemMachine(player, node, intArrayOf(TAKE_WORMS), 5)
}
return@on true
}
}
}
/*
[DEFENDER_ITEM_MACHINE_20242]
Options[ Stock-up, Take-crackers, Take-tofu, Take-worms]
take items gives 5,
stock up alternates crackers tofu worms
CRACKERS_10513, TOFU_10514, WORMS_10515
*/

View file

@ -0,0 +1,65 @@
package content.minigame.barbassault.arena.machines
import core.api.EquipmentSlot
import core.api.getItemFromEquipment
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import org.rs09.consts.Items
import org.rs09.consts.Scenery
class HealerMachine : InteractionListener {
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)
val TAKE_VAIL = Items.HEALING_VIAL4_10542
val TAKE_WORMS = Items.POISONED_WORMS_10540
val TAKE_TOFU = Items.POISONED_TOFU_10539
val TAKE_MEAT = Items.POISONED_MEAT_10541
val baseItems = intArrayOf(TAKE_WORMS, TAKE_TOFU, TAKE_MEAT)
val STOCK_UP = IntArray(11 * baseItems.size) { i -> baseItems[i % baseItems.size] }
override fun defineListeners() {
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Stock-up") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10559) {
//todo only allowed to have one vial
ItemMachine.handleAddItemMachine(player, node, STOCK_UP, 1)
}
return@on true
}
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-vail") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10559) {
//todo only allowed to have one vial
ItemMachine.handleAddItemMachine(player, node, intArrayOf(TAKE_VAIL), 1)
}
return@on true
}
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-worms") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10559) {
ItemMachine.handleAddItemMachine(player, node, intArrayOf(TAKE_WORMS), 5)
}
return@on true
}
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-tofu") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10559) {
ItemMachine.handleAddItemMachine(player, node, intArrayOf(TAKE_TOFU), 5)
}
return@on true
}
on(Scenery.HEALER_ITEM_MACHINE_20243, IntType.SCENERY, "Take-meat") { player, node ->
if (getItemFromEquipment(player, EquipmentSlot.CAPE)?.id == 10559) {
ItemMachine.handleAddItemMachine(player, node, intArrayOf(TAKE_MEAT), 5)
}
return@on true
}
}
}
/*
*
* [HEALER_ITEM_MACHINE_20243]
Options[ Stock-up, Take-vail, Take-tofu, Take-worms, Tale-meat]
Take item gives 5!
Stock-up gives vial and alternating tofo-worms-meat till full
POISONED_TOFU_10539,POISONED_MEAT_10541,POISONED_WORMS_10540
*/

View file

@ -0,0 +1,33 @@
package content.minigame.barbassault.arena.machines
import core.api.addItem
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
class ItemMachine {
companion object {
fun handleAddItemMachine(player: Player,node: Node, items: IntArray, amount: Int)
{
player.animate(Animation(5419)) // find right animation
player.lock(5) //
GameWorld.Pulser.submit(object : Pulse(3, player) {
override fun pulse(): Boolean {
//sendMessage(player,"You fill up your inventory with food from the dispenser") //defender
//sendMessage(player,"You fill up your inventory with poisoned food from the dispenser")// healer
//todo send right message depending on role
addArrayOfItems(player,items,amount)
player.unlock()
return true
}
})
}
fun addArrayOfItems(player: Player, ids: IntArray, amount: Int) {
ids.forEach { id -> addItem(player,id,amount) }
}
}
}

View file

@ -0,0 +1,59 @@
package content.minigame.barbassault.arenas.monsters
import content.minigame.barbassault.arena.HornHelper
import core.api.*
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 org.rs09.consts.NPCs
val PENANCE_FIGHTER_IDS = listOf(
NPCs.PENANCE_FIGHTER_5040,
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)
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) {
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 firstBefore = state.estimatedHit
state.estimatedHit = firstBefore + (HornHelper.getAttackerHorn(attacker as Player)?.ordinal?.plus(1) ?: 0) +1
}
override fun onCreation (self: NPC) {
self.setAttribute("agg_radius",2)
self.isWalks = true
self.isNeverWalks = false
self.walkRadius = 64
self.isAggressive = true
self.isRespawn = false
self.definition.combatDistance = 1
self.properties.combatPulse.style = CombatStyle.MELEE
}
}
//Shrink death 5098
//Fighter_Attack_5097
//5096 take hit
//5095_Move
//9094_Idle

View file

@ -0,0 +1,47 @@
package content.minigame.barbassault.arena.monsters
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
val PENANCE_HEALER_IDS = listOf(
NPCs.PENANCE_HEALER_5043,
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
)
class PenanceHealerNPC : NPCBehavior(*PENANCE_HEALER_IDS.toIntArray()) {
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
return 0.0
}
//sendMessage(player,"that's the wrong type of poisoned food to use! Penalty!")
}
/*
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?
*/

View file

@ -0,0 +1,34 @@
package content.minigame.barbassault.arena.monsters
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
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
*/

View file

@ -0,0 +1,60 @@
package content.minigame.barbassault.arena.monsters
import core.api.*
import core.api.getItemFromEquipment
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
//20730 = rangers cast
val PENANCE_RANGER_IDS = listOf(
NPCs.PENANCE_RANGER_5041,
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
)
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) {
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 onCreation (self: NPC) {
self.setAttribute("agg_radius",2)
self.isWalks = true
self.isNeverWalks = false
self.walkRadius = 64
self.isAggressive = true
self.definition.combatDistance = 8
self.properties.combatPulse.style = CombatStyle.RANGE
}
}
/*
* 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
*/

View file

@ -0,0 +1,50 @@
package content.minigame.barbassault.arena.monsters
import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
import core.game.node.entity.npc.NPCBehavior
import core.game.world.map.Location
import org.rs09.consts.NPCs
val PENANCE_RUNNER_IDS = listOf(
NPCs.PENANCE_RUNNER_5042,
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_RANGER_IDS.toIntArray()) {
val GOOD_EAT = "Chomp, chomp"
val BAD_EAT = "Blurghh"
val TRAP_HIT = "Urghhh!"
override fun getXpMultiplier(self: NPC, attacker: Entity): Double {
return 0.0
}
override fun onCreation(self: NPC) {
self.isWalks = true
self.walkRadius = 22
}
fun seekFood(){
}
}
//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
*/

View file

@ -0,0 +1,12 @@
package content.minigame.barbassault.arena.monsters
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
}
}

View file

@ -0,0 +1,79 @@
package content.minigame.barbassault.arena.scenery
import content.minigame.barbassault.arena.monsters.PENANCE_RUNNER_IDS
import core.api.*
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
// 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_ZONE: ZoneBorders = ZoneBorders(1900, 5475, 1902, 5473, 0)
val TRAP_EAST = Location.create(1901, 5474, 0)
val TRAP_WEST_ZONE: ZoneBorders = ZoneBorders(1870, 5474, 1872, 5472, 0)
val TRAP_WEST = Location.create(1871, 5473, 0)
val TRAPS_ZONE = arrayOf(TRAP_EAST_ZONE,TRAP_WEST_ZONE)
val TRAPS = arrayOf(TRAP_WEST,TRAP_EAST)
val playersInArea = mutableListOf<Player>()
override fun defineAreaBorders(): Array<ZoneBorders> {
return TRAPS_ZONE
}
override fun areaEnter(entity: Entity) {
if (PENANCE_RUNNER_IDS.contains(entity.id)) {
killRunner(entity)
updateTrap(entity.location)
sendMessageArea()
}
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 killRunner(entity: Entity){
}
fun updateTrap(location: Location) {
if (TRAPS.contains(location)){
}
}
fun sendMessageArea(){
playersInArea.forEach { player ->
sendMessage(player,"Entered Trap Area")
}
}
//you fixed the Penance Runner trap.
//sendMessage(player,"A Penance Runner broke a trap to the east/west!") //When a runner dies to trap announce to Defenders
//replaceScenery()
//animateScenery
}

View file

@ -0,0 +1,37 @@
package content.minigame.barbassault.arena.scenery
class EggCannon {
///stun(entity: Entity, ticks: Int)
///isStunned(entity: Entity)
//applyPoison (entity: Entity, source: Entity, severity: Int)
//isPoisoned (entity: Entity) : Boolean
//spawnProjectile
//face()
//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."
}
//emote 5428 maybe
/* GOLD I TELL YOU GOLD!!!!
https://youtu.be/_EipqTK3Qak?t=106
//egg explosion 20727
shoot option when no eggs in hoper =
MEssage chatbox-> There are no egs in the hopper.
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.
*/

View file

@ -0,0 +1,82 @@
package content.minigame.barbassault.arena.scenery
import core.api.sendMessage
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.plugin.Plugin
import org.rs09.consts.Components
import org.rs09.consts.Scenery
class HornOfGlory : ComponentPlugin() , InteractionListener {
companion object {
val QUEEN_ARRIVE = "The Queen has arrived and you can no longer use the horn of glory!"
//attacker
val CONTROLED_BRONZE_WIND = 0
val ACCURATE_IRON_WATER = 1
val AGGRISSIVE_STEEL_EARTH = 2
val DEFENSIVE_MITHRIL_FIRE = 3
//defender
val FOOD_TOFU = 0
val FOOD_CRACKERS = 1
val FOOD_WORMS = 2
//collector
val RED_EGG = 0
val GREEN_EGG = 1
val BLUE_EGG = 2
//healer
val POISON_TOFU = 0
val POISON_WORMS = 1
val POISON_MEAT = 2
val CALL_BUTTON = mapOf(
16 to CONTROLED_BRONZE_WIND,
17 to ACCURATE_IRON_WATER,
18 to AGGRISSIVE_STEEL_EARTH,
19 to DEFENSIVE_MITHRIL_FIRE,
20 to FOOD_TOFU,
22 to FOOD_CRACKERS,
21 to FOOD_WORMS,
13 to RED_EGG,
14 to GREEN_EGG,
15 to BLUE_EGG,
23 to POISON_TOFU,
24 to POISON_WORMS,
25 to POISON_MEAT
)
}
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.forId(Components.BARBASSAULT_HORN_484).plugin = this
return this
}
override fun handle(
player: Player?,
component: Component?,
opcode: Int,
button: Int,
slot: Int,
itemId: Int
): Boolean {
sendMessage(player!!,"Button " +button )
return true
}
override fun defineListeners() {
on(Scenery.HORN_OF_GLORY_20247, IntType.SCENERY, "Call") { player, _ ->
//emote 5438
player.interfaceManager.open(Component(484))
return@on true
}
}
}

View file

@ -0,0 +1,403 @@
package content.minigame.barbassault.lobby
import content.minigame.barbassault.BarbRole
import content.minigame.barbassault.party.Party
import content.minigame.barbassault.party.PartyHandler
import content.minigame.barbassault.party.PartyService
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.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld.ticks
import core.game.world.map.zone.ZoneBorders
import org.rs09.consts.Items
import org.rs09.consts.Scenery
//"-- Next wave no longer starting"
class BarbassaultLobby : InteractionListener, MapArea {
override fun defineAreaBorders(): Array<ZoneBorders> {
return areaBorders
}
override fun areaEnter(entity: Entity) {
updatePlayerWave(entity)
// openOverlay(entity, 256)
// Components.BARBASSAULT_PLAYERSTAT_490
sendMessage(entity as Player,"Party system is NOT Fully Implemented!!")
}
override fun areaLeave(entity: Entity, logout: Boolean) {
if (entity is Player) {
entity.interfaceManager.closeOverlay()
val barbassItems = intArrayOf(Items.POISONED_WORMS_10540)
entity.equipment.removeAll(barbassItems)
entity.inventory.removeAll(barbassItems)
}
}
fun updatePlayerWave(entity: Entity) {
val player = entity as? Player ?: return
val location = player.location
if (QUICK_START.insideBorder(location)) {
entity.setAttribute("/save:barbass:wave", 1)
return
}
for ((index, lobby) in waveLobbies.withIndex()) {
if (lobby.insideBorder(location)) {
if (lobby != MAIN_LOBBY) { // MAIN_LOBBY should not assign a wave number
entity.setAttribute("/save:barbass:wave", index + 1)
}
return
}
}
}
//attacker 20561 : ch8
//defender 20566 : ch10
//collector 20563 : ch13
//healer 20569 : ch14
override fun defineListeners() {
onUseWithPlayer(Items.SCROLL_10512) { inviter, _, invitee ->
val role = BarbRole.DEFENDER
PartyService.inviteToParty(inviter, invitee as Player, role)
val partyId = inviter.getAttribute<Int>("barbass:party-id")
val party = partyId?.let { PartyHandler.getParty(it) }
if (party != null) {
for (member in party.allMembers()) {
PartyService.updatePartyInterface(member.player)
}
}
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.
// waveAdvance(player)
return@on true
}
on(Items.SCROLL_10512, IntType.ITEM, "Write-Role") { player, _ ->
//player.interfaceManager.open(Component(493))
//setInterfaceModel(player, 20561, 493, 8,1)
sendDialogueOptions(
player,
"Which role would you like to perform?",
"Attacker", "Defender","Collector","Healer","Cancel")
addDialogueAction(player) { player , buttonId ->
writeRole(player,buttonId)
}
return@on true
}
on(Items.SCROLL_10512, IntType.ITEM, "Clear") { player, _ ->
val partyId = player.getAttribute<Int>("barbass:party-id") ?: return@on true
val party = PartyHandler.getParty(partyId) ?: return@on true
if (party.getLeader() != player) {
player.sendMessage("Only the party leader can clear the party.")
return@on true
}
val members = party.allMembers().map { it.player }
for (member in members) {
member.removeAttribute("barbass:party-id")
sendMessage(member,"The party has been cleared.")
closeOverlay(member)
openOverlay(member, 256)
PartyService.updatePartyInterface(member)
}
PartyHandler.removeParty(partyId)
return@on true
}
on(Scenery.LADDER_20193, IntType.SCENERY, "Climb-down") { player, _ ->
closeOverlay(player) // close party,
openOverlay(player, 494)// open countdown, Make a Count DownHandler
return@on true
}
on(Scenery.DOOR_20209, IntType.SCENERY, "Pass") { player, node ->
if (!QUICK_START.insideBorder(player.location)){
player.setAttribute("/save:barbass:wave", 1)
handlePlayerOptionDoor(player) { role ->
player.sendMessage("You are a ${role.name.lowercase().replaceFirstChar { it.uppercase() }}.")
handleWaveDoor(player, node, 489)
}
}else {
handleWaveDoor(player, node, 489)
}
return@on true
}
on(BARBDOORS, IntType.SCENERY, "Pass") { player, node ->
handleWaveDoor(player, node,256)
return@on true
}
on(Scenery.SCROLL_TABLE_20149, IntType.SCENERY, "Take-from") { player, _ ->
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!"
/*private val pulse = object : Pulse(1) {
override fun pulse(): Boolean {
ticks++
//setInterfaceText(player, ticks.toString(),494,0)
// for people in party update our time to next wave start
// maybe this is not the right way to do it?
if (ticks >= 500) {
ticks = 400
}
return false
}
}
*/
enum class RoomRole {
ATTACKER, DEFENDER, COLLECTOR, HEALER, ANYROLE
}
fun getModelFromButton(button: Int): Int {
return when (button) {
2 -> 20561
3 -> 20566
4 -> 20563
5 -> 20569
else -> 0 // Unknown or no match
}
}
fun getRoleFromButton(button: Int): BarbRole? {
return when (button) {
2 -> BarbRole.ATTACKER
3 -> BarbRole.DEFENDER
4 -> BarbRole.COLLECTOR
5 -> BarbRole.HEALER
else -> null
}
}
fun createPartyAsLeader(leader: Player, role: BarbRole): Int {
val (partyId, party) = PartyHandler.createNewParty()
val success = party.add(leader, role)
sendMessage(leader, "Party created with ID: $partyId")
if (!success) {
PartyHandler.removeParty(partyId)
}
return partyId
}
fun writeRole(player: Player, buttonId: Int) {
if (buttonId == 6) return
val playerRole = getRoleFromButton(buttonId) ?: return
val partyId = player.getAttribute<Int>("barbass:party-id")
val party = partyId?.let { PartyHandler.getParty(it) }
if (party != null) {
val roleCount = party.allMembers().count { it.role == playerRole }
if (roleCount >= 2) {
sendMessage(player,"That role is already full.")
return
}
party.changeRole(player, playerRole)
PartyService.updatePartyInterface(player)
} else {
val newPartyId = createPartyAsLeader(player, playerRole)
PartyService.updatePartyInterface(player)
}
sendMessage(player,"You've set your role to ${playerRole.name.lowercase().replaceFirstChar { it.uppercase() }}")
}
fun handlePlayerOptionDoor(player: Player, roomRoleOptions:(RoomRole) -> Unit){
sendDialogueOptions(
player,
"Which role would you like to perform?",
"Attacker", "Defender","Collector","Healer","I'll be any role!")
addDialogueAction(player) { _, buttonId ->
val role = when (buttonId) {
2 -> RoomRole.ATTACKER
3 -> RoomRole.DEFENDER
4 -> RoomRole.COLLECTOR
5 -> RoomRole.HEALER
6 -> RoomRole.ANYROLE
else -> RoomRole.ANYROLE
}
roomRoleOptions(role)
}
}
fun handleWriteRole(player: Player){
sendDialogueOptions(
player,
"Which role do you wish to be?",
"Attacker", "Defender","Collector","Healer","Cancel")
addDialogueAction(player) { _, buttonId ->
when (buttonId) {
2 -> BarbRole.ATTACKER
3 -> BarbRole.DEFENDER
4 -> BarbRole.COLLECTOR
5 -> BarbRole.HEALER
else -> {}
}
}
}
fun handleWaveDoor(player: Player, node: Node,iface: Int){
val doorLoc = node.location
val playerLoc = player.location
var wave = player.getAttribute("barbass:wave", 1)
if (wave == BARBWAVEDOOR[node.id]) {
val insideRoom = playerLoc.y <= doorLoc.y
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) {
closeOverlay(player)
PartyService.leaveParty(player)
} else {
openOverlay(player, iface)
player.sendMessage("you enter wave ${BARBWAVEDOOR[node.id]}")
}
}
}
}
fun waveAdvance(player: Player) {
var wave = player.getAttribute("barbass:wave", 1)
if (wave in 1..waveLobbies.size) {
val targetLobby = waveLobbies[wave]
teleport(player, targetLobby.randomWalkableLoc)
if (wave == 10) {player.setAttribute("/save:barbass:wave", 1)}
} else {
println("Invalid wave number: $wave")
}
}
companion object {
// 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)
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
)
val waveLobbies = listOf(
WAVE_LOBBY1, WAVE_LOBBY2, WAVE_LOBBY3, WAVE_LOBBY4,
WAVE_LOBBY5, WAVE_LOBBY6, WAVE_LOBBY7, WAVE_LOBBY8,
WAVE_LOBBY9, WAVE_LOBBY10,
MAIN_LOBBY
)
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)
// override fun tick() {
// TODO("Not yet implemented")
// }
}
/*
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
*/

View file

@ -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
}
}

View file

@ -0,0 +1,106 @@
package content.minigame.barbassault.party
import content.minigame.barbassault.BarbRole
import core.game.node.entity.player.Player
//todo fix party system. Maybe toss it all away and start over.
data class PartyMember(val player: Player, var role: BarbRole)
class Party(val id: Int) {
companion object {
const val MAX_MEMBERS = 5
const val MAX_PER_ROLE = 2
}
private val slots = MutableList<PartyMember?>(MAX_MEMBERS) { null }
private var leader: Player? = null
fun add(player: Player, role: BarbRole): Boolean {
// Check if player is already in party
if (slots.any { it?.player == player }) return false
// Check if party full
if (slots.count { it != null } >= MAX_MEMBERS) return false
// Check role limit
if (slots.count { it?.role == role } >= MAX_PER_ROLE) return false
// Find first empty slot
val emptyIndex = slots.indexOfFirst { it == null }
if (emptyIndex == -1) return false // no empty slots
slots[emptyIndex] = PartyMember(player, role)
if (leader == null) leader = player
player.setAttribute("barbass:party-id", this.id)
updateInterfaces()
return true
}
fun remove(player: Player): Boolean {
val index = slots.indexOfFirst { it?.player == player }
if (index == -1) return false // not in party
slots[index]?.player?.removeAttribute("barbass:party-id")
slots[index] = null
if (leader == player) {
disband()
} else {
updateInterfaces()
}
return true
}
fun updateInterfaces() {
slots.filterNotNull().forEach {
PartyService.updatePartyInterface(it.player)
}
}
fun disband() {
slots.filterNotNull().forEach {
it.player.removeAttribute("barbass:party-id")
it.player.sendMessage("The party has been disbanded.")
PartyService.updatePartyInterface(it.player)
}
PartyHandler.removeParty(id)
slots.fill(null)
leader = null
}
fun getLeader(): Player? = leader
fun setLeader(player: Player) {
if (slots.any { it?.player == player }) {
leader = player
updateInterfaces()
}
}
fun getRole(player: Player): BarbRole? =
slots.find { it?.player == player }?.role
fun changeRole(player: Player, newRole: BarbRole): Boolean {
val slot = slots.find { it?.player == player } ?: return false
if (slots.count { it?.role == newRole } >= MAX_PER_ROLE) return false
slot.role = newRole
updateInterfaces()
return true
}
fun contains(player: Player): Boolean =
slots.any { it?.player == player }
fun size(): Int = slots.count { it != null }
fun allMembers(): List<PartyMember> = slots.filterNotNull()
fun getSlots(): List<PartyMember?> = slots.toList()
fun clear() {
slots.filterNotNull().forEach {
it.player.removeAttribute("barbass:party-id")
}
slots.fill(null)
leader = null
updateInterfaces()
}
}

View file

@ -0,0 +1,39 @@
package content.minigame.barbassault.party
object PartyHandler {
private val parties = mutableMapOf<Int, Party>()
private val freedIds = ArrayDeque<Int>()
private var nextPartyId = 1
fun createNewParty(): Pair<Int, Party> {
val id = if (freedIds.isNotEmpty()) freedIds.removeFirst() else nextPartyId++
val party = Party(id)
parties[id] = party
return id to party
}
fun getOrCreateParty(id: Int): Party =
parties.getOrPut(id) { Party(id) }
fun getParty(id: Int): Party? = parties[id]
fun removeParty(id: Int) {
if (parties.remove(id) != null) {
freedIds.add(id)
}
}
fun allParties(): Map<Int, Party> = parties.toMap()
fun cleanupOfflineParties() {
val toRemove = parties.filter { (_, party) ->
val leader = party.getLeader()
leader == null || !leader.isActive()
}.keys
for (partyId in toRemove) {
removeParty(partyId)
println("Removed party $partyId because leader was offline or null.")
}
}
}

View file

@ -0,0 +1,107 @@
package content.minigame.barbassault.party
import content.minigame.barbassault.BarbRole
import core.api.sendMessage
import core.api.setInterfaceModel
import core.api.setInterfaceText
import core.game.node.entity.player.Player
class PartyService {
companion object {
fun inviteToParty(inviter: Player, invitee: Player, role: BarbRole) {
val partyId = inviter.getAttribute<Int>("barbass:party-id")
val party = partyId?.let { PartyHandler.getParty(it) }
when {
partyId == null -> sendMessage(inviter, "You're not in a party.")
party == null -> sendMessage(inviter, "Party $partyId not found.")
!party.contains(inviter) -> sendMessage(inviter, "You are not a member of party $partyId.")
invitee.getAttribute<Int>("barbass:party-id") != null -> sendMessage(inviter, "${invitee.name} is already in a party.")
party.size() >= Party.MAX_MEMBERS -> sendMessage(inviter, "Party is full.")
party.allMembers().count { it.role == role } >= Party.MAX_PER_ROLE -> sendMessage(inviter, "Too many players with the role $role.")
!party.add(invitee, role) -> sendMessage(inviter, "Failed to add ${invitee.name} as $role.")
party.getLeader() != inviter -> sendMessage(inviter, "Only the party leader can invite players.")
else -> {
invitee.setAttribute("barbass:party-id", partyId)
val formattedRole = role.name.lowercase().replaceFirstChar { it.uppercase() }
sendMessage(inviter, "${invitee.name} joined your party as $formattedRole.")
}
}
}
fun updatePartyInterface(player: Player) {
val ROLE_MODEL_MAP = mapOf(
BarbRole.ATTACKER to 20561,
BarbRole.COLLECTOR to 20563,
BarbRole.DEFENDER to 20566,
BarbRole.HEALER to 20569
)
val iLeaderText = 6
val iPlayerTextStart = 7
val iModelOffset = 10
val modelZoom = 2372
val iDefaultText = "-----"
val partyId = player.getAttribute<Int>("barbass:party-id") ?: return
val party = PartyHandler.getParty(partyId) ?: return
val members = party.allMembers()
val leader = party.getLeader()
if (leader != null) {
val leaderMember = members.find { it.player == leader }
setInterfaceText(player, leader.username, 256, iLeaderText)
setInterfaceModel(player, ROLE_MODEL_MAP[leaderMember?.role] ?: 20561, 256, iLeaderText + iModelOffset, modelZoom)
} else {
setInterfaceText(player, iDefaultText, 256, iLeaderText)
setInterfaceModel(player, 20561, 256, iLeaderText + iModelOffset, modelZoom)
}
val otherMembers = members.filter { it.player != leader }
for (i in 0 until 4) {
val slotTextId = iPlayerTextStart + i
val slotModelId = slotTextId + iModelOffset
if (i < otherMembers.size) {
val member = otherMembers[i]
setInterfaceText(player, member.player.username, 256, slotTextId)
setInterfaceModel(player, ROLE_MODEL_MAP[member.role] ?: 20561, 256, slotModelId, modelZoom)
} else {
setInterfaceText(player, iDefaultText, 256, slotTextId)
setInterfaceModel(player, -1, 256, slotModelId, modelZoom) // Default to attacker icon for empty
}
}
}
fun leaveParty(player: Player) {
val partyId = player.getAttribute<Int>("barbass:party-id") ?: return
val party = PartyHandler.getParty(partyId) ?: return
if (!party.remove(player)) {
player.sendMessage("Failed to leave the party.")
return
}
player.removeAttribute("barbass:party-id")
player.sendMessage("You have left the party.")
updatePartyInterface(player)
// Update remaining party members
for (member in party.allMembers()) {
updatePartyInterface(member.player)
}
if (party.allMembers().isEmpty()) {
PartyHandler.removeParty(partyId)
}
}
}
}