Repository reorganisation

Unified kotlin and java into just src/main
Unified the rs09 and core packages
Took all content out of the core package, and placed it into the new content package
Reorganised all source code relating to content to be easier to find and explore
This commit is contained in:
Ceikry
2023-01-26 13:59:28 +00:00
committed by Ryan
parent e4b799c44a
commit a100affda2
3156 changed files with 24205 additions and 30585 deletions
@@ -0,0 +1,73 @@
package content.minigame.allfiredup
import core.game.node.entity.player.Player
import core.tools.SystemLogger
import core.game.world.map.Location
/**
* Various data for beacons, such as varp and offset, required FM level, etc
* @author Ceikry
*/
enum class AFUBeacon(val title: String, val fmLevel: Int, val varpId: Int, val offset: Int, val location: Location, val experience: Double, val keeper: Int = 0) {
RIVER_SALVE("",43,1283,0,Location.create(3396, 3464, 0),216.2,8065),
RAG_AND_BONE("",43,1283,3,Location.create(3343, 3510, 0),235.8,8066),
JOLLY_BOAR("",48,1283,6,Location.create(3278, 3525, 0), 193.8,8067),
NORTH_VARROCK_CASTLE("",53,1283,9,Location.create(3236, 3527, 0),178.5,8068),
GRAND_EXCHANGE("",59,1283,12,Location.create(3170, 3536, 0),194.3,8069),
EDGEVILLE("",62,1283,15,Location.create(3087, 3516, 0),86.7,8070),
MONASTERY("",68,1283,18,Location.create(3034, 3518, 0),224.4,8071),
GOBLIN_VILLAGE("",72,1283,21,Location.create(2968, 3516, 0),194.8,8072),
BURTHORPE("",76,1283,24,Location.create(2940, 3565, 0),195.3,8073),
DEATH_PLATEAU("",79,1288,0,Location.create(2944, 3622, 0),249.9,8074),
TROLLHEIM("",83,1288,3,Location.create(2939, 3680, 0),201.0,8075),
GWD("",87,1288,6,Location.create(2937, 3773, 0),255.0,8076),
TEMPLE("",89,1288,9,Location.create(2946, 3836, 0),198.9),
PLATEAU("",92,1288,12,Location.create(2964, 3931, 0),147.9);
companion object {
fun forLocation(location: Location): content.minigame.allfiredup.AFUBeacon {
for (beacon in values()) {
if (beacon.location.equals(location)) return beacon
}
return content.minigame.allfiredup.AFUBeacon.RIVER_SALVE.also { SystemLogger.logWarn(this::class.java, "Unhandled Beacon Location ${location.toString()}") }
}
fun resetAllBeacons(player: Player){
for(beacon in values()){
player.varpManager.get(beacon.varpId).setVarbit(beacon.offset,0).send(player)
}
}
}
fun light(player: Player){
player.varpManager.get(varpId).setVarbit(offset,2).send(player)
}
fun diminish(player: Player){
player.varpManager.get(varpId).setVarbit(offset,3).send(player)
}
fun extinguish(player: Player){
player.varpManager.get(varpId).setVarbit(offset,0).send(player)
}
fun lightGnomish(player: Player){
player.varpManager.get(varpId).setVarbit(offset,4).send(player)
}
fun fillWithLogs(player: Player){
player.varpManager.get(varpId).setVarbit(offset,1).send(player)
}
fun getState(player: Player): content.minigame.allfiredup.BeaconState {
return content.minigame.allfiredup.BeaconState.values()[player.varpManager.get(varpId).getVarbit(offset) ?: 0]
}
}
enum class BeaconState{
EMPTY,
FILLED,
LIT,
DYING,
WARNING
}
@@ -0,0 +1,216 @@
package content.minigame.allfiredup
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import core.game.world.GameWorld
private val VALID_LOGS = intArrayOf(Items.LOGS_1511, Items.OAK_LOGS_1521,Items.WILLOW_LOGS_1519,Items.MAPLE_LOGS_1517,Items.YEW_LOGS_1515,Items.MAGIC_LOGS_1513)
private val FILL_ANIM = Animation(9136)
private val LIGHT_ANIM = Animation(7307)
/**
* Handles interactions for beacons
* @author Ceikry
*/
class AFUBeaconListeners : InteractionListener {
override fun defineListeners() {
on(IntType.SCENERY,"add-logs","light"){ player, node ->
val beacon = content.minigame.allfiredup.AFUBeacon.forLocation(node.location)
val questComplete = player.questRepository.isComplete("All Fired Up")
val questStage = player.questRepository.getStage("All Fired Up")
if ((beacon != content.minigame.allfiredup.AFUBeacon.RIVER_SALVE && beacon != content.minigame.allfiredup.AFUBeacon.RAG_AND_BONE && !questComplete)
|| (beacon == content.minigame.allfiredup.AFUBeacon.RIVER_SALVE && questStage < 20 && !questComplete)
|| (beacon == content.minigame.allfiredup.AFUBeacon.RAG_AND_BONE && questStage < 50 && !questComplete)) {
player.dialogueInterpreter.sendDialogues(player, core.game.dialogue.FacialExpression.THINKING, "I probably shouldn't mess with this.")
return@on true
}
player.debug(beacon.getState(player).name)
when (beacon.getState(player)) {
content.minigame.allfiredup.BeaconState.EMPTY -> fillBeacon(player, beacon, questComplete)
content.minigame.allfiredup.BeaconState.DYING -> restoreBeacon(player, beacon, questComplete)
content.minigame.allfiredup.BeaconState.FILLED -> lightBeacon(player, beacon, questComplete)
content.minigame.allfiredup.BeaconState.LIT, content.minigame.allfiredup.BeaconState.WARNING -> {
player.debug("INVALID BEACON STATE")
}
}
return@on true
}
}
fun fillBeacon(player: Player, beacon: content.minigame.allfiredup.AFUBeacon, questComplete: Boolean){
when(beacon){
content.minigame.allfiredup.AFUBeacon.MONASTERY -> {
if(player.skills.getLevel(Skills.PRAYER) < 31){
player.dialogueInterpreter.sendDialogues(NPC(beacon.keeper).getShownNPC(player), core.game.dialogue.FacialExpression.ANGRY,"You must join the monastery to light this beacon!")
return
}
}
content.minigame.allfiredup.AFUBeacon.GWD -> {
if(!AFURepairClimbHandler.isRepaired(player, beacon)){
player.dialogueInterpreter.sendDialogue("You must repair the windbreak before you","can light this beacon.")
return
}
}
content.minigame.allfiredup.AFUBeacon.GOBLIN_VILLAGE -> {
if(!player.questRepository.isComplete("Lost Tribe")){
player.dialogueInterpreter.sendDialogues(NPC(beacon.keeper).getShownNPC(player), core.game.dialogue.FacialExpression.THINKING,"We no trust you outsider. You no light our beacon.","(Complete Lost Tribe to use this beacon.)")
return
}
}
}
if(player.skills.getLevel(Skills.FIREMAKING) < beacon.fmLevel){
player.dialogueInterpreter.sendDialogue("You need ${beacon.fmLevel} Firemaking to light this beacon.")
return
}
val logs = getLogs(player,20)
if (logs.id != 0 && player.inventory.remove(logs)) {
player.lock()
var session: AFUSession? = null
if(questComplete){
session = player.getAttribute("afu-session", null)
if(session == null) {
session = AFUSession(player)
session.init()
}
}
GameWorld.Pulser.submit(object : Pulse() {
var counter = 0
override fun pulse(): Boolean {
when (counter++) {
0 -> player.animator.animate(FILL_ANIM)
1 -> {
beacon.fillWithLogs(player)
if(questComplete){
session?.setLogs(beacon.ordinal,logs)
}
player.varpManager.flagSave(beacon.varpId);
}
2 -> player.unlock().also {player.animator.animate(Animation.RESET); return true }
}
return false
}
})
} else {
player.dialogueInterpreter.sendDialogue("You need some logs to do this.")
}
}
fun lightBeacon(player: Player, beacon: content.minigame.allfiredup.AFUBeacon, questComplete: Boolean){
var session: AFUSession? = null
if(questComplete){
session = player.getAttribute("afu-session",null)
if(session == null) return
}
if(player.inventory.contains(Items.TINDERBOX_590,1)){
player.lock()
GameWorld.Pulser.submit(object: Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(LIGHT_ANIM)
1 -> {
beacon.light(player)
if(questComplete){
session?.startTimer(beacon.ordinal)
if(session?.getLitBeacons() == 6 && !player.hasFireRing()){
player.sendMessage("Congratulations on lighting 6 beacons at once! King Roald has something for you.")
player.setAttribute("/save:afu-mini:ring",true)
}
if(session?.getLitBeacons() == 10 && !player.hasFlameGloves()){
player.sendMessage("Congratulations on lighting 10 beacons at once! King Roald has something for you.")
player.setAttribute("/save:afu-mini:gloves",true)
}
if(session?.getLitBeacons() == 14 && !player.hasInfernoAdze()){
player.sendMessage("Congratulations on lighting all 14 beacons! King Roald has something special for you.")
player.setAttribute("/save:afu-mini:adze",true)
}
var experience = beacon.experience
experience += session?.getBonusExperience() ?: 0.0
player.skills.addExperience(Skills.FIREMAKING,experience)
} else {
player.questRepository.getQuest("All Fired Up").setStage(player, player.questRepository.getStage("All Fired Up") + 10)
}
}
2 -> player.unlock().also { return true }
}
return false
}
})
} else {
player.dialogueInterpreter.sendDialogue("You need a tinderbox to light this.")
}
}
fun restoreBeacon(player: Player, beacon: content.minigame.allfiredup.AFUBeacon, questComplete: Boolean){
var session: AFUSession? = null
if(questComplete){
session = player.getAttribute("afu-session",null)
if(session == null) return
}
val logs = getLogs(player, 5)
if (logs.id != 0 && player.inventory.remove(logs)) {
player.lock()
GameWorld.Pulser.submit(object: Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(FILL_ANIM)
1 -> beacon.light(player).also {
if(questComplete){
session?.refreshTimer(beacon,logs.id)
} else {
player.questRepository.getQuest("All Fired Up").setStage(player, 80)
}
}
2 -> player.unlock().also { return true }
}
return false
}
})
} else {
player.dialogueInterpreter.sendDialogue("You need some logs to do this.")
}
}
fun getLogs(player: Player, amount: Int): Item{
var logId = 0
for (log in VALID_LOGS) if (player.inventory.getAmount(log) >= amount) {logId = log; break}
return Item(logId,amount)
}
fun Player.hasFireRing(): Boolean{
return inventory.containsItem(Item(Items.RING_OF_FIRE_13659)) || bank.containsItem(Item(Items.RING_OF_FIRE_13659)) || equipment.containsItem(Item(Items.RING_OF_FIRE_13659))
}
fun Player.hasFlameGloves(): Boolean{
return inventory.containsItem(Item(Items.FLAME_GLOVES_13660)) || bank.containsItem(Item(Items.FLAME_GLOVES_13660)) || equipment.containsItem(Item(Items.FLAME_GLOVES_13660))
}
fun Player.hasInfernoAdze(): Boolean{
return inventory.containsItem(Item(Items.INFERNO_ADZE_13661)) || bank.containsItem(Item(Items.INFERNO_ADZE_13661)) || equipment.containsItem(Item(Items.INFERNO_ADZE_13661))
}
}
@@ -0,0 +1,141 @@
package content.minigame.allfiredup
import core.game.node.entity.impl.ForceMovement
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import content.global.skill.construction.NailType
import core.game.node.item.Item
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import java.util.*
/**
* Handles repairing and climbing of the 3 beacon shortcuts needed to access them
* @author Ceikry
*/
class AFURepairClimbHandler : InteractionListener {
val repairIDs = intArrayOf(38480,38470,38494)
val climbIDs = intArrayOf(38469,38471,38486,38481)
override fun defineListeners() {
on(repairIDs, IntType.SCENERY, "repair"){ player, _ ->
var rco: RepairClimbObject = RepairClimbObject.GWD
for(ent in RepairClimbObject.values()) if(ent.destinationDown?.withinDistance(player.location,2) == true || ent.destinationUp?.withinDistance(player.location,2) == true) rco = ent
repair(player,rco)
return@on true
}
on(climbIDs, IntType.SCENERY, "climb"){ player, node ->
var rco: RepairClimbObject = RepairClimbObject.GWD
for(ent in RepairClimbObject.values()) if(ent.destinationDown?.withinDistance(player.location,2) == true || ent.destinationUp?.withinDistance(player.location,2) == true) rco = ent
climb(player,rco,node.location)
return@on true
}
}
private fun repair(player: Player,rco: RepairClimbObject){
val skill = rco.levelRequirement?.first ?: 0
val level = rco.levelRequirement?.second ?: 0
if(player.skills.getLevel(skill) < level){
player.dialogueInterpreter.sendDialogue("You need level $level ${Skills.SKILL_NAME[skill]} for this.")
return
}
var requiresNeedle = false
val requiredItems = when(rco){
RepairClimbObject.DEATH_PLATEAU -> {
arrayOf(Item(Items.PLANK_960,2))
}
RepairClimbObject.BURTHORPE -> {
arrayOf(Item(Items.IRON_BAR_2351,2))
}
RepairClimbObject.GWD -> {
requiresNeedle = true
arrayOf(Item(Items.JUTE_FIBRE_5931,3))
}
RepairClimbObject.TEMPLE -> {
arrayOf(Item(Items.IRON_BAR_2351,2))
}
}
if(requiresNeedle){
if(player.inventory.containsItem(Item(Items.NEEDLE_1733)) && player.inventory.containItems(*requiredItems.map { it.id }.toIntArray())) {
player.inventory.remove(*requiredItems)
if (Random().nextBoolean()) player.inventory.remove(Item(Items.NEEDLE_1733))
} else {
player.dialogueInterpreter.sendDialogue("You need a needle and ${requiredItems.map { "${it.amount} ${it.name.toLowerCase()}s" }.toString().replace("[","").replace("]","")} for this.")
return
}
} else {
if(player.inventory.containsItem(Item(Items.HAMMER_2347)) && player.inventory.containItems(*requiredItems.map { it.id }.toIntArray())) {
val nails = NailType.get(player,4)
if(nails == null && rco == RepairClimbObject.DEATH_PLATEAU){
player.dialogueInterpreter.sendDialogue("You need 4 nails for this.")
return
} else if (rco == RepairClimbObject.DEATH_PLATEAU){
player.inventory.remove(Item(nails.itemId,4))
}
player.inventory.remove(*requiredItems)
} else {
player.dialogueInterpreter.sendDialogue("You need a hammer and ${requiredItems.map { "${it.amount} ${it.name.toLowerCase()}s" }.toString().replace("[","").replace("]","")} for this.")
return
}
}
player.varpManager.get(rco.varp).setVarbit(rco.offset,1).send(player)
player.varpManager.flagSave(rco.varp)
}
private fun climb(player: Player, rco: RepairClimbObject, location: Location){
ForceMovement.run(player,location,rco.getOtherLocation(player),rco.getAnimation(player),rco.getAnimation(player),rco.getDirection(player),20).endAnimation = Animation(-1)
}
private enum class RepairClimbObject(val varp: Int, val offset: Int, val destinationUp: Location?, val destinationDown: Location?, val levelRequirement: Pair<Int,Int>?){
DEATH_PLATEAU(1282,15,Location.create(2949, 3623, 0),Location.create(2954, 3623, 0), Pair(Skills.CONSTRUCTION,42)),
BURTHORPE(1282,14,Location.create(2941, 3563, 0),Location.create(2934, 3563, 0),Pair(Skills.SMITHING,56)),
GWD(1283,27,null,null,Pair(Skills.CRAFTING,60)),
TEMPLE(1287,29,Location.create(2949, 3835, 0),Location.create(2956, 3835, 0),Pair(Skills.SMITHING,64));
fun getOtherLocation(player: Player): Location?{
if(player.location == destinationDown) return destinationUp
else return destinationDown
}
fun getAnimation(player: Player): Animation {
if(getOtherLocation(player) == destinationDown) return Animation(1148)
else return Animation(740)
}
fun getDirection(player: Player): Direction {
if(this == BURTHORPE){
return Direction.EAST
} else return Direction.WEST
}
fun isRepaired(player: Player): Boolean{
return player.varpManager.get(varp).getVarbit(offset) == 1
}
}
companion object {
fun isRepaired(player: Player, beacon: content.minigame.allfiredup.AFUBeacon): Boolean{
if(beacon == content.minigame.allfiredup.AFUBeacon.DEATH_PLATEAU) return RepairClimbObject.DEATH_PLATEAU.isRepaired(player)
if(beacon == content.minigame.allfiredup.AFUBeacon.BURTHORPE) return RepairClimbObject.BURTHORPE.isRepaired(player)
if(beacon == content.minigame.allfiredup.AFUBeacon.GWD) return RepairClimbObject.GWD.isRepaired(player)
if(beacon == content.minigame.allfiredup.AFUBeacon.TEMPLE) return RepairClimbObject.TEMPLE.isRepaired(player)
else return true
}
}
}
@@ -0,0 +1,121 @@
package content.minigame.allfiredup
import core.api.LogoutListener
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
import org.rs09.consts.Items
import core.tools.colorize
/**
* Handles keeping track of lit beacons and their burn time remaining
* @author Ceikry
*/
class AFUSession(val player: Player? = null) : LogoutListener {
private val beaconTimers = Array(14){i -> BeaconTimer(0, content.minigame.allfiredup.AFUBeacon.values()[i]) }
private val logInventories = Array(14){Item(0,0)}
private val beaconWatched = Array(14){false}
private var isActive = false
fun init() {
isActive = true
GameWorld.Pulser.submit(object: Pulse(){
override fun pulse(): Boolean {
player!!.setAttribute("afu-pulse",this)
beaconTimers.forEach {timer ->
timer.ticks--
if(timer.ticks == 300) timer.beacon.diminish(player).also {
if(beaconWatched[timer.beacon.ordinal]){
beaconWatched[timer.beacon.ordinal] = false
timer.ticks += (getTicks(logInventories[timer.beacon.ordinal].id) * 5)
timer.beacon.light(player)
player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_"," ")} watcher has used your backup logs."))
} else {
player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_", " ")} beacon is dying!"))
}
}
if(timer.ticks == 0) timer.beacon.extinguish(player).also { player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_"," ")} beacon has gone out!")) }
}
return !isActive
}
})
player!!.setAttribute("afu-session",this)
}
fun getLitBeacons(): Int{
return beaconTimers.count { it.ticks > 0 }
}
fun end(){
isActive = false
}
fun setLogs(beaconIndex: Int, logs: Item){
logInventories[beaconIndex] = logs
}
fun startTimer(beaconIndex: Int){
val ticks = getTicks(logInventories[beaconIndex].id) * 20
logInventories[beaconIndex] = Item(0,0)
beaconTimers[beaconIndex].ticks = ticks
}
fun refreshTimer(beacon: content.minigame.allfiredup.AFUBeacon, logID: Int){
val ticks = getTicks(logID) * 5
beaconTimers.forEach {
if(it.beacon.ordinal == beacon.ordinal) it.ticks += ticks
}
}
fun setWatcher(index: Int, logs: Item){
beaconWatched[index] = true
logInventories[index] = logs
}
fun isWatched(index: Int): Boolean{
return beaconWatched[index]
}
fun getTicks(logID: Int): Int{
val ticks = when(logID){
Items.LOGS_1511 -> 65
Items.OAK_LOGS_1521 -> 68
Items.WILLOW_LOGS_1519 -> 73
Items.MAPLE_LOGS_1517 -> 79
Items.YEW_LOGS_1515 -> 83
Items.MAGIC_LOGS_1513 -> 90
else -> 0
}
return ticks
}
fun getBonusExperience(): Double{
return when(getLitBeacons()){
1 -> 608.4
2 -> 1622.4
3 -> 1987.4
4 -> 2149.6
5 -> 2149.6
6 -> 2514.6
7 -> 2555.2
8 -> 2758.0
9 -> 2839.1
10 -> 3041.9
11 -> 3123.0
12 -> 3244.7
13 -> 3366.4
14 -> 4867.4
else -> 0.0
}
}
override fun logout(player: Player) {
content.minigame.allfiredup.AFUBeacon.resetAllBeacons(player)
val session: AFUSession? = player.getAttribute("afu-session",null)
session?.end()
player.removeAttribute("afu-session")
}
internal class BeaconTimer(var ticks: Int, val beacon: content.minigame.allfiredup.AFUBeacon)
}
@@ -0,0 +1,91 @@
package content.minigame.allfiredup
import core.game.dialogue.DialoguePlugin
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import org.rs09.consts.Items
private val VALID_LOGS = arrayOf(Items.LOGS_1511, Items.OAK_LOGS_1521, Items.WILLOW_LOGS_1519, Items.MAPLE_LOGS_1517, Items.YEW_LOGS_1515, Items.MAGIC_LOGS_1513)
@Initializable
//TODO: Add requirements for beacon keepers to watch beacons, most of the requirements were not possible to implement at the time of writing this.
class BeaconTenderDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player) {
var index = 0
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
return BeaconTenderDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
index = getIndexOf((args[0] as NPC).originalId)
if(index == content.minigame.allfiredup.AFUBeacon.GWD.ordinal && player.skills.getLevel(Skills.SUMMONING) < 81){
npc("Awwf uurrrhur","(You need 81 Summoning to communicate with Nanuq.)")
stage = 1000
return true
}
if(index == content.minigame.allfiredup.AFUBeacon.MONASTERY.ordinal && player.skills.getLevel(Skills.PRAYER) < 53){
npc("I will aid you when your devotion is","strong enough.","(You need 53 Prayer for him to watch the beacon.)")
stage = 1000
return true
}
npc = (args[0] as NPC).getShownNPC(player)
npc("Hello, adventurer.")
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
val beacon = content.minigame.allfiredup.AFUBeacon.values()[index]
val logs = getLogs(player,5)
val session: AFUSession? = player.getAttribute("afu-session",null)
when(stage){
0 -> player("Hello!").also { stage++ }
1 -> if(beacon.getState(player) == content.minigame.allfiredup.BeaconState.LIT && session?.isWatched(index) == false){
options("Can you watch this beacon for me?","Nevermind.").also { stage = 10 }
} else {
npc("Carry on, adventurer.").also { stage = 1000 }
}
10 -> when(buttonId){
1 -> player("Can you watch this beacon for me?").also { stage++ }
2 -> player("Nevermind.").also { stage = 1000 }
}
11 -> npc("Certainly, adventurer. Do you have logs for me?").also { stage++ }
12 -> if(logs.id != 0){
player("Yes, I do!").also { stage++ }
} else {
player("No, I don't.").also { stage = 1000 }
}
13 -> npc("Great, hand them over.").also { stage++ }
14 -> player("Here you go!").also {
player.inventory.remove(logs)
session?.setWatcher(index,logs)
stage = 1000
}
1000 -> end()
}
return true
}
fun getIndexOf(id: Int): Int{
if(id == 8065) return 0
if(id == 8066) return 1
for(index in ids.indices){
if(ids[index] == id) return index + 2
}
return -1
}
fun getLogs(player: Player, amount: Int): Item {
var logId = 0
for (log in VALID_LOGS) if (player.inventory.getAmount(log) >= amount) {logId = log; break}
return Item(logId,amount)
}
override fun getIds(): IntArray {
return intArrayOf(8067,8068,8069,8070,8071,8072,8073,8074,8075,8076)
}
}
@@ -0,0 +1,47 @@
package content.minigame.allfiredup
import core.game.node.item.Item
import org.rs09.consts.Items
import core.game.dialogue.DialogueFile
import core.tools.END_DIALOGUE
import core.tools.START_DIALOGUE
class KingRoaldAFUMiniDialogue : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when(stage){
START_DIALOGUE -> npc("Did what?").also { stage++ }
1 -> {
if (player!!.getAttribute("afu-mini:adze", false)) {
player("I lit all 14 beacons at once!")
} else if (player!!.getAttribute("afu-mini:gloves", false)) {
player("I lit 10 beacons at once!")
} else if (player!!.getAttribute("afu-mini:ring", false)) {
player("I lit 6 beacons at once!")
}
stage++
}
2 -> {
npc("Oh, wonderful! Here is your reward then.")
if (player!!.getAttribute(
"afu-mini:adze",
false
)
) if (player!!.inventory.add(Item(Items.INFERNO_ADZE_13661))) player!!.removeAttribute("afu-mini:adze")
if (player!!.getAttribute(
"afu-mini:gloves",
false
)
) if (player!!.inventory.add(Item(Items.FLAME_GLOVES_13660))) player!!.removeAttribute("afu-mini:gloves")
if (player!!.getAttribute(
"afu-mini:ring",
false
)
) if (player!!.inventory.add(Item(Items.RING_OF_FIRE_13659))) player!!.removeAttribute("afu-mini:ring")
stage = END_DIALOGUE
}
END_DIALOGUE -> end()
}
}
}
@@ -0,0 +1,67 @@
package content.minigame.barbassault
import core.api.*
import core.game.dialogue.DialoguePlugin
import core.game.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import core.tools.END_DIALOGUE
import java.text.SimpleDateFormat
import java.time.temporal.ChronoUnit
import java.util.*
@Initializable
class CaptainCainDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player) {
val sdf = SimpleDateFormat("ddMMyyyy")
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
return CaptainCainDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "Hello, there, adventurer. Say, you wouldn't happen to be interested in purchasing a Fighter Torso would you?")
stage = 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
val start = sdf.parse("27112020").toInstant()
val now = Date().toInstant()
val days = ChronoUnit.DAYS.between(start,now)
when(stage){
0 -> npcl(core.game.dialogue.FacialExpression.ANNOYED,"I'm having to offer this service because it's been $days days since Ryan promised to give us barbarian assault.").also { stage++ }
1 -> options("Yes, please.","No, thanks.").also { stage++ }
2 -> when(buttonId){
1 -> playerl(core.game.dialogue.FacialExpression.FRIENDLY, "Yes, please.").also { stage = 10 }
2 -> playerl(core.game.dialogue.FacialExpression.HALF_THINKING, "No, thanks.").also { stage = END_DIALOGUE }
}
10 -> npcl(core.game.dialogue.FacialExpression.FRIENDLY, "Alright, then, that'll be 7,500,000 gold please.").also { stage++ }
11 -> options("Here you go!","Nevermind.").also { stage++ }
12 -> when(buttonId){
1 -> if(inInventory(player, 995, 7500000))
playerl(core.game.dialogue.FacialExpression.FRIENDLY, "Here you go!").also { stage = 20 }
else
playerl(core.game.dialogue.FacialExpression.HALF_GUILTY, "Actually, I don't have that much.").also { stage = END_DIALOGUE }
2 -> playerl(core.game.dialogue.FacialExpression.FRIENDLY, "On second thought, nevermind.").also { stage = END_DIALOGUE }
}
20 -> {
npcl(core.game.dialogue.FacialExpression.FRIENDLY, "Thank you much, kind sir. And here's your torso.")
if(removeItem(player, Item(995,7500000), Container.INVENTORY)) {
addItem(player, Items.FIGHTER_TORSO_10551, 1)
}
stage = END_DIALOGUE
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.CAPTAIN_CAIN_5030)
}
}
@@ -0,0 +1,126 @@
package content.minigame.barrows;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.BattleState;
import core.game.node.entity.combat.DeathTask;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.HintIconManager;
import core.game.world.map.Location;
import core.tools.RandomFunction;
/**
* Handles a barrow brother NPC.
* @author Emperor
*/
public final class BarrowBrother extends NPC {
/**
* The player to target.
*/
private final Player player;
/**
* Constructs a new {@code BarrowBrother} {@code Object}.
* @param player The target.
* @param id The NPC id.
* @param location The location.
*/
public BarrowBrother(Player player, int id, Location location) {
super(id, location);
this.player = player;
}
@Override
public void init() {
super.init();
super.setRespawn(false);
if (location.getZ() == 3) {
sendChat("You dare disturb my rest!");
} else {
sendChat("You dare steal from us!");
}
getProperties().getCombatPulse().attack(player);
HintIconManager.registerHintIcon(player, this);
}
@Override
public void handleTickActions() {
if (DeathTask.isDead(player)) {
return;
}
if (!player.isActive() || !player.getLocation().withinDistance(location)) {
clear();
return;
}
if (!getProperties().getCombatPulse().isAttacking()) {
getProperties().getCombatPulse().attack(player);
}
}
@Override
public void sendImpact(BattleState state) {
int maxHit = 0;
switch (getId()) {
case 2025:// ahrim
maxHit = 25;
break;
case 2026:// dharok
maxHit = 60;
break;
case 2027:// guthan
maxHit = 24;
break;
case 2028:// karil
maxHit = 20;
break;
case 2029:// torag
maxHit = 23;
break;
case 2030:// verac
maxHit = 25;
break;
}
if (state.getEstimatedHit() > maxHit) {
state.setEstimatedHit(RandomFunction.random(maxHit - 10, maxHit));
}
if (state.getSecondaryHit() > maxHit) {
state.setSecondaryHit(RandomFunction.random(maxHit - 10, maxHit));
}
}
@Override
public void finalizeDeath(Entity killer) {
super.finalizeDeath(killer);
if (killer == player) {
player.getSavedData().getActivityData().getBarrowBrothers()[getBrotherIndex()] = true;
BarrowsActivityPlugin.sendConfiguration(player);
}
}
@Override
public void clear() {
super.clear();
if (player.isActive()) {
player.getHintIconManager().clear();
}
player.removeAttribute("barrow:npc");
player.removeAttribute("brother:" + getBrotherIndex());
}
/**
* Gets the barrow brother index.
* @return The index.
*/
private int getBrotherIndex() {
return getId() - 2025;
}
/**
* Gets the player.
* @return The player.
*/
public Player getPlayer() {
return player;
}
}
@@ -0,0 +1,377 @@
package content.minigame.barrows;
import core.game.component.Component;
import core.game.activity.ActivityPlugin;
import core.game.global.action.ClimbActionHandler;
import core.game.global.action.DoorActionHandler;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.DeathTask;
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.npc.agg.AggressiveBehavior;
import core.game.node.entity.npc.agg.AggressiveHandler;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.ActivityData;
import content.global.skill.summoning.familiar.Familiar;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.update.flag.context.Graphics;
import core.net.packet.PacketRepository;
import core.net.packet.context.CameraContext;
import core.net.packet.context.CameraContext.CameraType;
import core.net.packet.context.MinimapStateContext;
import core.net.packet.out.CameraViewPacket;
import core.net.packet.out.MinimapState;
import core.plugin.Initializable;
import core.tools.RandomFunction;
import core.game.world.GameWorld;
import core.plugin.ClassScanner;
import static core.api.ContentAPIKt.getWorldTicks;
/**
* Handles the barrows activity plugin.
* @author Emperor
*/
@Initializable
public final class BarrowsActivityPlugin extends ActivityPlugin {
/**
* The tunnel configuration values.
*/
private static final int[] TUNNEL_CONFIGS = { 55328769, 2867201, 44582944, 817160, 537688072, 40763408, 44320784, 23478274 };
/**
* Represents the tunnels between 2 rooms in the barrows tunnels.
*/
public static final ZoneBorders[] MINI_TUNNELS = {
new ZoneBorders(3532, 9665, 3570, 9671),
new ZoneBorders(3575, 9676, 3570, 9671),
new ZoneBorders(3575, 9676, 3581, 9714),
new ZoneBorders(3534, 9718, 3570, 9723),
new ZoneBorders(3523, 9675, 3528, 9712),
new ZoneBorders(3541, 9711, 3545, 9712),
new ZoneBorders(3558, 9711, 3562, 9712),
new ZoneBorders(3568, 9701, 3569, 9705),
new ZoneBorders(3551, 9701, 3552, 9705),
new ZoneBorders(3534, 9701, 3535, 9705),
new ZoneBorders(3541, 9694, 3545, 9695),
new ZoneBorders(3558, 9694, 3562, 9695),
new ZoneBorders(3568, 9684, 3569, 9688),
new ZoneBorders(3551, 9684, 3552, 9688),
new ZoneBorders(3534, 9684, 3535, 9688),
new ZoneBorders(3541, 9677, 3545, 9678),
new ZoneBorders(3558, 9677, 3562, 9678),
};
/**
* The overlay.
*/
private static final Component OVERLAY = new Component(24);
/**
* The activity handling pulse.
*/
private static final Pulse PULSE = new Pulse(0) {
@Override
public boolean pulse() {
boolean end = true;
for (Player p : RegionManager.getRegionPlayers(14231)) {
end = false;
int index = p.getAttribute("barrow:drain-index", -1);
if (index > -1) {
p.removeAttribute("barrow:drain-index");
p.getPacketDispatch().sendItemOnInterface(-1, 1, 24, index);
continue;
}
if (p.getLocation().getZ() == 0 && p.getAttribute("barrow:looted", false) && getWorldTicks() % 3 == 0) {
if (RandomFunction.random(15) == 0) {
p.getImpactHandler().manualHit(p, RandomFunction.random(5), HitsplatType.NORMAL);
Graphics.send(Graphics.create(405), p.getLocation());
}
}
int drain = 8;
System.out.println(getWorldTicks() % 30);
//if (p.getLocks().isLocked("barrow:drain") || RandomFunction.random(100) % 2 == 0) {
// continue;
//}
for (boolean killed : p.getSavedData().getActivityData().getBarrowBrothers()) {
if (killed) {
drain += 1;
}
}
if(getWorldTicks() % 30 == 0){
p.getSkills().decrementPrayerPoints(drain);
p.getLocks().lock("barrow:drain", (3 + RandomFunction.random(15)) * 3);
index = 1 + RandomFunction.random(6);
p.setAttribute("barrow:drain-index", index);
p.getPacketDispatch().sendItemZoomOnInterface(4761 + RandomFunction.random(12), 100, 24, index);
p.getPacketDispatch().sendAnimationInterface(9810, 24, index);
}
}
return end;
}
};
/**
* Constructs a new {@code BarrowsActivityPlugin} {@code Object}.
*/
public BarrowsActivityPlugin() {
super("Barrows", false, false, false);
}
@Override
public void locationUpdate(Entity e, Location last) {
if (e instanceof Player && e.getViewport().getRegion().getId() == 14231) {
boolean tunnel = false;
for (ZoneBorders border : MINI_TUNNELS) {
if (border.insideBorder(e)) {
tunnel = true;
break;
}
}
Player player = (Player) e;
if ((player.getConfigManager().get(1270) == 1) != tunnel) {
player.getConfigManager().set(1270, tunnel ? 3 : 0, true);//@emp: proper value seems to be 3, val of 1 makes corridors black
}
}
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player player = (Player) e;
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2));
player.getInterfaceManager().openOverlay(OVERLAY);
player.getConfigManager().set(0, 1);
if (player.getConfigManager().get(452) == 0) {
shuffleCatacombs(player);
}
sendConfiguration(player);
if (!PULSE.isRunning()) {
PULSE.restart();
PULSE.start();
GameWorld.getPulser().submit(PULSE);
}
} else {
((NPC) e).setAggressive(true);
((NPC) e).setAggressiveHandler(new AggressiveHandler(e, new AggressiveBehavior() {
@Override
public boolean canSelectTarget(Entity entity, Entity target) {
if (!target.isActive() || DeathTask.isDead(target)) {
return false;
}
if (!target.getProperties().isMultiZone() && target.inCombat()) {
return false;
}
return true;
}
}));
}
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
player.getInterfaceManager().closeOverlay();
NPC npc = player.getAttribute("barrow:npc");
if (npc != null && !DeathTask.isDead(npc)) {
npc.clear();
}
player.removeAttribute("barrow:solvedpuzzle");
player.removeAttribute("barrow:opened_chest");
player.removeAttribute("crusade-delay");
if (!logout && player.getAttribute("barrow:looted", false)) {
for (int i = 0; i < 6; i++) {
player.removeAttribute("brother:" + i);
player.getSavedData().getActivityData().getBarrowBrothers()[i] = false;
}
player.removeAttribute("barrow:looted");
shuffleCatacombs(player);
player.getSavedData().getActivityData().setBarrowTunnelIndex(RandomFunction.random(6));
player.getSavedData().getActivityData().setBarrowKills(0);
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.RESET, 0, 0, 0, 0, 0));
}
}
return super.leave(e, logout);
}
/**
* "Shuffles" the catacomb gates.
* @param player The player.
*/
public static void shuffleCatacombs(Player player) {
int value = TUNNEL_CONFIGS[RandomFunction.random(TUNNEL_CONFIGS.length)];
value |= 1 << (6 + RandomFunction.random(4));
player.getConfigManager().set(452, value);
}
@Override
public boolean death(Entity e, Entity killer) {
Player player = null;
if (killer instanceof Player) {
player = (Player) killer;
} else if (killer instanceof Familiar) {
player = ((Familiar) killer).getOwner();
}
if (player != null && e instanceof NPC) {
player.getSavedData().getActivityData().setBarrowKills(player.getSavedData().getActivityData().getBarrowKills() + 1);
sendConfiguration(player);
}
return false;
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof Scenery) {
Scenery object = (Scenery) target;
Player player = (Player) e;
if (object.getId() >= 6702 && object.getId() <= 6707) {
ClimbActionHandler.climb((Player) e, ClimbActionHandler.CLIMB_UP, BarrowsCrypt.getCrypt(object.getId() - 6702).getExitLocation());
return true;
}
if (object.getId() >= 6708 && object.getId() <= 6712) {
ClimbActionHandler.climb((Player) e, ClimbActionHandler.CLIMB_UP, BarrowsCrypt.getCrypt(player.getSavedData().getActivityData().getBarrowTunnelIndex()).getEnterLocation());
return true;
}
switch (object.getWrapper().getId()) {
case 6727:
case 6724:
case 6746:
case 6743:
if (player.getAttribute("barrow:solvedpuzzle", false)) {
break;
}
player.setAttribute("barrow:puzzledoor", object);
BarrowsPuzzle.open(player);
return true;
}
switch (object.getId()) {
case 6714:
case 6733:
int index = -1;
int brother = player.getSavedData().getActivityData().getBarrowTunnelIndex();
if (!player.getSavedData().getActivityData().getBarrowBrothers()[brother] && RandomFunction.random(15) == 0 && !player.getAttribute("brother:" + brother, false)) {
index = brother;
}
if (index > -1) {
BarrowsCrypt.getCrypt(index).spawnBrother(player, RegionManager.getTeleportLocation(target.getLocation(), 1));
}
DoorActionHandler.handleAutowalkDoor(e, (Scenery) target);
return true;
case 6821:
BarrowsCrypt.getCrypt(BarrowsCrypt.AHRIM).openSarcophagus((Player) e, object);
return true;
case 6771:
BarrowsCrypt.getCrypt(BarrowsCrypt.DHAROK).openSarcophagus((Player) e, object);
return true;
case 6773:
BarrowsCrypt.getCrypt(BarrowsCrypt.GUTHAN).openSarcophagus((Player) e, object);
return true;
case 6822:
BarrowsCrypt.getCrypt(BarrowsCrypt.KARIL).openSarcophagus((Player) e, object);
return true;
case 6772:
BarrowsCrypt.getCrypt(BarrowsCrypt.TORAG).openSarcophagus((Player) e, object);
return true;
case 6823:
BarrowsCrypt.getCrypt(BarrowsCrypt.VERAC).openSarcophagus((Player) e, object);
return true;
case 6774:
player.lock(1);
brother = player.getSavedData().getActivityData().getBarrowTunnelIndex();
if (!player.getSavedData().getActivityData().getBarrowBrothers()[brother] && !player.getAttribute("brother:" + brother, false)) {
BarrowsCrypt.getCrypt(brother).spawnBrother(player, RegionManager.getTeleportLocation(target.getCenterLocation(), 4));
}
player.setAttribute("barrow:opened_chest", true);
sendConfiguration(player);
return true;
case 6775:
if (option.getName().equals("Close")) {
player.removeAttribute("barrow:opened_chest");
sendConfiguration(player);
return true;
}
if (player.getAttribute("barrow:looted", false)) {
player.getPacketDispatch().sendMessage("The chest is empty.");
return true;
}
player.setAttribute("/save:barrow:looted",true);
RewardChest.reward(player);
//PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.SHAKE, 3, 2, 2, 2, 2));
return true;
}
}
return false;
}
/**
* Sends the kill count configuration.
* @param player The player.
*/
public static void sendConfiguration(Player player) {
ActivityData data = player.getSavedData().getActivityData();
int config = data.getBarrowKills() << 17;
for (int i = 0; i < data.getBarrowBrothers().length; i++) {
if (data.getBarrowBrothers()[i]) { // This actually wasn't in 498
// but we'll keep it anyways.
config |= 1 << i;
}
}
if (player.getAttribute("barrow:opened_chest", false)) {
config |= 1 << 16;
}
player.getConfigManager().set(453, config);
}
@Override
public boolean actionButton(Player player, int interfaceId, int buttonId, int slot, int itemId, int opcode) {
return false;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (target instanceof BarrowBrother) {
Player p = null;
if (e instanceof Player) {
p = (Player) e;
} else if (e instanceof Familiar) {
p = ((Familiar) e).getOwner();
}
if (p != null && p != ((BarrowBrother) target).getPlayer()) {
p.getPacketDispatch().sendMessage("He's not after you.");
return false;
}
}
return super.continueAttack(e, target, style, message);
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return this;
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public void configure() {
ClassScanner.definePlugin(new TunnelEntranceDialogue());
ClassScanner.definePlugin(BarrowsPuzzle.SHAPES);
registerRegion(14231);
BarrowsCrypt.init();
PULSE.stop();
}
}
@@ -0,0 +1,191 @@
package content.minigame.barrows;
import core.game.global.action.DigAction;
import core.game.global.action.DigSpadeHandler;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
/**
* Handles a barrows crypt.
* @author Emperor
*/
public final class BarrowsCrypt {
/**
* The ahrim barrows crypt index.
*/
public static final int AHRIM = 0;
/**
* The dharok barrows crypt index.
*/
public static final int DHAROK = 1;
/**
* The guthan barrows crypt index.
*/
public static final int GUTHAN = 2;
/**
* The karil barrows crypt index.
*/
public static final int KARIL = 3;
/**
* The torag barrows crypt index.
*/
public static final int TORAG = 4;
/**
* The verac barrows crypt index.
*/
public static final int VERAC = 5;
/**
* The barrows crypts.
*/
private static final BarrowsCrypt[] CRYPTS = { new BarrowsCrypt(AHRIM, 2025, Location.create(3557, 9703, 3), Location.create(3565, 3289, 0)), new BarrowsCrypt(DHAROK, 2026, Location.create(3556, 9718, 3), Location.create(3575, 3298, 0)), new BarrowsCrypt(GUTHAN, 2027, Location.create(3534, 9704, 3), Location.create(3577, 3283, 0)), new BarrowsCrypt(KARIL, 2028, Location.create(3546, 9684, 3), Location.create(3565, 3276, 0)), new BarrowsCrypt(TORAG, 2029, Location.create(3568, 9683, 3), Location.create(3553, 3283, 0)), new BarrowsCrypt(VERAC, 2030, Location.create(3578, 9706, 3), Location.create(3557, 3298, 0)) };
/**
* The NPC id.
*/
private final int npcId;
/**
* The location to teleport to when entering the crypt.
*/
private final Location location;
/**
* The exit location.
*/
private final Location exitLocation;
/**
* The crypt index.
*/
private final int index;
/**
* Constructs a new {@code BarrowsCrypt} {@code Object}.
* @param location The location to teleport to when entering the crypt.
* @param exitLocation The location to teleport to when leaving the crypt.
*/
public BarrowsCrypt(int index, int npcId, Location location, Location exitLocation) {
this.index = index;
this.npcId = npcId;
this.location = location;
this.exitLocation = exitLocation;
}
/**
* Initializes the barrow crypts.
*/
public static void init() {
for (final BarrowsCrypt crypt : CRYPTS) {
DigAction action = new DigAction() {
@Override
public void run(Player player) {
crypt.enter(player);
}
};
Location base = crypt.getExitLocation();
for (int x = -2; x <= 2; x++) {
for (int y = -2; y <= 2; y++) {
DigSpadeHandler.register(base.transform(x, y, 0), action);
}
}
}
}
/**
* Opens the sarcophagus.
* @param player The player.
*/
public void openSarcophagus(Player player, Scenery object) {
if (index == player.getSavedData().getActivityData().getBarrowTunnelIndex()) {
player.getDialogueInterpreter().open("barrow_tunnel", index);
return;
}
if (player.getSavedData().getActivityData().getBarrowBrothers()[index] || player.getAttribute("barrow:npc") != null) {
player.getPacketDispatch().sendMessage("You don't find anything.");
return;
}
player.getPacketDispatch().sendMessage("You don't find anything.");
Location location = RegionManager.getTeleportLocation(object.getLocation().transform(Direction.SOUTH_WEST), object.getSizeX() + 1, object.getSizeY() + 1);
spawnBrother(player, location);
}
/**
* Spawns the barrow brother.
* @param player The player.
* @param location The location.
* @return {@code True} if successful.
*/
public boolean spawnBrother(Player player, Location location) {
if (player.getAttribute("brother:" + index, false)) {
return false;
}
NPC npc = new BarrowBrother(player, npcId, location);
npc.init();
player.setAttribute("barrow:npc", npc);
player.setAttribute("brother:" + index, true);
return true;
}
/**
* Enters the crypt.
* @param player The player.
*/
protected void enter(Player player) {
player.addExtension(BarrowsCrypt.class, this);
player.getPacketDispatch().sendMessage("You've broken into a crypt!");
player.getProperties().setTeleportLocation(getEnterLocation());
}
/**
* Gets the crypt for the given index.
* @param index The crypt index.
* @return The barrows crypt.
*/
public static BarrowsCrypt getCrypt(int index) {
return CRYPTS[index];
}
/**
* Gets the location to teleport to upon entering.
* @return The location.
*/
public Location getEnterLocation() {
return location;
}
/**
* Gets the exit location.
* @return The location.
*/
public Location getExitLocation() {
return exitLocation;
}
/**
* Gets the npcId.
* @return The npcId.
*/
public int getNpcId() {
return npcId;
}
/**
* Gets the index.
* @return The index.
*/
public int getIndex() {
return index;
}
}
@@ -0,0 +1,169 @@
package content.minigame.barrows;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.net.packet.PacketRepository;
import core.net.packet.context.DisplayModelContext;
import core.net.packet.context.DisplayModelContext.ModelType;
import core.net.packet.out.DisplayModel;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Handles the barrows puzzle.
* @author Emperor
*/
public final class BarrowsPuzzle extends ComponentPlugin {
/**
* The shapes puzzle.
*/
public static final BarrowsPuzzle SHAPES = new BarrowsPuzzle(new int[] { 6734, 6735, 6736 }, getAnswerModel(6731, true), getAnswerModel(6732, false), getAnswerModel(6733, false));
/**
* The lines puzzle.
*/
public static final BarrowsPuzzle LINES = new BarrowsPuzzle(new int[] { 6728, 6729, 6730 }, getAnswerModel(6725, true), getAnswerModel(6726, false), getAnswerModel(6727, false));
/**
* The squares puzzle.
*/
public static final BarrowsPuzzle SQUARES = new BarrowsPuzzle(new int[] { 6722, 6723, 6724 }, getAnswerModel(6719, true), getAnswerModel(6720, false), getAnswerModel(6721, false));
/**
* The triangle-on-circles puzzle.
*/
public static final BarrowsPuzzle TRIANGLE_CIRCLES = new BarrowsPuzzle(new int[] { 6716, 6717, 6718 }, getAnswerModel(6713, true), getAnswerModel(6714, false), getAnswerModel(6715, false));
/**
* The puzzle component.
*/
private static final Component COMPONENT = new Component(25);
/**
* The question models.
*/
private final int[] questionModels;
/**
* The answer models.
*/
private final int[] answerModels;
/**
* Constructs a new {@code BarrowsPuzzle} {@code Object}.
* @param questionModels The question models.
* @param answerModels The answer models.
*/
private BarrowsPuzzle(int[] questionModels, int... answerModels) {
this.questionModels = questionModels;
this.answerModels = answerModels;
}
/**
* Creates a new barrows puzzle instance of this puzzle.
* @return The new barrows puzzle instance.
*/
public BarrowsPuzzle create() {
int[] answers = Arrays.copyOf(answerModels, answerModels.length);
List<Integer> list = new ArrayList<>(20);
for (int answer : answers) {
list.add(answer);
}
Collections.shuffle(list, new Random());
for (int i = 0; i < list.size(); i++) {
answers[i] = list.get(i);
}
return new BarrowsPuzzle(questionModels, answers);
}
/**
* Opens a random barrows puzzle.
* @param player The player.
*/
public static void open(Player player) {
int index = RandomFunction.random(4);
if (index == player.getAttribute("puzzle:index", -1)) {
index = (index + 1) % 4;
}
open(player, index);
}
/**
* Opens the barrows puzzle for the given index.
* @param player The player.
* @param index The index (0 = shapes, 1 = lines, 2 = squares, 3 =
* triangle-on-circle).
*/
public static void open(Player player, int index) {
BarrowsPuzzle puzzle = SHAPES;
switch (index) {
case 1:
puzzle = LINES;
break;
case 2:
puzzle = SQUARES;
break;
case 3:
puzzle = TRIANGLE_CIRCLES;
break;
}
puzzle = puzzle.create();
player.setAttribute("puzzle:index", index);
player.setAttribute("puzzle:answers", puzzle.answerModels);
player.getInterfaceManager().open(COMPONENT);
for (int i = 0; i < puzzle.questionModels.length; i++) {
PacketRepository.send(DisplayModel.class, new DisplayModelContext(player, ModelType.MODEL, puzzle.questionModels[i], 0, 25, 6 + i));
}
for (int i = 0; i < puzzle.answerModels.length; i++) {
PacketRepository.send(DisplayModel.class, new DisplayModelContext(player, ModelType.MODEL, puzzle.answerModels[i] & 0xFFFF, 0, 25, 2 + i));
}
PacketRepository.send(DisplayModel.class, new DisplayModelContext(player, ModelType.MODEL, puzzle.answerModels[2] & 0xFFFF, 0, 25, 5));
}
/**
* Gets the answer model id.
* @param modelId The model id.
* @param correct If the answer is correct.
* @return The model id hash.
*/
private static int getAnswerModel(int modelId, boolean correct) {
return modelId | (correct ? 1 : 0) << 16;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(25, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (button) {
case 2:
case 3:
case 5:
player.getInterfaceManager().close();
boolean correct = ((player.getAttribute("puzzle:answers", new int[3])[button == 5 ? 2 : button - 2] >> 16) & 0xFF) == 1;
if (!correct) {
player.getPacketDispatch().sendMessage("You got the puzzle wrong! You can hear the catacombs moving around you.");
BarrowsActivityPlugin.shuffleCatacombs(player);
break;
}
player.setAttribute("/save:barrow:solvedpuzzle", true);
player.getPacketDispatch().sendMessage("You hear the doors' locking mechanism grind open.");
break;
default:
return false;
}
return true;
}
}
@@ -0,0 +1,102 @@
package content.minigame.barrows
import core.api.announceIfRare
import core.game.component.Component
import core.game.container.access.InterfaceContainer
import content.data.BossKillCounter
import core.game.node.entity.player.Player
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.tools.RandomFunction
import org.rs09.consts.Components
import org.rs09.consts.Items
import core.api.utils.WeightBasedTable
import core.api.utils.WeightedItem
/**
* The reward chest.
* @author Ceikry
* and slightly kermit
*/
object RewardChest {
/**
* The low profit drop table.
*/
private val DROP_TABLE = WeightBasedTable.create(
//Weighted total = 3050
WeightedItem(Items.COINS_995, 1, 5306, 950.0),
WeightedItem(Items.MIND_RUNE_558, 60, 60, 300.0),
WeightedItem(Items.MIND_RUNE_558, 100, 850, 300.0),
WeightedItem(Items.CHAOS_RUNE_562, 115, 720, 300.0),
WeightedItem(Items.DEATH_RUNE_560, 15, 15, 300.0),
WeightedItem(Items.DEATH_RUNE_560, 70, 230, 300.0),
WeightedItem(Items.BLOOD_RUNE_565, 35, 230, 300.0),
WeightedItem(Items.BOLT_RACK_4740, 35, 280, 300.0),
//Weight total = 975
WeightedItem(Items.SUPER_DEFENCE2_165, 1, 1, 325.0),
WeightedItem(Items.PRAYER_POTION2_141, 1, 1, 325.0),
WeightedItem(Items.RESTORE_POTION2_129, 1, 1, 325.0),
//Weight total = 53
WeightedItem(Items.TOOTH_HALF_OF_A_KEY_985, 1, 1, 25.0),
WeightedItem(Items.LOOP_HALF_OF_A_KEY_987, 1, 1, 25.0),
WeightedItem(Items.DRAGON_MED_HELM_1149, 1, 1, 3.0),
//Weight total = 120 BARROWS ITEMS V
WeightedItem(4708, 1, 1, 5.0),
WeightedItem(4710, 1, 1, 5.0),
WeightedItem(4712, 1, 1, 5.0),
WeightedItem(4714, 1, 1, 5.0),
WeightedItem(4716, 1, 1, 5.0),
WeightedItem(4718, 1, 1, 5.0),
WeightedItem(4720, 1, 1, 5.0),
WeightedItem(4722, 1, 1, 5.0),
WeightedItem(4724, 1, 1, 5.0),
WeightedItem(4726, 1, 1, 5.0),
WeightedItem(4728, 1, 1, 5.0),
WeightedItem(4730, 1, 1, 5.0),
WeightedItem(4732, 1, 1, 5.0),
WeightedItem(4734, 1, 1, 5.0),
WeightedItem(4736, 1, 1, 5.0),
WeightedItem(4738, 1, 1, 5.0),
WeightedItem(4745, 1, 1, 5.0),
WeightedItem(4747, 1, 1, 5.0),
WeightedItem(4749, 1, 1, 5.0),
WeightedItem(4751, 1, 1, 5.0),
WeightedItem(4753, 1, 1, 5.0),
WeightedItem(4755, 1, 1, 5.0),
WeightedItem(4757, 1, 1, 5.0),
WeightedItem(4759, 1, 1, 5.0)
)
/**
* Rewards the player.
*
* @param player The player.
*/
@JvmStatic
fun reward(player: Player) {
for (killed in player.savedData.activityData.barrowBrothers) {
if (!killed){
player.sendMessage("You can't loot the chest until you kill all 6 barrows brothers.")
player.removeAttribute("barrow:looted")
// Because they haven't
// actually looted the
// chest yet.
return
}
}
val rewards: MutableList<Item> = ArrayList()
var maxRolls = 2 + RandomFunction.random(1,4)
for (i in 0 until maxRolls) {
rewards.addAll(DROP_TABLE.roll())
}
InterfaceContainer.generateItems(player, rewards.toTypedArray(), arrayOf("Examine"), 364, 4,3,4)
player.interfaceManager.open(Component(Components.TRAIL_REWARD_364))
BossKillCounter.addtoBarrowsCount(player)
for(item in rewards){
announceIfRare(player, item);
if(!player.inventory.add(item)){
GroundItemManager.create(item,player)
}
}
}
}
@@ -0,0 +1,83 @@
package content.minigame.barrows;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.plugin.PluginManifest;
import core.plugin.PluginType;
/**
* The tunnel entrance dialogue handling plugin.
* @author Emperor
*/
@PluginManifest(type = PluginType.DIALOGUE)
public final class TunnelEntranceDialogue extends DialoguePlugin {
/**
* The crypt index.
*/
@SuppressWarnings("unused")
private int index;
/**
* Constructs a new {@code TunnelEntranceDialogue} {@code Object}.
*/
public TunnelEntranceDialogue() {
super();
}
/**
* Constructs a new {@code TunnelEntranceDialogue} {@code Object}.
* @param player The player.
*/
public TunnelEntranceDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new TunnelEntranceDialogue(player);
}
@Override
public boolean open(Object... args) {
this.index = (Integer) args[0];
player.getDialogueInterpreter().sendPlainMessage(false, "You find a hidden tunnel, do you want to enter?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
if (stage++ == 0) {
player.getDialogueInterpreter().sendOptions(null, "Yeah, I'm fearless!", "No way, that looks scary!");
return true;
}
switch (buttonId) {
case 1:
int offsetX = 0;
int offsetY = 0;
int configValue = player.getConfigManager().get(452);
if ((configValue & (1 << 7)) != 0) {
offsetX = 34;
offsetY = 34;
} else if ((configValue & (1 << 6)) != 0) {
offsetY = 34;
} else if ((configValue & (1 << 9)) != 0) {
offsetX = 34;
}
int x = 3534 + offsetX;
int y = 9677 + offsetY;
player.getProperties().setTeleportLocation(Location.create(x, y, 0));
case 2:
end();
return true;
}
return false;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("barrow_tunnel") };
}
}
@@ -0,0 +1,360 @@
package content.minigame.blastfurnace
import core.api.*
import core.game.container.impl.EquipmentContainer
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import content.global.skill.smithing.smelting.Bar
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.tools.RandomFunction
import org.rs09.consts.Items
import org.rs09.consts.Items.GOLDSMITH_GAUNTLETS_776
/**le Blast Furnace has arrived:
* Handles most of the Blast Furnace's operating logic, there is some crosstalk between
* this file and BlastFurnaceListeners.kt as well as the BlastFurnaceZone.kt.
* This also handles a lot of the varbit fuckery for the furnace. The other
* varbit fuckery is handled in BlastFurnaceListeners.
* Varbits are still slightly busted but not in a way that breaks the operation or usage of
* Blast Furnace, just visual and I've had enough of the funny binary numbers to say fuck it
* and will just come back to it at a later date.
* @author phil lips*/
object BlastFurnace {
val belt1 = getScenery(1943, 4967, 0)
val belt2 = getScenery(1943, 4966, 0)
val belt3 = getScenery(1943, 4965, 0)
val disLoc = getScenery(1941, 4963, 0)
var pipe1 = getScenery(1943, 4961, 0)
var pipe2 = getScenery(1947, 4961, 0)
var cogs1 = getScenery(1945, 4965, 0)
var cogs2 = getScenery(1945, 4967, 0)
var beltLoc1 = getScenery(1944, 4965, 0)
var beltLoc2 = getScenery(1944, 4967, 0)
var gearsLoc = getScenery(1945, 4966, 0)
var stoveLoc = getScenery(1948, 4963, 0)
val mPot = 9098
var gaugeViewList = ArrayList<Player>()
var blastFurnacePlayerList = ArrayList<Player>()
var furnaceTemp = 0
var pumpPipeBroken = false
var potPipeBroken = false
var stoveCoke = 0
var stoveTemp = 0
var beltRunning = false
var makeBars = false
var beltBroken = false
var cogBroken = false
var pumping = false
var pedaling = false
var barsHot = false
var giveSmithXp = 0
/**This pulse object handles checks between*/
var blastPulse = object : Pulse() {
override fun pulse(): Boolean {
gaugeViewList.forEach {
var anim = furnaceTemp + 2452
animateInterface(it, 30, 4, anim)
}
blastFurnacePlayerList.forEach {
if(it.getAttribute("BlastTimer",0) > 0 && it.getSkills().getLevel(Skills.SMITHING) < 60){
it.incrementAttribute("BlastTimer",-1)
} else if(it.getAttribute("BlastTimer",0) <= 0 && it.getSkills().getLevel(Skills.SMITHING) < 60){
it.removeAttribute("BlastTimer")
sendDialogue(it,"Your time in the Blast Furnace has run out!")
it.properties.teleportLocation = Location.create(2931, 10197, 0)
} else if(it.getAttribute("BlastTimer",false) && it.getSkills().getLevel(Skills.SMITHING) >= 60){
it.removeAttribute("BlastTimer")
}
if(giveSmithXp > 0){
rewardXP(it,Skills.SMITHING,1.0)
giveSmithXp--
}
}
interfaceManager()
runConveyor()
stoveCokeTemperature()
furnaceTemperature()
operateFurnace()
breakStuff()
fixStuff()
return false
}
}
/**This handles the coke stove temperature, if there is coke in the
* coke oven the temperature will raise, otherwise the temperature
* will lower, 0-33 is cold, 34-66 is warm, 67-100 is hot*/
fun stoveCokeTemperature() {
if (getWorldTicks() % 10 == 0 && stoveCoke > 0) {
stoveCoke--
}
if (stoveCoke > 0) {
if (stoveTemp < 100) {
stoveTemp += 1
}
} else if (stoveTemp > 0) {
stoveTemp--
}
if (stoveTemp > 66 && stoveLoc!!.id != 9087) {
stoveLoc = getScenery(1948, 4963, 0)
replaceScenery(stoveLoc!!, 9087, -1)
} else if (stoveTemp in 34..66 && stoveLoc!!.id != 9086) {
stoveLoc = getScenery(1948, 4963, 0)
replaceScenery(stoveLoc!!, 9086, -1)
} else if (stoveTemp < 32 && stoveLoc!!.id != 9085) {
stoveLoc = getScenery(1948, 4963, 0)
replaceScenery(stoveLoc!!, 9085, -1)
}
}
/**This handles the raising and lowering of the furnace temperature
* depending on whether or not the coke stove is hot and if the
* furnace pump is being operated. A hot coke stove will raise the
* temperature the fastest, a warm coke stove will raise it slowly,
* and a cold stove will raise it the slowest*/
fun furnaceTemperature() {
if (stoveTemp >= 67 && pumping && furnaceTemp < 100 && (!pumpPipeBroken || !pumpPipeBroken)) {
furnaceTemp += 3
} else if (stoveTemp >= 34 && pumping && furnaceTemp < 100 && (!pumpPipeBroken || !pumpPipeBroken)) {
furnaceTemp += 2
} else if (stoveTemp > 0 && pumping && furnaceTemp < 100 && (!pumpPipeBroken || !pumpPipeBroken)) {
furnaceTemp += 1
} else if (furnaceTemp > 0) {
furnaceTemp -= 1
}
}
/**Tells the furnace whether or not to smelt bars depending on if
* the furnace temperature is in the right range. Also contains the
* logic for smelting the players ore given the fact that they actually
* have ore in their ore container and/or have coal in their coal container*/
fun operateFurnace() {
makeBars = furnaceTemp in 51..66
blastFurnacePlayerList.forEach { player ->
var playerCoal = player.blastCoal.getAmount(Items.COAL_453)
var playerOre = player.blastOre.toArray().filterNotNull()
var barsAmountFree = player.blastBars.freeSlots()
var barsAmount = player.blastBars.itemCount()
var oreAmount = player.blastOre.itemCount()
var totalAmount = barsAmount + oreAmount
if (barsHot) {
player.varpManager.get(543).setVarbit(8, 2).send(player)
}else if (makeBars && playerOre.isNotEmpty() && barsAmountFree > 0 && totalAmount < 56 && player.getAttribute("OreInPot",false) == true) {
playerOre.forEach { oreID ->
playerCoal = player.blastCoal.getAmount(Items.COAL_453)
var bars = arrayOf(Bar.forOre(oreID.id)!!)
if(oreID.id == Items.IRON_ORE_440) {
bars = arrayOf(Bar.STEEL, Bar.IRON)
}
inner@ for(bar in bars) {
var hasRequirements = true
for(required in bar.ores) {
if(required.id == Items.COAL_453) {
if(!player.blastCoal.contains(Items.COAL_453, required.amount / 2)) {
hasRequirements = false
}
} else if(!player.blastOre.containsItem(required)) {
hasRequirements = false
}
}
if(hasRequirements) {
var removed = true
for(required in bar.ores) {
if(required.id == Items.COAL_453) {
if(!player.blastCoal.remove(Item(Items.COAL_453, required.amount / 2))) {
removed = false
}
} else {
if(!player.blastOre.remove(required)) {
removed = false
}
}
}
if(removed) {
player.varpManager.get(543).setVarbit(8, 1).send(player)
barsHot = true
player.blastBars.add(bar.product)
var experience = bar.experience
if(bar.product.id == Items.GOLD_BAR_2357 &&
player.equipment[EquipmentContainer.SLOT_HANDS] != null &&
player.equipment[EquipmentContainer.SLOT_HANDS].id == GOLDSMITH_GAUNTLETS_776) {
experience *= 2.5;
}
rewardXP(player, Skills.SMITHING, experience)
totalAmount = barsAmount + oreAmount
giveSmithXp++
break@inner
}
}
}
}
}
if(!barsHot && playerOre.isNotEmpty()) {
var coalToAdd = 0
playerOre.forEach { oreID ->
when(oreID.id){
Items.RUNITE_ORE_451 -> coalToAdd = (player.blastOre.getAmount(451) * 4) - playerCoal
Items.ADAMANTITE_ORE_449 -> coalToAdd = (player.blastOre.getAmount(449) * 3) - playerCoal
Items.MITHRIL_ORE_447 -> coalToAdd = (player.blastOre.getAmount(447) * 2) - playerCoal
Items.IRON_ORE_440 -> coalToAdd = player.blastOre.getAmount(440) - playerCoal
}
}
if (coalToAdd < 0){
player.varpManager.get(543).setVarbit(12, 0).send(player)
} else player.varpManager.get(543).setVarbit(12, coalToAdd).send(player)
}
else if(playerOre.isEmpty()) {
player.varpManager.get(543).setVarbit(12,0).send(player)
}
if(playerOre.isEmpty() && player.getAttribute("OreInPot",false)){
player.removeAttribute("OreInPot")
}
}
}
/**This handles the conveyor belt, if the pedals are running and the belt
* isn't broken then the conveyor belt will run*/
fun runConveyor() {
if (pedaling && (!beltBroken && !cogBroken)) {
animateScenery(belt1!!, 2435)
animateScenery(belt2!!, 2435)
animateScenery(belt3!!, 2435)
animateScenery(beltLoc1!!, 2436)
animateScenery(beltLoc2!!, 2436)
animateScenery(cogs1!!, 2436)
animateScenery(cogs2!!, 2436)
animateScenery(gearsLoc!!, 2436)
beltRunning = true
} else {
animateScenery(belt1!!, -1)
animateScenery(belt2!!, -1)
animateScenery(belt3!!, -1)
animateScenery(beltLoc1!!, -1)
animateScenery(beltLoc2!!, -1)
animateScenery(cogs1!!, -1)
animateScenery(cogs2!!, -1)
animateScenery(gearsLoc!!, -1)
beltRunning = false
}
}
/**Its just one of those days*/
fun breakStuff() {
if (pumping && furnaceTemp > 76) {
if (RandomFunction.random(1, 100) > 20 && (!potPipeBroken || !pumpPipeBroken)) {
if (RandomFunction.random(1, 100) > 50 && !potPipeBroken) {
pipe1 = getScenery(1943, 4961, 0)
potPipeBroken = true
}
if (RandomFunction.random(1, 100) <= 50 && !pumpPipeBroken) {
pipe2 = getScenery(1947, 4961, 0)
pumpPipeBroken = true
}
}
}
if (beltRunning && (!beltBroken || !cogBroken)) {
if (RandomFunction.random(1, 100) <= 2) {
beltLoc2 = getScenery(1944, 4967, 0)
beltBroken = true
} else if (RandomFunction.random(1, 100) <= 2) {
cogs2 = getScenery(1945, 4967, 0)
cogBroken = true
}
}
if (beltBroken && beltLoc2!!.id != 9103) {
beltLoc2 = getScenery(1944, 4967, 0)
replaceScenery(beltLoc2!!, 9103, -1)
}
if (cogBroken && cogs2!!.id != 9105) {
cogs2 = getScenery(1945, 4967, 0)
replaceScenery(cogs2!!, 9105, -1)
}
if (potPipeBroken && pipe1!!.id != 9117) {
pipe1 = getScenery(1943, 4961, 0)
replaceScenery(pipe1!!, 9117, -1)
}
if (pumpPipeBroken && pipe2!!.id != 9121) {
pipe2 = getScenery(1947, 4961, 0)
replaceScenery(pipe2!!, 9121, -1)
}
}
/**This replaces the breakable objects IDs back to their unbroken state*/
fun fixStuff() {
if (!potPipeBroken && pipe1!!.id != 9116) {
pipe1 = getScenery(1943, 4961, 0)
replaceScenery(pipe1!!, 9116, -1)
}
if (!pumpPipeBroken && pipe2!!.id != 9120) {
pipe2 = getScenery(1947, 4961, 0)
replaceScenery(pipe2!!, 9120, -1)
}
if (!beltBroken && beltLoc2!!.id != 9102) {
beltLoc2 = getScenery(1944, 4967, 0)
replaceScenery(beltLoc2!!, 9102, -1)
}
if (!cogBroken && cogs2!!.id != 9104) {
cogs2 = getScenery(1945, 4967, 0)
replaceScenery(cogs2!!, 9104, -1)
}
}
/**Hi kids!
* Do you like Varbits?
* Wanna see me stick Nine Binary Bytes, through each one of my eyelids?
* Wanna look at how many bars you have left inside the furnace???*/
fun interfaceManager() {
var playerBars = listOf<Item>()
var bronzeBit = 1
var ironBit = 1
var steelBit = 1
var mithrilBit = 1
var adamantiteBit = 1
var runiteBit = 1
var silverBit = 1
var goldBit = 1
var barTotal = 0
blastFurnacePlayerList.forEach { player ->
playerBars = player.blastBars.toArray().filterNotNull()
var barAmount = player.blastBars.toArray().filterNotNull().count()
var updateInterface = true
if (playerBars.isNotEmpty() && updateInterface) {
playerBars.forEach { barItem ->
when (barItem.id) {
Items.BRONZE_BAR_2349 -> player.varpManager.get(545).setVarbit(0, bronzeBit++).send(player)
Items.IRON_BAR_2351 -> player.varpManager.get(545).setVarbit(8, ironBit++).send(player)
Items.STEEL_BAR_2353 -> player.varpManager.get(545).setVarbit(16, steelBit++).send(player)
Items.MITHRIL_BAR_2359 -> player.varpManager.get(545).setVarbit(24, mithrilBit++).send(player)
Items.ADAMANTITE_BAR_2361 -> player.varpManager.get(546).setVarbit(0, adamantiteBit++).send(player)
Items.RUNITE_BAR_2363 -> player.varpManager.get(546).setVarbit(8, runiteBit++).send(player)
Items.SILVER_BAR_2355 -> player.varpManager.get(546).setVarbit(24, silverBit++).send(player)
Items.GOLD_BAR_2357 -> player.varpManager.get(546).setVarbit(16, goldBit++).send(player)
}
}
}
if (barTotal > barAmount) {
playerBars.forEach { barItem ->
when (barItem.id) {
Items.BRONZE_BAR_2349 -> player.varpManager.get(545).setVarbit(0, bronzeBit--).send(player)
Items.IRON_BAR_2351 -> player.varpManager.get(545).setVarbit(8, ironBit--).send(player)
Items.STEEL_BAR_2353 -> player.varpManager.get(545).setVarbit(16, steelBit--).send(player)
Items.MITHRIL_BAR_2359 -> player.varpManager.get(545).setVarbit(24, mithrilBit--).send(player)
Items.ADAMANTITE_BAR_2361 -> player.varpManager.get(546).setVarbit(0, adamantiteBit--).send(player)
Items.RUNITE_BAR_2363 -> player.varpManager.get(546).setVarbit(8, runiteBit--).send(player)
Items.SILVER_BAR_2355 -> player.varpManager.get(546).setVarbit(24, silverBit--).send(player)
Items.GOLD_BAR_2357 -> player.varpManager.get(546).setVarbit(16, goldBit--).send(player)
}
}
}
}
}
}
@@ -0,0 +1,72 @@
package content.minigame.blastfurnace
import core.api.*
import core.game.node.item.Item
import org.rs09.consts.Components
import org.rs09.consts.Items
import core.game.interaction.InterfaceListener
/**
* Handles the blast furnace bar stock interface.
* @author definitely phil who didn't get help from ceikry at all haha :)
* @version 69.0
*/
class BlastFurnaceInterfaceListener : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.BLAST_FURNACE_BAR_STOCK_28){ player, _, _, buttonID, _, _ ->
val bar = BFBars.forId(buttonID) ?: return@on false
val isAll = buttonID == bar.allButtonId
val playerAmt = player.varpManager.get(bar.varpIndex).getVarbitValue(bar.offset) ?: 0
if(playerAmt == 0) return@on true
var amtToWithdraw = if(isAll) playerAmt else 1
if(freeSlots(player) < amtToWithdraw){
amtToWithdraw = freeSlots(player)
}
val barItemId = when(bar){
BFBars.BRONZE -> Items.BRONZE_BAR_2349
BFBars.IRON -> Items.IRON_BAR_2351
BFBars.STEEL -> Items.STEEL_BAR_2353
BFBars.MITHRIL -> Items.MITHRIL_BAR_2359
BFBars.ADAMANT -> Items.ADAMANTITE_BAR_2361
BFBars.RUNITE -> Items.RUNITE_BAR_2363
BFBars.SILVER -> Items.SILVER_BAR_2355
BFBars.GOLD -> Items.GOLD_BAR_2357
}
player.varpManager.get(bar.varpIndex).setVarbit(bar.offset, playerAmt - amtToWithdraw).send(player)
addItem(player, barItemId, amtToWithdraw)
while(amtToWithdraw > 0){
player.blastBars.remove(Item(barItemId))
amtToWithdraw--
}
if(player.blastBars.isEmpty) player.varpManager.get(543).clear().send(player)
return@on true
}
}
internal enum class BFBars(val buttonId: Int, val varpIndex: Int, val offset: Int, val allButtonId: Int = buttonId + 2){
BRONZE(43, 545, 0, 44),
IRON(40, 545, 8, 41),
STEEL(36, 545, 16),
MITHRIL(33, 545, 24),
ADAMANT(30, 546, 0),
RUNITE(27, 546, 8),
SILVER(24, 546, 24),
GOLD(21, 546, 16);
companion object {
private val idMap = values().map { it.buttonId to it }.toMap()
fun forId(buttonId: Int): BFBars? {
return idMap[buttonId] ?: idMap[buttonId - 2] ?: idMap[buttonId - 1]
}
}
}
}
@@ -0,0 +1,383 @@
package content.minigame.blastfurnace
import core.api.Container
import core.api.*
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import content.global.skill.smithing.smelting.Bar
import core.game.system.task.Pulse
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import core.game.world.map.Location
import org.rs09.consts.Items
/**"Most" of the listeners for blast furnace live in this funny little file, handles
* listeners for most things from interacting with the temp gauge to putting ore on the
* conveyor belt. The only thing that's not in here as far as listeners goes is Ordan's unnoting.
* That lives in OrdanDialogue.kt
* @author phil lips*/
class BlastFurnaceListeners : InteractionListener {
val disLoc = getScenery(1941, 4963, 0)
val brokenPotPipe = 9117
val brokenPumpPipe = 9121
val pump = 9090
val stove = intArrayOf(9085, 9086, 9087)
val coke = 9088
val pedals = 9097
val conveyorLoad = 9100
val dispenser = intArrayOf(9093, 9094, 9095, 9096)
val brokenBelt = 9103
val brokenCog = 9105
val tGauge = 9089
val playerOre = intArrayOf(
Items.IRON_ORE_440,
Items.COPPER_ORE_436,
Items.TIN_ORE_438,
Items.COAL_453,
Items.MITHRIL_ORE_447,
Items.ADAMANTITE_ORE_449,
Items.SILVER_ORE_442,
Items.GOLD_ORE_444,
Items.RUNITE_ORE_451
)
val notedOre = intArrayOf(
Items.IRON_ORE_441,
Items.COPPER_ORE_437,
Items.TIN_ORE_439,
Items.COAL_454,
Items.MITHRIL_ORE_448,
Items.ADAMANTITE_ORE_450,
Items.SILVER_ORE_443,
Items.GOLD_ORE_445,
Items.RUNITE_ORE_452
)
override fun defineListeners() {
/**FINALLY AFK STRENGTH TRAINING*/
on(pump, IntType.SCENERY, "operate") { player, node ->
if(player.getSkills().getLevel(Skills.STRENGTH) >= 30) {
val pumpL = Location(1950, 4961, 0)
val pumpF = Location(1949, 4961, 0)
player.properties.teleportLocation = pumpL
submitIndividualPulse(player, object : Pulse() {
override fun pulse(): Boolean {
face(player, pumpF,)
animate(player, 2432)
BlastFurnace.pumping = true
if (!BlastFurnace.pumpPipeBroken || !BlastFurnace.potPipeBroken) rewardXP(
player,
Skills.STRENGTH,
4.0
)
return false
}
override fun stop() {
BlastFurnace.pumping = false
super.stop()
}
})
}else{
sendDialogue(player,"I need 30 Strength to do this!")
}
return@on true
}
/**Logic for the pedals that run the conveyor, rewards Agility XP every tick that they're being
* pedaled but will stop once the conveyor breaks.*/
on(pedals, IntType.SCENERY, "pedal") { player, node ->
if(player.getSkills().getLevel(Skills.AGILITY) >= 30) {
val pedalL = Location(1947, 4966, 0)
val pedalF = Location(1946, 4966, 0)
player.properties.teleportLocation = pedalL
submitIndividualPulse(player, object : Pulse() {
override fun pulse(): Boolean {
face(player, pedalF,)
animate(player, 2433)
BlastFurnace.pedaling = true
if (BlastFurnace.beltRunning) rewardXP(player, Skills.AGILITY, 2.0)
return false
}
override fun stop() {
BlastFurnace.pedaling = false
super.stop()
}
})
}else{
sendDialogue(player,"I need 30 Agility to do this!")
}
return@on true
}
/**Lets players use a spade to take coke from the pile of coke*/
on(coke, IntType.SCENERY, "collect") { player, node ->
if (inInventory(player, Items.SPADE_952, 1)) {
animate(player, 2441)
removeItem(player, Items.SPADE_952, Container.INVENTORY)
addItem(player, Items.SPADEFUL_OF_COKE_6448, 1)
lockInteractions(player,1)
} else {
sendMessage(player, "You need a spade to do this!")
}
return@on true
}
/**This code is for handling the coke stove, lets players interact with it with the spadeful of coke
* and rewards firemaking XP when shoving coke in there, it will not allow players to shovel more
* coke in if it is already full.*/
on(stove, IntType.SCENERY, "refuel") { player, node ->
if (inInventory(player, Items.SPADEFUL_OF_COKE_6448, 1) && BlastFurnace.stoveCoke < 30 && player.getSkills().getLevel(Skills.FIREMAKING) >= 30) {
animate(player, 2442)
lockInteractions(player,2)
submitIndividualPulse(player, object : Pulse() {
override fun pulse(): Boolean {
removeItem(player, Items.SPADEFUL_OF_COKE_6448, Container.INVENTORY)
addItem(player, Items.SPADE_952, 1)
animate(player, 2443)
return true
}
})
rewardXP(player, Skills.FIREMAKING, 5.0)
BlastFurnace.stoveCoke++
}else if(inInventory(player, Items.SPADEFUL_OF_COKE_6448,1) && BlastFurnace.stoveCoke >= 30 && player.getSkills().getLevel(Skills.FIREMAKING) >= 30){
sendDialogue(player,"The coke stove is already full!")
} else if(player.getSkills().getLevel(Skills.FIREMAKING) < 30){
sendDialogue(player,"I need 30 Firemaking to do this")
} else {
sendMessage(player,"You need some coke to do that!")
}
return@on true
}
/**This beautiiful block of bullshit handles the logic for putting coal and ores
* on the conveyor belt. It won't let you put anything on there if there's no room
* in your blast ore or blast coal player containers, the way it works is that it
* puts your coal and ore into the blast furnace containers however, the blast furnace will NOT
* smelt your ores because it's waiting for a player attribute to be set by the ore NPCs that this spawns
* Is it fucky? Yes
* Does it work? Also yes*/
on(conveyorLoad, IntType.SCENERY, "put-ore-on") { player, node ->
val rocksInInven = playerOre.filter {inInventory(player, it)}
var oreToActuallyAdd = 0
var coalToActuallyAdd = 0
if(player.blastCoal.freeSlots() > 0 || player.blastOre.freeSlots() > 0) {
player.dialogueInterpreter.sendOptions("Add all your ore to the furnace?", "Yes", "No")
player.dialogueInterpreter.addAction { player, button ->
if (button == 2 && rocksInInven.isNotEmpty()) {
rocksInInven.forEach { oreID ->
val oreAmount = amountInInventory(player, oreID)
val copperInPot = player.blastOre.getAmount(436)
val tinInPot = player.blastOre.getAmount(438)
if(oreID == Items.COAL_453 && oreAmount <= player.blastCoal.freeSlots()){
coalToActuallyAdd = oreAmount
}else if(oreID == Items.COAL_453 && oreAmount > player.blastCoal.freeSlots() && player.blastCoal.freeSlots() > 0){
coalToActuallyAdd = player.blastCoal.freeSlots()
}
if(oreID != Items.COAL_453 && oreAmount <= player.blastOre.freeSlots()){
oreToActuallyAdd = oreAmount
}else if(oreID != Items.COAL_453 && oreAmount > player.blastOre.freeSlots() && player.blastOre.freeSlots() > 0){
oreToActuallyAdd = player.blastOre.freeSlots()
}
if(oreID == Items.COPPER_ORE_436 && (oreToActuallyAdd + copperInPot) > 14){
while(oreToActuallyAdd + copperInPot > 14){
oreToActuallyAdd--
}
}
if(oreID == Items.TIN_ORE_438 && (oreToActuallyAdd + tinInPot) > 14){
while(oreToActuallyAdd + tinInPot > 14){
oreToActuallyAdd--
}
}
val bar = Bar.forOre(oreID)
if(oreID == Items.COAL_453) {
if (coalToActuallyAdd > 0 && getStatLevel(player, Skills.SMITHING) >= 30) {
player.blastCoal.add(Item(Items.COAL_453,coalToActuallyAdd))
removeItem(player, Item(oreID, coalToActuallyAdd), Container.INVENTORY)
BlastFurnaceOre(player, BFOreVariant.values()[playerOre.indexOf(oreID)],coalToActuallyAdd).init()
}
else if(getStatLevel(player, Skills.SMITHING) < 30){
sendDialogue(player, "My Smithing level is not high enough to use Coal!")
}
else sendDialogue(player, "It looks like the melting pot is already full of coal!")
} else if (bar != null) {
if (oreToActuallyAdd > 0 && getStatLevel(player, Skills.SMITHING) >= bar.level) {
player.blastOre.add(Item(oreID,oreToActuallyAdd))
removeItem(player, Item(oreID, oreToActuallyAdd), Container.INVENTORY)
BlastFurnaceOre(player, BFOreVariant.values()[playerOre.indexOf(oreID)],oreToActuallyAdd).init()
}
else if(getStatLevel(player, Skills.SMITHING) < bar.level){
sendDialogue(player, "My Smithing level is not high enough to smelt ${bar.name.toLowerCase()}!")
}
else sendDialogue(player, "It looks like the melting pot is already full of ore!")
}
}
}else if (button == 2 && rocksInInven.isEmpty()){
sendDialogue(player,"I should make sure that I have some ore before doing this.")
}
}
}
return@on true
}
/**Added this because clicking on ore then the belt and getting "Nothing interesting happens" is annoying
* it's essentially the same thing as above except without the dialogue because if you're clicking on ore
* and trying to use it on the conveyor belt then you know what you're trying to do.*/
onUseWith(IntType.SCENERY,conveyorLoad,*playerOre){ player, _, oreType ->
val amountInInventory = player.inventory.getAmount(oreType.id)
val spaceForCoal = player.blastCoal.freeSlots()
val spaceForOre = player.blastOre.freeSlots()
val copperInPot = player.blastOre.getAmount(436)
val tinInPot = player.blastOre.getAmount(438)
var amountToAdd = 0
if(oreType.id == Items.COAL_453 && amountInInventory <= spaceForCoal){
amountToAdd = amountInInventory
}else if(oreType.id == Items.COAL_453 && amountInInventory > spaceForCoal){
amountToAdd = spaceForOre
}
if(oreType.id != Items.COAL_453 && amountInInventory <= spaceForOre){
amountToAdd = amountInInventory
}else if(oreType.id != Items.COAL_453 && amountInInventory > spaceForOre){
amountToAdd = spaceForOre
}
if(oreType.id == Items.COPPER_ORE_436 && (amountToAdd + copperInPot) > 14){
while(amountToAdd + copperInPot > 14){
amountToAdd--
}
}
if(oreType.id == Items.TIN_ORE_438 && (amountToAdd + tinInPot) > 14){
while(amountToAdd + tinInPot > 14){
amountToAdd--
}
}
val bar = Bar.forOre(oreType.id)
if(oreType.id == Items.COAL_453) {
if (amountToAdd > 0 && getStatLevel(player, Skills.SMITHING) >= 30) {
player.blastCoal.add(Item(oreType.id,amountToAdd))
removeItem(player, Item(oreType.id, amountToAdd), Container.INVENTORY)
BlastFurnaceOre(player, BFOreVariant.values()[playerOre.indexOf(oreType.id)],amountToAdd).init()
}else if(getStatLevel(player,Skills.SMITHING) < 30){
sendDialogue(player,"My Smithing level is not high enough to use Coal!")
}
else sendDialogue(player, "It looks like the melting pot is already full of ore!")
} else if(bar != null) {
if (amountToAdd > 0 && getStatLevel(player, Skills.SMITHING) >= bar.level) {
player.blastOre.add(Item(oreType.id,amountToAdd))
removeItem(player, Item(oreType.id, amountToAdd), Container.INVENTORY)
BlastFurnaceOre(player, BFOreVariant.values()[playerOre.indexOf(oreType.id)],amountToAdd).init()
}else if(getStatLevel(player,Skills.SMITHING) < bar.level){
sendDialogue(player,"My Smithing level is not high enough to smelt Iron!")
}
else sendDialogue(player, "It looks like the melting pot is already full of ore!")
}
return@onUseWith true
}
/**This handles interacting with the temperature gauge on the furnace*/
on(tGauge, IntType.SCENERY, "read") { player, node ->
player.interfaceManager.openComponent(30)
return@on true
}
/**This handles taking bars from the dispenser*/
on(dispenser, IntType.SCENERY, "search", "take"){ player, node ->
if(player.varpManager.get(543).getVarbitValue(8) == 0 || player.varpManager.get(543).getVarbitValue(8) == 3) {
player.interfaceManager.openComponent(28)
}
return@on true
}
/**Handles using a bucket of water on the bar dispenser*/
onUseWith(IntType.SCENERY,dispenser,Items.BUCKET_OF_WATER_1929){ player, used, with ->
when {
player.varpManager.get(543).getVarbitValue(8) == 2 -> {
removeItem(player,Items.BUCKET_OF_WATER_1929,Container.INVENTORY)
addItem(player,Items.BUCKET_1925)
BlastFurnace.barsHot = false
player.varpManager.get(543).setVarbit(8,3).send(player)
}
player.varpManager.get(543).getVarbitValue(8) == 0 -> {
sendDialogue(player,"There's nothing to cool off!")
}
player.varpManager.get(543).getVarbitValue(8) == 1 -> {
sendDialogue(player,"I should wait until the machine is finished")
}
player.varpManager.get(543).getVarbitValue(8) == 3 -> {
sendDialogue(player,"These bars have already cooled off!")
}
}
return@onUseWith true
}
/**The sequel to Limp Bizkits hit single, "Fix shit"*/
on(brokenPotPipe, IntType.SCENERY, "repair"){ player, _ ->
if(player.getSkills().getLevel(Skills.CRAFTING) >= 30){
if(inInventory(player,Items.HAMMER_2347,1)) {
rewardXP(player, Skills.CRAFTING, 50.0)
BlastFurnace.potPipeBroken = false
}
else {
sendMessage(player, "I need a hammer to do this!")
}
}else{
sendDialogue(player,"I need 30 Craft in order to do this")
}
return@on true
}
on(brokenPumpPipe, IntType.SCENERY, "repair"){ player, _ ->
if(player.getSkills().getLevel(Skills.CRAFTING) >= 30){
if(inInventory(player,Items.HAMMER_2347,1)) {
rewardXP(player, Skills.CRAFTING, 50.0)
BlastFurnace.pumpPipeBroken = false
}
else {
sendMessage(player, "I need a hammer to do this!")
}
}else{
sendDialogue(player,"I need 30 Craft in order to do this")
}
return@on true
}
on(brokenBelt, IntType.SCENERY, "repair"){ player, _ ->
if(player.getSkills().getLevel(Skills.CRAFTING) >= 30){
if(inInventory(player,Items.HAMMER_2347,1)) {
rewardXP(player, Skills.CRAFTING, 50.0)
BlastFurnace.beltBroken = false
}
else {
sendMessage(player, "I need a hammer to do this!")
}
}else{
sendDialogue(player,"I need 30 Craft in order to do this")
}
return@on true
}
on(brokenCog, IntType.SCENERY, "repair"){ player, _ ->
if(player.getSkills().getLevel(Skills.CRAFTING) >= 30){
if(inInventory(player,Items.HAMMER_2347,1)) {
rewardXP(player, Skills.CRAFTING, 50.0)
BlastFurnace.cogBroken = false
}
else {
sendMessage(player, "I need a hammer to do this!")
}
}else{
sendDialogue(player,"I need 30 Craft in order to do this")
}
return@on true
}
}
}
@@ -0,0 +1,91 @@
package content.minigame.blastfurnace
import core.api.*
import core.game.node.entity.npc.AbstractNPC
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import org.rs09.consts.NPCs
/**On god this is like 95% ceikry and 5% me adding a setAttribute to the clear code
* @author funny alium man*/
@Initializable
class BlastFurnaceOre : AbstractNPC {
//Arios constructor spaghetti
constructor() : super(NPCs.COAL_2562, null, true) {}
private constructor(id: Int, location: Location) : super(id, location) {}
constructor(owner: Player, variant: BFOreVariant, amount: Int) : super(
when(variant){
BFOreVariant.IRON -> NPCs.IRON_ORE_2556
BFOreVariant.COPPER -> NPCs.COPPER_ORE_2555
BFOreVariant.TIN -> NPCs.TIN_ORE_2554
BFOreVariant.COAL -> NPCs.COAL_2562
BFOreVariant.MITHRIL -> NPCs.MITHRIL_ORE_2557
BFOreVariant.ADAMANT -> NPCs.ADAMANTITE_ORE_2558
BFOreVariant.SILVER -> NPCs.SILVER_ORE_2560
BFOreVariant.GOLD -> NPCs.GOLD_ORE_2561
BFOreVariant.RUNITE -> NPCs.RUNITE_ORE_2559
}, Location.create(1942, 4966, 0)) {this.owner = owner; isRespawn = false; }
var owner: Player? = null
var delay = 2
var counter = 3
override fun construct(id: Int, location: Location, vararg objects: Any): AbstractNPC {
return BlastFurnaceOre(id, location)
}
override fun getIds(): IntArray {
return intArrayOf(
NPCs.IRON_ORE_2556,
NPCs.COPPER_ORE_2555,
NPCs.TIN_ORE_2554,
NPCs.COAL_2562,
NPCs.MITHRIL_ORE_2557,
NPCs.ADAMANTITE_ORE_2558,
NPCs.SILVER_ORE_2560,
NPCs.GOLD_ORE_2561,
NPCs.PERFECT_GOLD_ORE_2563,
NPCs.RUNITE_ORE_2559)
}
override fun handleTickActions() {
if (BlastFurnace.beltRunning) {
delay--
if (delay <= 0 && getWorldTicks() % 2 == 0) { //run every other tick
if (counter > 0) {
properties.teleportLocation = location.transform(0, -1, 0)
counter--
if (counter == 0) {
val animation = Animation(2434)
animate(animation)
owner?.setAttribute("/save:OreInPot",true)
submitIndividualPulse(this, object : Pulse(animationDuration(animation)) {
override fun pulse(): Boolean {
clear()
return true
}
})
}
}
}
}
}
}
enum class BFOreVariant {
IRON,
COPPER,
TIN,
COAL,
MITHRIL,
ADAMANT,
SILVER,
GOLD,
RUNITE
}
@@ -0,0 +1,55 @@
package content.minigame.blastfurnace
import core.api.*
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.world.map.zone.MapZone
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneBuilder
import core.game.world.map.zone.ZoneMonitor
import core.plugin.Initializable
import core.plugin.Plugin
/**Code for defining the Blast Furnace zone, Blast Furnace will only
* operate and run its logic if there are actual players in this zone
* @author phil lips*/
//Remove this once the funny dupe gets fixed
//@Initializable
class BlastFurnaceZone : MapZone("Blast Furnace Zone",true), Plugin<Any> {
var pulseStarted = false
override fun newInstance(arg: Any?): Plugin<Any> {
ZoneBuilder.configure(this)
return this
}
override fun fireEvent(identifier: String?, vararg args: Any?): Any {
return Unit
}
override fun configure() {
super.register(ZoneBorders(1935,4956,1956,4974))
}
override fun enter(e: Entity?): Boolean {
if (!pulseStarted){
submitWorldPulse(BlastFurnace.blastPulse)
pulseStarted = true
}
if (e != null && e.isPlayer) {
BlastFurnace.blastFurnacePlayerList.add(e.asPlayer())
}
return super.enter(e)
}
override fun leave(e: Entity?, logout: Boolean): Boolean {
if (e != null && e.isPlayer) {
BlastFurnace.blastFurnacePlayerList.remove(e.asPlayer())
}
return super.leave(e, logout)
}
}
@@ -0,0 +1,24 @@
package content.minigame.blastfurnace
import core.game.interaction.InterfaceListener
/**Handles adding and removing players to the temp gauge viewing list.
* Only updates the gauge if people are actually looking at it
* @author phil lips*/
class PhunnyGaugeTempInterfaceListener : InterfaceListener {
override fun defineInterfaceListeners() {
onOpen(30) {player, component ->
BlastFurnace.gaugeViewList.add(player)
return@onOpen true
}
onClose(30) {player, component ->
BlastFurnace.gaugeViewList.remove(player)
return@onClose true
}
}
}
@@ -0,0 +1,80 @@
package content.minigame.bountyhunter;
import core.cache.def.impl.SceneryDefinition;
import core.game.activity.ActivityManager;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
/**
* Handles the bounty hunter options.
* @author Emperor
*/
public final class BHOptionHandler extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(28110).getHandlers().put("option:exit", this);
SceneryDefinition.forId(28119).getHandlers().put("option:enter", this);
SceneryDefinition.forId(28120).getHandlers().put("option:enter", this);
SceneryDefinition.forId(28121).getHandlers().put("option:enter", this);
SceneryDefinition.forId(28122).getHandlers().put("option:exit", this);
SceneryDefinition.forId(28115).getHandlers().put("option:view", this);
SceneryDefinition.forId(28116).getHandlers().put("option:view", this);
return this;
}
@Override
public boolean handle(final Player player, Node node, String option) {
Scenery object = (Scenery) node;
final BountyHunterActivity activity = player.getExtension(BountyHunterActivity.class);
switch (object.getId()) {
case 28119:
ActivityManager.start(player, "BH low_level", false);
return true;
case 28120:
ActivityManager.start(player, "BH mid_level", false);
return true;
case 28121:
ActivityManager.start(player, "BH high_level", false);
return true;
case 28115:
BHScoreBoard.getRogues().open(player);
return true;
case 28116:
BHScoreBoard.getHunters().open(player);
return true;
case 28122:
if (activity == null) {
return false;
}
if (player.getAttribute("exit_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You can't leave the crater until the exit penalty is over.");
return true;
}
player.lock(2);
GameWorld.getPulser().submit(new Pulse(1) {
@Override
public boolean pulse() {
player.getProperties().setTeleportLocation(activity.getType().getExitLocation());
return true;
}
});
player.animate(Animation.create(7376));
return true;
case 28110:
if (activity == null) {
return false;
}
activity.leaveWaitingRoom(player, false);
return true;
}
return false;
}
}
@@ -0,0 +1,158 @@
package content.minigame.bountyhunter;
import java.nio.ByteBuffer;
import core.cache.misc.buffer.ByteBufferUtils;
import core.game.component.Component;
import core.game.node.entity.player.Player;
import core.tools.StringUtils;
/**
* The score board.
* @author Emperor
*/
public final class BHScoreBoard {
/**
* The score board size.
*/
private static final int SIZE = 10;
/**
* The names.
*/
private String[] names = new String[SIZE];
/**
* The scores.
*/
private int[] scores = new int[SIZE];
/**
* The bounty hunters scoreboard.
*/
private static final BHScoreBoard HUNTERS = new BHScoreBoard();
/**
* The bounty hunter rogues scoreboard.
*/
private static final BHScoreBoard ROGUES = new BHScoreBoard();
/**
* Constructs a new {@code BHScoreBoard} {@code Object}.
*/
public BHScoreBoard() {
for (int i = 0; i < SIZE; i++) {
names[i] = "Nobody yet";
}
}
/**
* Initializes the score boards data.
*/
public static void init() {
/* if (true) { // Indicates no cache exists yet.
return;
}
ByteBuffer buffer = file.data();
for (int i = 0; i < SIZE; i++) {
HUNTERS.scores[i] = buffer.getInt();
HUNTERS.names[i] = ByteBufferUtils.getString(buffer);
}
for (int i = 0; i < SIZE; i++) {
ROGUES.scores[i] = buffer.getInt();
ROGUES.names[i] = ByteBufferUtils.getString(buffer);
}*/
}
/**
* Updates the store file for the scores.
*/
public static void update() {
ByteBuffer buffer = ByteBuffer.allocate(500);
for (int i = 0; i < SIZE; i++) {
buffer.putInt(HUNTERS.scores[i]);
ByteBufferUtils.putString(HUNTERS.names[i], buffer);
}
for (int i = 0; i < SIZE; i++) {
buffer.putInt(ROGUES.scores[i]);
ByteBufferUtils.putString(ROGUES.names[i], buffer);
}
buffer.flip();
//AriosStore.setArchive("bh_scores", buffer);
}
/**
* Opens the score board.
* @param player The player.
*/
public void open(Player player) {
int component = 654;
if (this == ROGUES) {
component = 655;
}
player.getInterfaceManager().open(new Component(component));
for (int i = 0; i < SIZE; i++) {
player.getPacketDispatch().sendString(StringUtils.formatDisplayName(names[i]), component, 15 + i);
player.getPacketDispatch().sendString(Integer.toString(scores[i]), component, 25 + i);
}
}
/**
* Checks if the ratings of the player is good enough for the score board.
* @param player The player.
*/
public void check(Player player) {
int score = player.getSavedData().getActivityData().getBountyHunterRate();
if (this == ROGUES) {
score = player.getSavedData().getActivityData().getBountyRogueRate();
}
for (int i = 0; i < SIZE; i++) {
if (score > scores[i]) {
insert(player, score, i);
update();
break;
}
}
}
/**
* Inserts the player in the score board.
* @param player The player.
* @param score The score.
* @param index The board index.
*/
private void insert(Player player, int score, int index) {
if (names[index].equals(player.getName())) {
scores[index] = score;
return;
}
for (int i = SIZE - 2; i >= index; i--) {
String name = names[i];
if (name.equals(player.getName())) {
name = names[--i];
}
scores[i + 1] = scores[i];
names[i + 1] = name;
}
names[index] = player.getName();
scores[index] = score;
}
/**
* Gets the rogues.
* @return The rogues.
*/
public static BHScoreBoard getRogues() {
return ROGUES;
}
/**
* Gets the hunters.
* @return The hunters.
*/
public static BHScoreBoard getHunters() {
return HUNTERS;
}
}
@@ -0,0 +1,105 @@
package content.minigame.bountyhunter;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
/**
* Holds a player's bounty hunter data.
* @author Emperor
*/
public final class BountyEntry {
/**
* The target.
*/
private Player target;
/**
* The player hunting this player.
*/
private Player hunter;
/**
* Constructs a new {@code BountyEntry} {@code Object}.
*/
public BountyEntry() {
/*
* empty.
*/
}
/**
* Updates the overlay.
* @param player The player.
*/
public void update(Player player) {
String name = "No one";
if (target != null) {
name = target.getUsername();
}
player.getPacketDispatch().sendString(name, 653, 7);
updatePenalty(player, false);
}
/**
* Updates the current penalty.
* @param player The player.
* @param unlock If the components should be unlocked.
*/
public void updatePenalty(Player player, boolean unlock) {
int penalty = player.getAttribute("pickup_penalty", 0);
int child = -1;
if (GameWorld.getTicks() > penalty) {
player.removeAttribute("pickup_penalty");
player.getPacketDispatch().sendInterfaceConfig(653, 8, true);
} else if (penalty != 0) {
child = 8;
int seconds = (int) Math.round((penalty - GameWorld.getTicks()) * 0.6);
player.getPacketDispatch().sendString(seconds + " Sec", 653, 10);
}
penalty = player.getAttribute("exit_penalty", 0);
if (GameWorld.getTicks() > penalty) {
player.removeAttribute("exit_penalty");
player.getPacketDispatch().sendInterfaceConfig(653, 11, true);
} else if (penalty != 0) {
child = 11;
int seconds = (int) Math.round((penalty - GameWorld.getTicks()) * 0.6);
player.getPacketDispatch().sendString(seconds + " Sec", 653, 13);
}
if (unlock && child > -1) {
player.getPacketDispatch().sendInterfaceConfig(653, child, false);
}
}
/**
* Gets the target.
* @return The target.
*/
public Player getTarget() {
return target;
}
/**
* Sets the target.
* @param target The target to set.
*/
public void setTarget(Player target) {
this.target = target;
}
/**
* Gets the hunter.
* @return The hunter.
*/
public Player getHunter() {
return hunter;
}
/**
* Sets the hunter.
* @param hunter The hunter to set.
*/
public void setHunter(Player hunter) {
this.hunter = hunter;
}
}
@@ -0,0 +1,639 @@
package content.minigame.bountyhunter;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.activity.ActivityManager;
import core.game.activity.ActivityPlugin;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.HintIconManager;
import core.game.node.entity.player.link.prayer.PrayerType;
import core.game.node.item.GroundItem;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.Point;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneRestriction;
import core.game.world.map.zone.impl.MultiwayCombatZone;
import core.game.world.map.zone.impl.WildernessZone;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
import core.tools.RandomFunction;
import java.util.*;
/**
* Handles the Bounty hunter activity.
* @author Emperor
*/
@Initializable
public final class BountyHunterActivity extends ActivityPlugin {
/**
* The skull values.
*/
private static final int[] SKULL_VALUES = { 100_000, // Bronze skull
500_000, // Iron skull
1_100_000, // Adamant skull
2_500_000, // Runite skull
-1 // Dragon skull
};
/**
* The exit offsets.
*/
private static final Point[] EXIT_OFFSETS = { new Point(19, 58), new Point(24, 44), new Point(29, 34), new Point(36, 22), new Point(52, 17), new Point(14, 72), new Point(15, 85), new Point(17, 127), new Point(14, 133), new Point(19, 151), new Point(38, 163), new Point(49, 170), new Point(64, 20), new Point(84, 16), new Point(106, 18), new Point(69, 176), new Point(85, 176), new Point(127, 174), new Point(130, 21), new Point(138, 33), new Point(155, 48), new Point(163, 53), new Point(172, 60), new Point(174, 64), new Point(176, 106), new Point(178, 84), new Point(155, 169), new Point(162, 162), new Point(163, 153), new Point(173, 136) };
/**
* The minimum amount of players to enter the crater.
*/
private static final int MINIMUM_PLAYERS = 2;
/**
* The waiting room overlay.
*/
private static final Component WAITING_OVERLAY = new Component(656);
/**
* The game overlay.
*/
private static final Component GAME_OVERLAY = new Component(653);
/**
* The player in the current crater.
*/
final Map<Player, BountyEntry> players = new HashMap<>();
/**
* The waiting room.
*/
private final List<Player> waitingRoom = new ArrayList<>(20);
/**
* The crater type.
*/
private final CraterType type;
/**
* The amount of time to wait in the waiting room.
*/
private int waitingTime = 166;
/**
* The waiting room pulse.
*/
private final Pulse waitRoomPulse = new Pulse(1) {
@Override
public boolean pulse() {
String time = Integer.toString((int) Math.round(waitingTime-- * 0.6)) + " Sec";
for (Player player : waitingRoom) {
player.getPacketDispatch().sendString(time, 656, 10);
}
if (waitingTime == -1) {
for (Iterator<Player> it = waitingRoom.iterator(); it.hasNext();) {
enterCrater(it.next());
it.remove();
}
return true;
}
return false;
}
@Override
public void stop() {
super.stop();
waitingTime = 166;
}
};
/**
* The game pulse (doesn't update every tick on 2009scape as well).
*/
private final Pulse gamePulse = new Pulse(10) {
@Override
public boolean pulse() {
for (Player player : players.keySet()) {
BountyEntry entry = players.get(player);
if (entry.getTarget() == null) {
findTarget(player);
}
entry.updatePenalty(player, false);
}
return false;
}
};
/**
* Constructs a new {@code BountyHunterActivity} {@code Object}.
*/
public BountyHunterActivity() {
this(CraterType.LOW_LEVEL);
}
/**
* Constructs a new {@code BountyHunterActivity} {@code Object}.
*/
public BountyHunterActivity(CraterType type) {
super("BH " + type.name().toLowerCase(), false, false, false, ZoneRestriction.FOLLOWERS);
this.type = type;
}
@Override
public void register() {
waitRoomPulse.stop();
gamePulse.stop();
if (getType() == CraterType.LOW_LEVEL) {
// Disable bounty hunter area as wilderness
Location check = Location.create(3166, 3679, 0);
for (ZoneBorders border : WildernessZone.getInstance().getBorders()) {
if (border.insideBorder(check)) {
/* if (GameWorld.getSettings().isPvp()) {
border.addException(new ZoneBorders(2924, 3306, 3078, 3404));
}*/
border.addException(new ZoneBorders(3140, 3653, 3149, 3670));
border.addException(new ZoneBorders(3150, 3656, 3154, 3676));
border.addException(new ZoneBorders(3155, 3661, 3164, 3686));
border.addException(new ZoneBorders(3165, 3667, 3173, 3693));
border.addException(new ZoneBorders(3174, 3673, 3192, 3705));
border.addException(new ZoneBorders(3193, 3681, 3196, 3709));
break;
}
}
ClassScanner.definePlugin(new ComponentPlugin() {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(657, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
if (button == 18) {
player.getInterfaceManager().close();
player.lock(1);
BountyHunterActivity activity = player.getExtension(BountyHunterActivity.class);
if (activity.players.isEmpty()) {
activity.joinWaitingRoom(player);
return true;
}
activity.enterCrater(player);
}
return true;
}
});
BHScoreBoard.init();
ClassScanner.definePlugin(new BountyLocateSpell());
ClassScanner.definePlugin(new BHOptionHandler());
ActivityManager.register(new BountyHunterActivity(CraterType.MID_LEVEL));
ActivityManager.register(new BountyHunterActivity(CraterType.HIGH_LEVEL));
}
}
@Override
public boolean start(Player player, boolean login, Object... args) {
if (player.getFamiliarManager().hasFamiliar()) {
player.getPacketDispatch().sendMessage("You can't bring a follower into the crater.");
return false;
}
if (!getType().canEnter(player)) {
return false;
}
player.addExtension(BountyHunterActivity.class, this);
if (!login) {
player.getInterfaceManager().open(new Component(657));
} else {
enterCrater(player);
}
return true;
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player && getType().getZone().insideBorder(e.getLocation()) || e instanceof Player) {
if (e.getAttribute("viewing_orb") != null) {
return super.enter(e);
}
Player player = (Player) e;
for (int i = 0; i < type.ordinal(); i++) {
if (!player.getMusicPlayer().hasUnlockedIndex(517 + i)) {
player.getMusicPlayer().unlock(444 - i, false);
}
}
player.addExtension(BountyHunterActivity.class, this);
BountyEntry entry = new BountyEntry();
players.put(player, entry);
player.getInterfaceManager().openOverlay(GAME_OVERLAY);
int penalty;
if ((penalty = player.getAttribute("pickup_penalty", 0)) != 0) {
player.setAttribute("/save:pickup_penalty", GameWorld.getTicks() + penalty);
}
if ((penalty = player.getAttribute("exit_penalty", 0)) != 0) {
player.setAttribute("/save:exit_penalty", GameWorld.getTicks() + penalty);
if (player.getPrayer().get(PrayerType.PROTECT_ITEMS)) {
player.getPrayer().toggle(PrayerType.PROTECT_ITEMS);
}
}
findTarget(player);
entry.updatePenalty(player, true);
player.getInteraction().set(Option._P_ATTACK);
player.getInteraction().remove(Option._P_ASSIST);
player.getSkullManager().setSkullCheckDisabled(true);
player.getSkullManager().setWilderness(true);
player.setAttribute("bh_joined", GameWorld.getTicks() + 10);
updateSkull(player);
if (!gamePulse.isRunning()) {
gamePulse.start();
GameWorld.getPulser().submit(gamePulse);
}
}
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
player.removeExtension(BountyHunterActivity.class);
if (waitingRoom.contains(player)) {
leaveWaitingRoom(player, logout);
}
BountyEntry entry = players.get(player);
if (entry != null) {
leaveCrater(player, logout, entry);
}
}
return super.leave(e, logout);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof GroundItem && option.getName().equals("take")) {
return actionButton((Player) e, 192, 19, -1, -1, 55);
}
if (target instanceof Item && option.getName().equals("drop")) {
if (((Item) target).getValue() > 1000) {
((Player) e).getPacketDispatch().sendMessage("This item is too valuable to drop in the crater.");
return true;
}
}
return false;
}
@Override
public boolean ignoreMultiBoundaries(Entity attacker, Entity victim) {
if (attacker instanceof Player) {
BountyEntry entry = players.get(attacker);
return entry != null && entry.getTarget() == victim;
}
return false;
}
@SuppressWarnings("deprecation")
@Override
public boolean actionButton(Player player, int interfaceId, int buttonId, int slot, int itemId, int opcode) {
if (interfaceId == 192 && buttonId == 19) {
BountyEntry entry = players.get(player);
if (entry != null && player.getAttribute("pickup_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You should not be picking up items. Now you must wait before you can leave.");
player.removeAttribute("pickup_penalty");
player.setAttribute("/save:exit_penalty", GameWorld.getTicks() + 300);
entry.updatePenalty(player, true);
if (player.getPrayer().get(PrayerType.PROTECT_ITEMS)) {
player.getPrayer().toggle(PrayerType.PROTECT_ITEMS);
}
}
} else if (interfaceId == 271 && buttonId == 25) {
if (player.getAttribute("exit_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You can't use the protect item prayer until your penalty has passed.");
player.getConfigManager().send(PrayerType.PROTECT_ITEMS.getConfig(), 0);
return true;
}
}
return false;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e instanceof Player && target instanceof Player) {
if (((Player) target).getAttribute("bh_joined", -1) > GameWorld.getTicks()) {
((Player) e).getPacketDispatch().sendMessage("This player has only just entered and is temporarily invulnerable to attacks.");
return false;
}
e.removeAttribute("bh_joined");
}
return true;
}
/**
* Updates the skull.
* @param player The player.
*/
private void updateSkull(final Player player) {
if (player.getAttribute("value_listener") == null) {
ContainerListener listener = new ContainerListener() {
@Override
public void update(Container c, ContainerEvent event) {
refresh(c);
}
@Override
public void refresh(Container c) {
updateSkull(player);
}
};
player.setAttribute("value_listener", listener);
player.getInventory().getListeners().add(listener);
player.getEquipment().getListeners().add(listener);
}
long value = 0;
for (Item item : player.getInventory().toArray()) {
if (item != null) {
value += item.getValue();
}
}
for (Item item : player.getEquipment().toArray()) {
if (item != null) {
value += item.getValue();
}
}
int skull = 2;
if (value >= 0) {
for (int i = 0; i < SKULL_VALUES.length - 1; i++) {
if (value < SKULL_VALUES[i]) {
skull = 6 - i;
break;
}
}
}
player.getSkullManager().setSkulled(true);
player.getAppearance().setSkullIcon(skull);
player.getAppearance().sync();
}
/**
* Enters the bounty hunter crater.
* @param player The player.
*/
public void enterCrater(Player player) {
Point offset = RandomFunction.getRandomElement(EXIT_OFFSETS);
Location destination = Location.create(getType().getZone().getSouthWestX() + offset.getX(), getType().getZone().getSouthWestY() + offset.getY(), 0);
player.getProperties().setTeleportLocation(destination);
player.animate(Animation.create(7377));
}
/**
* Leaves the bounty hunter crater.
* @param player The player.
* @param logout If the player has logged out.
* @param entry The player's bounty entry.
*/
public void leaveCrater(Player player, boolean logout, BountyEntry entry) {
if (entry.getHunter() != null) {
BountyEntry other = players.get(entry.getHunter());
if (other != null) {
entry.getHunter().getPacketDispatch().sendMessage("Your target has " + (logout ? "logged out" : "left") + ". You shall be found a new target.");
other.setTarget(null);
findTarget(entry.getHunter());
}
}
if (entry.getTarget() != null) {
BountyEntry other = players.get(entry.getTarget());
if (other != null) {
other.setHunter(null);
}
}
player.getHintIconManager().clear();
players.remove(player);
ContainerListener listener = player.getAttribute("value_listener");
if (listener != null) {
player.getInventory().getListeners().remove(listener);
player.getEquipment().getListeners().remove(listener);
}
player.getAppearance().setSkullIcon(-1);
player.getAppearance().sync();
player.getInteraction().remove(Option._P_ATTACK);
player.getInteraction().set(Option._P_ASSIST);
player.getSkullManager().setSkullCheckDisabled(false);
player.getSkullManager().setWilderness(false);
player.getInterfaceManager().closeOverlay();
if (players.isEmpty()) {
gamePulse.stop();
}
int penalty;
if ((penalty = player.getAttribute("pickup_penalty", 0)) > GameWorld.getTicks()) {
player.setAttribute("/save:pickup_penalty", penalty - GameWorld.getTicks());
} else {
player.removeAttribute("pickup_penalty");
}
if ((penalty = player.getAttribute("exit_penalty", 0)) > GameWorld.getTicks()) {
player.setAttribute("/save:exit_penalty", penalty - GameWorld.getTicks());
} else {
player.removeAttribute("exit_penalty");
}
player.getSkullManager().setSkulled(false);
}
/**
* Joins the waiting room.
* @param player The player.
*/
private void joinWaitingRoom(Player player) {
waitingRoom.add(player);
player.getProperties().setTeleportLocation(getType().getRoomLocation());
player.getInterfaceManager().openOverlay(WAITING_OVERLAY);
player.getPacketDispatch().sendString("Players waiting (need " + MINIMUM_PLAYERS + "):", 656, 6);
updateWaitingRoomSize();
if (waitingRoom.size() == MINIMUM_PLAYERS) {
String time = (int) Math.round(waitingTime * 0.6) + " Sec";
for (Player p : waitingRoom) {
player.getPacketDispatch().sendString(time, 656, 10);
p.getPacketDispatch().sendInterfaceConfig(656, 9, false);
p.getPacketDispatch().sendInterfaceConfig(656, 8, false);
}
if (!waitRoomPulse.isRunning()) {
waitRoomPulse.start();
GameWorld.getPulser().submit(waitRoomPulse);
}
} else if (waitingRoom.size() > MINIMUM_PLAYERS) {
player.getPacketDispatch().sendString((int) Math.round(waitingTime * 0.6) + " Sec", 656, 10);
player.getPacketDispatch().sendInterfaceConfig(656, 9, false);
player.getPacketDispatch().sendInterfaceConfig(656, 8, false);
}
}
/**
* Leaves the waiting room.
* @param player The player.
*/
@SuppressWarnings("deprecation")
public void leaveWaitingRoom(Player player, boolean logout) {
waitingRoom.remove(player);
if (waitingRoom.size() < MINIMUM_PLAYERS && waitRoomPulse.isRunning()) {
waitRoomPulse.stop();
for (Player p : waitingRoom) {
p.getPacketDispatch().sendInterfaceConfig(656, 9, true);
p.getPacketDispatch().sendInterfaceConfig(656, 8, true);
}
}
updateWaitingRoomSize();
player.getProperties().setTeleportLocation(getType().getExitLocation());
player.getInterfaceManager().closeOverlay();
if (logout) {
player.setLocation(getType().getExitLocation());
}
}
/**
* Finds a target for the specified player.
* @param player The player.
*/
private void findTarget(Player player) {
Player target = null;
BountyEntry other = null;
int difference = 999;
for (Player p : players.keySet()) {
if (p == player) {
continue;
}
BountyEntry entry = players.get(p);
if (entry.getHunter() == null) {
int diff = Math.abs(player.getProperties().getCurrentCombatLevel() - p.getProperties().getCurrentCombatLevel());
if (diff < difference) {
difference = diff;
target = p;
other = entry;
}
}
}
if (other != null) {
other.setHunter(player);
HintIconManager.registerHintIcon(player, target);
} else {
player.getHintIconManager().clear();
}
BountyEntry entry = players.get(player);
entry.setTarget(target);
entry.update(player);
}
/**
* Updates the amount of players in the waiting room.
*/
private void updateWaitingRoomSize() {
String size = Integer.toString(waitingRoom.size());
for (Player player : waitingRoom) {
player.getPacketDispatch().sendString(size, 656, 7);
}
}
@Override
public boolean canLogout(Player player) {
if (player.getAttribute("exit_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You can't logout until the exit penalty is over.");
return false;
}
return true;
}
@Override
public boolean death(Entity e, Entity killer) {
if (e instanceof Player) {
Player player = (Player) e;
BountyEntry entry = players.get(player);
if (entry != null) {
if (entry.getHunter() != killer && killer instanceof Player) {
handleRogueKill((Player) killer, player, entry);
} else if (entry.getHunter() == killer) { // "They" is not a
// typo, this was
// the actual
// message on RS.
entry.getHunter().getPacketDispatch().sendMessage("You killed " + player.getUsername() + ". They were your target, so your Hunter PvP rating increases!");
entry.getHunter().getSavedData().getActivityData().updateBountyHunterRate(1);
BHScoreBoard.getHunters().check(entry.getHunter());
} else if (entry.getHunter() != null) {
entry.getHunter().getPacketDispatch().sendMessage("Your target has died. You shall be found a new target.");
}
if (entry.getHunter() != null) {
BountyEntry other = players.get(entry.getHunter());
if (other != null) {
other.setTarget(null);
}
entry.setHunter(null);
}
player.getHintIconManager().clear();
if (player.getAttribute("pickup_penalty", 0) != 0) {
player.setAttribute("pickup_penalty", GameWorld.getTicks() - 5);
}
if (player.getAttribute("exit_penalty", 0) != 0) {
player.setAttribute("exit_penalty", GameWorld.getTicks() - 5);
}
entry.updatePenalty((Player) e, true);
}
}
return false;
}
/**
* Handles a rogue kill.
* @param player The player who killed the victim.
* @param victim The victim.
*/
private void handleRogueKill(Player player, Player victim, BountyEntry entry) {
player.getPacketDispatch().sendMessage("You killed " + victim.getUsername() + ". They were not your target, so your Rogue PvP rating");
player.getPacketDispatch().sendMessage("increases!");
player.getPacketDispatch().sendMessage("This means you get the pick-up penalty: pick anything up and you can't leave!");
player.getSavedData().getActivityData().updateBountyRogueRate(1);
BHScoreBoard.getRogues().check(player);
player.setAttribute("/save:pickup_penalty", GameWorld.getTicks() + 300);
entry.updatePenalty(player, true);
}
@Override
public boolean teleport(Entity e, int type, Node node) {
if (e instanceof Player && type != -1) {
((Player) e).getPacketDispatch().sendMessage("A magical force stops you from teleporting.");
return false;
}
return true;
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return this;
}
@Override
public Location getSpawnLocation() {
return Location.create(3166, 3679, 0);
}
@Override
public void configure() {
registerRegion(6234);
register(getType().getZone());
int x = getType().getZone().getSouthWestX();
int y = getType().getZone().getSouthWestY();
MultiwayCombatZone.getInstance().register(new ZoneBorders(x + 56, y + 40, x + 140, y + 140));
}
/**
* Gets the type.
* @return The type.
*/
public CraterType getType() {
return type;
}
}
@@ -0,0 +1,99 @@
package content.minigame.bountyhunter;
import core.game.node.entity.impl.PulseType;
import core.game.node.entity.combat.spell.MagicSpell;
import core.game.node.entity.combat.spell.Runes;
import core.game.interaction.MovementPulse;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.spell.SpellType;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.node.entity.player.link.TeleportManager.TeleportType;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.plugin.Plugin;
/**
* Handles the bounty target locate spell.
* @author Emperor
*/
public final class BountyLocateSpell extends MagicSpell {
/**
* Constructs a new {@code BountyLocateSpell} {@code Object}.
*/
public BountyLocateSpell() {
super(SpellBook.MODERN, 32, 45, null, null, null, new Item[] { Runes.AIR_RUNE.getItem(1), Runes.FIRE_RUNE.getItem(1), Runes.LAW_RUNE.getItem(1) });
}
@Override
public boolean cast(Entity entity, Node target) {
BountyHunterActivity activity = entity.getExtension(BountyHunterActivity.class);
Player player = (Player) entity;
if (activity == null) {
player.getPacketDispatch().sendMessage("You can only use this spell in the Bounty Hunter craters.");
return false;
}
BountyEntry entry = activity.players.get(player);
if (entry == null || entry.getTarget() == null) {
player.getPacketDispatch().sendMessage("You don't have a target to teleport to.");
return true;
}
if (player.getStateManager().hasState(EntityState.FROZEN) || player.getStateManager().hasState(EntityState.STUNNED)) {
player.getPacketDispatch().sendMessage("You can't use this when " + (player.getStateManager().hasState(EntityState.STUNNED) ? "stunned." : "frozen."));
return true;
}
boolean combat = player.inCombat();
if (!super.meetsRequirements(entity, true, combat)) {
return false;
}
if (combat) {
player.getPacketDispatch().sendMessage("You were fighting recently so you'll run instead of teleport.");
target = entry.getTarget();
Location location = entry.getTarget().getLocation();
if (!location.withinDistance(player.getLocation(), 30)) {
int offsetX = location.getX() - player.getLocation().getX();
int offsetY = location.getY() - player.getLocation().getY();
if (offsetX > 30) {
offsetX = 30;
} else if (offsetX < -30) {
offsetX = -30;
}
if (offsetY > 30) {
offsetY = 30;
} else if (offsetY < -30) {
offsetY = -30;
}
target = player.getLocation().transform(offsetX, offsetY, 0);
}
player.getPulseManager().run(new MovementPulse(player, target) {
@Override
public boolean pulse() {
return true;
}
}, PulseType.STANDARD);
return true;
}
Location destination = RegionManager.getTeleportLocation(entry.getTarget().getLocation(), 5);
if (entity.getTeleporter().send(destination, TeleportType.NORMAL, -1)) {
if (!super.meetsRequirements(entity, true, true)) {
entity.getTeleporter().getCurrentTeleport().stop();
return false;
}
entity.setAttribute("magic-delay", GameWorld.getTicks() + 5);
return true;
}
return false;
}
@Override
public Plugin<SpellType> newInstance(SpellType arg) throws Throwable {
SpellBook.MODERN.register(60, this);
return this;
}
}
@@ -0,0 +1,131 @@
package content.minigame.bountyhunter;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneBorders;
/**
* Represents the crater types.
* @author Emperor
*/
public enum CraterType {
/**
* The low level crater.
*/
LOW_LEVEL(3, Location.create(1548, 5804, 0), Location.create(1548, 5804, 0), Location.create(3152, 3672, 0), new ZoneBorders(2688, 5632, 2879, 5823)),
/**
* The mid level crater.
*/
MID_LEVEL(50, Location.create(1558, 5785, 0), Location.create(1548, 5804, 0), Location.create(3158, 3680, 0), new ZoneBorders(2944, 5632, 3135, 5823)),
/**
* The high level crater.
*/
HIGH_LEVEL(95, Location.create(1570, 5804, 0), Location.create(1548, 5804, 0), Location.create(3164, 3685, 0), new ZoneBorders(3200, 5632, 3391, 5823));
/**
* The level required to enter the crater.
*/
private final int level;
/**
* The waiting room location.
*/
private final Location roomLocation;
/**
* The crater location.
*/
private final Location craterLocation;
/**
* The exit location.
*/
private final Location exitLocation;
/**
* The zone borders.
*/
private final ZoneBorders zone;
/**
* Constructs a new {@code CraterType} {@code Object}. The level required to
* enter the crater.
* @param roomLocation The location of the waiting room.
* @param craterLocation The location of the crater.
* @param exitLocation The location to go the when exiting.
* @param zone The crater zone.
*/
private CraterType(int level, Location roomLocation, Location craterLocation, Location exitLocation, ZoneBorders zone) {
this.level = level;
this.roomLocation = roomLocation;
this.craterLocation = craterLocation;
this.exitLocation = exitLocation;
this.zone = zone;
}
/**
* Checks if the player can enter the crater.
* @param player The player.
* @return {@code True} if so.
*/
public boolean canEnter(Player player) {
int combatLevel = player.getProperties().getCurrentCombatLevel();
if (player.getIronmanManager().checkRestriction()) {
return false;
}
if (ordinal() < CraterType.values().length - 1) {
if (combatLevel > CraterType.values()[ordinal() + 1].level + 5) {
player.getPacketDispatch().sendMessage("Your combat level has to be below " + (CraterType.values()[ordinal() + 1].level + 5) + " to enter this crater.");
return false;
}
}
if (combatLevel < level) {
player.getPacketDispatch().sendMessage("You need a combat level of " + level + " to enter this crater.");
return false;
}
return true;
}
/**
* Gets the level requirement.
* @return The level requirement.
*/
public int getLevel() {
return level;
}
/**
* Gets the roomLocation.
* @return The roomLocation.
*/
public Location getRoomLocation() {
return roomLocation;
}
/**
* Gets the craterLocation.
* @return The craterLocation.
*/
public Location getCraterLocation() {
return craterLocation;
}
/**
* Gets the exitLocation.
* @return The exitLocation.
*/
public Location getExitLocation() {
return exitLocation;
}
/**
* Gets the zone.
* @return The zone.
*/
public ZoneBorders getZone() {
return zone;
}
}
@@ -0,0 +1,120 @@
package content.minigame.bountyhunter
import core.api.*
import core.game.dialogue.DialoguePlugin
import core.game.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.IronmanMode
import core.plugin.Initializable
import org.rs09.consts.NPCs
import core.game.dialogue.IfTopic
import core.game.dialogue.Topic
import core.tools.END_DIALOGUE
import core.tools.START_DIALOGUE
/**
* Provides dialogue tree for Maximillian Sackville,
* the Bounty Hounter roving banker.
*
* @author vddCore
*/
@Initializable
class MaximillianSackvilleDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player) {
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) {
START_DIALOGUE -> when {
hasIronmanRestriction(player, IronmanMode.ULTIMATE) -> {
npcl(
core.game.dialogue.FacialExpression.NEUTRAL,
"My apologies, dear ${if (player.isMale) "sir" else "madam"}, " +
"our services are not available for Ultimate ${if (player.isMale) "Ironmen" else "Ironwomen"}."
).also { stage = END_DIALOGUE }
}
else -> {
npcl(
core.game.dialogue.FacialExpression.NEUTRAL,
"Good day, how may I help you?"
).also {
if (hasAwaitingGrandExchangeCollections(player)) {
stage++
} else {
stage += 2
}
}
}
}
1 -> npcl(
core.game.dialogue.FacialExpression.NEUTRAL,
"Before we go any further, I should inform you that you " +
"have items ready for collection from the Grand Exchange."
).also { stage++ }
2 -> playerl(
core.game.dialogue.FacialExpression.ASKING,
"Who are you?"
).also { stage++ }
3 -> npcl(
core.game.dialogue.FacialExpression.NEUTRAL,
"How inconsiderate of me, dear ${if (player.isMale) "sir" else "madam"}. " +
"My name is Maximillian Sackville and I conduct operations here on behalf " +
"of The Bank of Gielinor."
).also { stage++ }
4 -> showTopics(
Topic(core.game.dialogue.FacialExpression.NEUTRAL, "I'd like to access my bank account.", 10),
IfTopic(
core.game.dialogue.FacialExpression.NEUTRAL,
"I'd like to switch to my ${getBankAccountName(player, true)} bank account.",
11,
hasActivatedSecondaryBankAccount(player)
),
Topic(core.game.dialogue.FacialExpression.NEUTRAL, "I'd like to check my PIN settings.", 12),
Topic(core.game.dialogue.FacialExpression.NEUTRAL, "I'd like to collect items.", 13),
Topic(core.game.dialogue.FacialExpression.ASKING, "Aren't you afraid of working in the Wilderness?", 5)
)
5 -> npcl(
core.game.dialogue.FacialExpression.NEUTRAL,
"While the Wilderness is quite a dangerous place, The Bank of Gielinor offers " +
"us - roving bankers - extraordinary benefits for our hard work in hazardous environments."
).also { stage++ }
6 -> npcl(
core.game.dialogue.FacialExpression.NEUTRAL,
"This allows us to provide our services to customers regardless of their current " +
"whereabouts. Our desire to serve is stronger than our fear of the Wilderness."
).also { stage = END_DIALOGUE }
10 -> {
openBankAccount(player)
end()
}
11 -> {
toggleBankAccount(player)
npcl(
core.game.dialogue.FacialExpression.NEUTRAL,
"Naturally. You can now access your ${getBankAccountName(player)} bank account."
).also { stage = END_DIALOGUE }
}
12 -> {
openBankPinSettings(player)
end()
}
13 -> {
openGrandExchangeCollectionBox(player)
end()
}
}
return true
}
override fun getIds() = intArrayOf(NPCs.BANKER_6538)
}
@@ -0,0 +1,87 @@
package content.minigame.clanwars;
import core.game.activity.ActivityManager;
import core.game.interaction.Option;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.request.RequestModule;
import core.game.node.entity.player.link.request.RequestType;
import core.game.system.communication.ClanRank;
import core.plugin.Plugin;
/**
* Handles the Clan wars challenge option.
* @author Emperor
* @versuib 1,9
*/
public final class CWChallengeOption extends OptionHandler {
/**
* The challenge option.
*/
public static final Option OPTION = new Option("Challenge", 0);
/**
* The request type.
*/
private static final RequestType REQUEST_TYPE = new RequestType("Sending challenge request...", ":clanreq:", getModule()) {
@Override
public boolean canRequest(Player player, Player target) {
if (player.getCommunication().getClan() == null) {
player.getPacketDispatch().sendMessage("You have to be in a clan to challenge players.");
return false;
}
if (player.getCommunication().getClan().getRank(player).ordinal() < ClanRank.CAPTAIN.ordinal()) {
player.getPacketDispatch().sendMessage("Your clan rank is not high enough to challenge other clans.");
return false;
}
if (player.getCommunication().getClan().getClanWar() != null) {
player.getPacketDispatch().sendMessage("Your clan is already in a war.");
return false;
}
if (target.getCommunication().getClan() == null) {
player.getPacketDispatch().sendMessage("This player is not in a clan.");
return false;
}
if (target.getCommunication().getClan().getRank(target).ordinal() < ClanRank.CAPTAIN.ordinal()) {
player.getPacketDispatch().sendMessage("This player's clan rank is not high enough to accept challenges.");
return false;
}
if (target.getCommunication().getClan().getClanWar() != null) {
player.getPacketDispatch().sendMessage("This player's clan is already in a war.");
return false;
}
if (target.getCommunication().getClan() == player.getCommunication().getClan()) {
player.getPacketDispatch().sendMessage("You can't challenge someone from your own clan.");
return false;
}
return true;
}
};
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
OPTION.setHandler(this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
player.getRequestManager().request((Player) node, REQUEST_TYPE);
return true;
}
/**
* Gets the request module.
* @return The module.
*/
private static RequestModule getModule() {
return new RequestModule() {
@Override
public void open(Player player, Player target) {
ActivityManager.start(player, "Clan wars", false, target);
}
};
}
}
@@ -0,0 +1,496 @@
package content.minigame.clanwars;
import java.util.ArrayList;
import java.util.List;
import core.game.component.Component;
import core.game.activity.ActivityPlugin;
import core.plugin.Initializable;
import content.global.skill.summoning.familiar.Familiar;
import content.global.skill.summoning.pet.Pet;
import core.game.interaction.Option;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.impl.PulseManager;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.ConfigurationManager.Configuration;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.system.communication.ClanEntry;
import core.game.system.communication.ClanRepository;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.map.build.DynamicRegion;
import core.game.world.map.zone.RegionZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneType;
import core.game.world.map.zone.impl.MultiwayCombatZone;
import core.game.world.update.flag.chunk.AnimateObjectUpdateFlag;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Handles the clan wars activity.
* @author Emperor
*/
@Initializable
public final class ClanWarsActivityPlugin extends ActivityPlugin {
/**
* The first clan.
*/
private ClanRepository firstClan;
/**
* The second clan.
*/
private ClanRepository secondClan;
/**
* The first clan's players.
*/
private List<Player> firstClanPlayers = new ArrayList<>(20);
/**
* The second clan's players.
*/
private List<Player> secondClanPlayers = new ArrayList<>(20);
/**
* The list of viewing players.
*/
private List<Player> viewingPlayers = new ArrayList<>(20);
/**
* The amount of ticks.
*/
private int ticks;
/**
* The updating pulse.
*/
private Pulse pulse;
/**
* The attack option.
*/
private static final Option ATTACK_OPTION = new Option("Attack", 0).setHandler(new OptionHandler() {
@Override
public boolean handle(Player player, Node node, String option) {
player.getProperties().getCombatPulse().attack(node);
return true;
}
@Override
public boolean isWalk() {
return false;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
return this;
}
@Override
public boolean isDelayed(Player player) {
return false;
}
});
/**
* Constructs a new {@code ClanWarsActivityPlugin} {@code Object}.
*/
public ClanWarsActivityPlugin() {
super("Clan wars", true, false, true);
}
@Override
public boolean start(Player player, boolean login, Object... args) {
Player other = (Player) args[0];
firstClan = player.getCommunication().getClan();
secondClan = other.getCommunication().getClan();
firstClan.setClanWar(this);
secondClan.setClanWar(this);
sendWarDeclaration(firstClan.getPlayers());
sendWarDeclaration(secondClan.getPlayers());
handleWall();
join(player);
join(other);
return true;
}
/**
* Handles the wall in the middle of the battlefield.
*/
private void handleWall() {
int offset = 0;
for (int x = 5; x < 54; x++) {
offset = (offset + 1) % 3;
SceneryBuilder.add(new Scenery(28174 + offset, base.transform(x, 64, 0)));
}
GameWorld.getPulser().submit(pulse = new Pulse(200) {
@Override
public boolean pulse() {
for (int x = 5; x < 54; x++) {
Location l = base.transform(x, 64, 0);
Scenery object = RegionManager.getObject(l);
if (object != null) {
Animation anim = Animation.create(7386 + ((object.getId() - 28174) % 3));
anim.setObject(object);
RegionManager.getRegionChunk(l).flag(new AnimateObjectUpdateFlag(anim));
}
}
GameWorld.getPulser().submit(new Pulse(5) {
@Override
public boolean pulse() {
for (int x = 5; x < 54; x++) {
Location l = base.transform(x, 64, 0);
Scenery object = RegionManager.getObject(l);
if (object != null) {
SceneryBuilder.remove(object);
}
}
return true;
}
});
super.setTicksPassed(250);
sendGameData();
if (firstClanPlayers.isEmpty() || secondClanPlayers.isEmpty()) {
finishWar();
}
return true;
}
});
}
/**
* Ends the war.
*/
public void finishWar() {
firstClan.setClanWar(null);
secondClan.setClanWar(null);
int firstInterfaceId = firstClanPlayers.isEmpty() ? 650 : 651;
int secondInterfaceId = firstClanPlayers.isEmpty() ? 651 : 650;
String[] message = new String[] { "Your clan has been defeated!", "Your clan is victorious!" };
for (Player p : firstClanPlayers) {
p.getProperties().setTeleportLocation(getLeaveLocation());
p.getInterfaceManager().openComponent(firstInterfaceId);
p.getPacketDispatch().sendMessage(message[firstInterfaceId - 650]);
p.fullRestore();
PulseManager.cancelDeathTask(p);
}
for (Player p : secondClanPlayers) {
p.getProperties().setTeleportLocation(getLeaveLocation());
p.getInterfaceManager().openComponent(secondInterfaceId);
p.getPacketDispatch().sendMessage(message[secondInterfaceId - 650]);
p.fullRestore();
PulseManager.cancelDeathTask(p);
}
for (Player p : viewingPlayers) {
p.getProperties().setTeleportLocation(getLeaveLocation());
if (p.getCommunication().getClan() == firstClan) {
p.getInterfaceManager().openComponent(firstInterfaceId);
p.getPacketDispatch().sendMessage(message[firstInterfaceId - 650]);
} else {
p.getInterfaceManager().openComponent(secondInterfaceId);
p.getPacketDispatch().sendMessage(message[secondInterfaceId - 650]);
}
}
}
/**
* Sends the game data for all players in the game.
*/
public void sendGameData() {
for (Player p : firstClanPlayers) {
sendGameData(p);
}
for (Player p : secondClanPlayers) {
sendGameData(p);
}
for (Player p : viewingPlayers) {
sendGameData(p);
}
}
/**
* Sends the game data for the player.
* @param p The player.
*/
public void sendGameData(Player p) {
int value = 0;
boolean first = p.getCommunication().getClan() == firstClan;
String name = firstClan.getName();
if (first) {
value |= firstClanPlayers.size() << 5;
value |= secondClanPlayers.size() << 14;
} else {
name = secondClan.getName();
value |= secondClanPlayers.size() << 5;
value |= firstClanPlayers.size() << 14;
}
if (pulse.getTicksPassed() < 200) {
value |= (200 - pulse.getTicksPassed()) << 23;
}
p.getConfigManager().set(Configuration.CLAN_WAR_DATA, value);
p.getPacketDispatch().sendString(name, 265, 2);
}
@Override
public boolean teleport(Entity e, int type, Node node) {
if (type != -1 && type != 2 && e instanceof Player) {
((Player) e).getPacketDispatch().sendMessage("You can't teleport away from a war.");
return false;
}
return true;
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInteraction().set(ATTACK_OPTION);
player.getInteraction().remove(Option._P_ASSIST);
player.getSkullManager().setSkullCheckDisabled(true);
player.getSkullManager().setWilderness(true);
player.getInterfaceManager().openOverlay(new Component(265));
} else if (e instanceof Familiar && !(e instanceof Pet)) {
Familiar familiar = (Familiar) e;
if (familiar.isCombatFamiliar()) {
familiar.transform(familiar.getOriginalId() + 1);
}
}
return true;
}
@Override
public boolean death(Entity e, Entity killer) {
if (e instanceof Player) {
return enterViewingRoom((Player) e);
}
return false;
}
/**
* Enters the viewing room.
* @param player The player.
* @return {@code True} if successfully entered the viewing room.
*/
public boolean enterViewingRoom(Player player) {
Location destination = null;
if (player.getCommunication().getClan() == firstClan) {
remove(player, firstClanPlayers);
destination = base.transform(55 + RandomFunction.randomize(3), 51 + RandomFunction.randomize(11), 0);
} else if (player.getCommunication().getClan() == secondClan) {
remove(player, secondClanPlayers);
destination = base.transform(55 + RandomFunction.randomize(3), 66 + RandomFunction.randomize(11), 0);
} else {
return false;
}
player.getProperties().setTeleportLocation(destination);
viewingPlayers.add(player);
sendGameData();
return true;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e instanceof Familiar) {
e = ((Familiar) e).getOwner();
}
if (target instanceof Familiar) {
target = ((Familiar) target).getOwner();
}
if (e instanceof Player && target instanceof Player) {
Player player = (Player) e;
Player other = (Player) target;
ClanRepository clan = player.getCommunication().getClan();
if (pulse.isRunning()) {
player.getPacketDispatch().sendMessage("The war hasn't started yet.");
return false;
}
if (!firstClanPlayers.contains(player) && !secondClanPlayers.contains(player)) {
return false;
}
if (other.getCommunication().getClan() == clan) {
player.getPacketDispatch().sendMessage("You can only attack players in a different clan.");
return false;
}
if (!firstClanPlayers.contains(other) && !secondClanPlayers.contains(other)) {
player.getPacketDispatch().sendMessage("You can't attack this player.");
return false;
}
}
return true;
}
/**
* Removes the player from the game.
* @param player The player.
* @param players The players list.
*/
public void remove(Player player, List<Player> players) {
players.remove(player);
if (!pulse.isRunning() && players.isEmpty()) {
finishWar();
}
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof Scenery) {
Scenery object = (Scenery) target;
if (object.getId() == 28214 || object.getId() == 28140) {
e.getProperties().setTeleportLocation(getLeaveLocation());
return true;
}
}
return false;
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInterfaceManager().closeOverlay();
player.getInteraction().remove(ATTACK_OPTION);
if (firstClanPlayers.contains(player)) {
remove(player, firstClanPlayers);
} else if (secondClanPlayers.contains(player)) {
remove(player, secondClanPlayers);
} else {
viewingPlayers.remove(player);
}
sendGameData();
player.getSkullManager().setSkullCheckDisabled(false);
player.getSkullManager().setWilderness(false);
if (logout) {
e.setLocation(getLeaveLocation());
}
} else if (e instanceof Familiar && !(e instanceof Pet)) {
Familiar familiar = (Familiar) e;
if (familiar.isCombatFamiliar()) {
familiar.reTransform();
}
}
return true;
}
@Override
public Object fireEvent(String identifier, Object... args) {
if (identifier.equals("join")) {
join((Player) args[0]);
return true;
}
if (identifier.equals("leavefc")) {
Player p = (Player) args[0];
p.getProperties().setTeleportLocation(getLeaveLocation());
return true;
}
return null;
}
/**
* Gets the leaving location.
* @return The leaving location.
*/
private static Location getLeaveLocation() {
Location l = Location.create(3265 + RandomFunction.randomize(13), 3675 + RandomFunction.randomize(18), 0);
while (!RegionManager.isTeleportPermitted(l)) {
l = l.transform(1, 1, 0);
}
return l;
}
/**
* Makes the player join the game.
* @param player The player.
*/
public void join(Player player) {
if (!pulse.isRunning()) {
enterViewingRoom(player);
return;
}
boolean first = player.getCommunication().getClan() == firstClan;
if (first) {
if (firstClanPlayers.contains(player)) {
return;
}
firstClanPlayers.add(player);
player.getProperties().setTeleportLocation(base.transform(34 + RandomFunction.randomize(4), 10, 0));
} else {
if (secondClanPlayers.contains(player)) {
return;
}
secondClanPlayers.add(player);
player.getProperties().setTeleportLocation(base.transform(26 + RandomFunction.randomize(4), 118, 0));
}
sendGameData();
}
/**
* Sends messages to the list of players.
* @param players The players list.
*/
private static void sendWarDeclaration(List<ClanEntry> players) {
Location check = Location.create(3272, 3682, 0);
for (ClanEntry e : players) {
Player p = e.getPlayer();
if (p.getLocation().withinDistance(check, 128)) {
p.getPacketDispatch().sendMessage("<col=ff0000>Your clan has been challenged to a clan war!");
p.getPacketDispatch().sendMessage("<col=ff0000>Step through the purple portal in the Challenge Hall.");
p.getPacketDispatch().sendMessage("<col=ff0000>Battle will commence in 2 minutes.");
}
}
}
@Override
public void configure() {
setZoneType(ZoneType.SAFE.getId());
DynamicRegion[] regions = DynamicRegion.create(new ZoneBorders(3264, 3712, 3328, 3840));
setRegionBase(regions);
int x = base.getX();
int y = base.getY() + 20;
RegionZone multi = new RegionZone(MultiwayCombatZone.getInstance(), new ZoneBorders(x, y, x + 63, y + 88));
for (DynamicRegion r : regions) {
r.setMulticombat(true);
r.getRegionZones().add(multi);
r.setRegionTimeOut(250);
r.setMusicId(442);
}
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return new ClanWarsActivityPlugin();
}
/**
* Gets the ticks.
* @return The ticks.
*/
public int getTicks() {
return ticks;
}
/**
* Sets the ticks.
* @param ticks The ticks to set.
*/
public void setTicks(int ticks) {
this.ticks = ticks;
}
}
@@ -0,0 +1,98 @@
package content.minigame.clanwars;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.game.world.map.zone.ZoneRestriction;
import core.game.world.map.zone.impl.WildernessZone;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
/**
* Handles the clan wars challenge room.
* @author Emperor
*/
@Initializable
public final class ClanWarsChallengeRoom extends MapZone implements Plugin<Object> {
/**
* Constructs a new {@code ClanWarsChallengeRoom} {@code Object}.
*/
public ClanWarsChallengeRoom() {
super("clan wars cr", true, ZoneRestriction.RANDOM_EVENTS);
}
@Override
public void configure() {
register(new ZoneBorders(3264, 3672, 3279, 3695));
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player p = (Player) e;
p.getSkullManager().setWildernessDisabled(true);
p.getSkullManager().setWilderness(false);
p.getInterfaceManager().closeOverlay();
p.getInteraction().remove(Option._P_ASSIST);
p.getInteraction().set(CWChallengeOption.OPTION);
}
return super.enter(e);
}
@Override
public boolean leave(final Entity e, final boolean logout) {
if (e instanceof Player) {
Player p = (Player) e;
p.getSkullManager().setWildernessDisabled(false);
p.getInteraction().remove(CWChallengeOption.OPTION);
p.getInteraction().set(Option._P_ASSIST);
if (WildernessZone.isInZone(e)) {
WildernessZone.show(p);
p.getSkullManager().setWilderness(true);
}
}
return super.leave(e, logout);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof Scenery) {
Scenery object = (Scenery) target;
Player player = (Player) e;
if (object.getId() == 28213) {
if (player.getCommunication().getClan() == null) {
player.getPacketDispatch().sendMessage("You have to be in a clan to enter this portal.");
} else if (player.getCommunication().getClan().isDefault()) {
player.sendMessage("You can't use the main clan chat for this.");
return true;
} else if (player.getCommunication().getClan().getClanWar() == null) {
player.getPacketDispatch().sendMessage("Your clan has to be in a war.");
} else {
player.getCommunication().getClan().getClanWar().fireEvent("join", player);
}
return true;
}
}
return false;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
ClassScanner.definePlugin(new CWChallengeOption());
return this;
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
}
@@ -0,0 +1,174 @@
package content.minigame.duel
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.plugin.Initializable
/**
* @author qmqz
*/
@Initializable
class AfrahDialogue : core.game.dialogue.DialoguePlugin {
private val conversations = arrayOf (0, 4, 10, 11, 15, 17, 20, 22, 23, 24, 29, 32)
override fun open(vararg args: Any): Boolean {
player(core.game.dialogue.FacialExpression.ASKING, "Hi!")
stage = conversations.random()
npc = args[0] as NPC
return true
}
constructor() {}
constructor(player: Player?) : super(player) {}
override fun getIds(): IntArray {
return intArrayOf(968)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) {
0 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Ooh. This is exciting!")
stage++
}
1 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Yup!")
stage = 99
}
2 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "I wouldn't want to be the poor guy that has to", "clean up after the duels.")
stage++
}
3 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Me neither.")
stage = 99
}
4 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "My son just won his first duel!")
stage++
}
5 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Congratulations!")
stage++
}
6 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "He ripped his opponent in half!")
stage++
}
7 -> {
player(core.game.dialogue.FacialExpression.ASKING, "That's gotta hurt!")
stage++
}
8 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "He's only 10 as well!")
stage++
}
9 -> {
player(core.game.dialogue.FacialExpression.ASKING, "You gotta start 'em young!")
stage = 99
}
10 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Hmph.")
stage = 99
}
11 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "My favourite fighter is Mubariz!")
stage++
}
12 -> {
player(core.game.dialogue.FacialExpression.ASKING, "The guy at the information kiosk?")
stage++
}
13 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Yeah! He rocks!")
stage++
}
14 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Takes all sorts, I guess.")
stage = 99
}
15 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Hi! I'm here to watch the duels!")
stage++
}
16 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Me too!")
stage = 99
}
17 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Did you know they think this place dates","back to the second age?!")
stage++
}
18 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Really?")
stage++
}
19 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Yeah. The guy at the information kiosk was telling me.")
stage = 99
}
20 -> {
npc(core.game.dialogue.FacialExpression.ANGRY, "Can't you see I'm watching the duels?")
stage++
}
21 -> {
player(core.game.dialogue.FacialExpression.SAD, "I'm sorry!")
stage = 99
}
22 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Well. This beats doing the shopping!")
stage = 99
}
23 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Hi!")
stage = 99
}
24 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Knock knock!")
stage++
}
25 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Who's there?")
stage++
}
26 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Boo!")
stage++
}
27 -> {
player(core.game.dialogue.FacialExpression.ASKING, "Boo who?")
stage++
}
28 -> {
npc(core.game.dialogue.FacialExpression.LAUGH, "Don't cry, it's just me!")
stage = 99
}
29 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Why did the skeleton burp?")
stage++
}
30 -> {
player(core.game.dialogue.FacialExpression.ASKING, "I don't know?")
stage++
}
31 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "'Cause it didn't have the guts to fart!")
stage = 99
}
32 -> {
npc(core.game.dialogue.FacialExpression.ASKING, "Waaaaassssssuuuuupp?!.")
stage = 99
}
99 -> end()
}
return true
}
override fun newInstance(player: Player): core.game.dialogue.DialoguePlugin {
return AfrahDialogue(player)
}
}
@@ -0,0 +1,39 @@
package content.minigame.duel;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.plugin.Plugin;
/**
* Handles the challenge option for dueling.
* @author Vexia
*
*/
public class ChallengeOptionPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
DuelArenaActivity.CHALLENGE_OPTION.setHandler(this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Player other = (Player) node;
if (other.getInterfaceManager().isOpened() || other.getExtension(DuelSession.class) != null) {
player.getPacketDispatch().sendMessage("Other player is busy at the moment.");
return true;
}
if (other.getRequestManager().getTarget() == player && other.getAttribute("duel:partner") == player) {
player.getRequestManager().request(other, other.getAttribute("duel:staked", false) ? DuelArenaActivity.STAKE_REQUEST : DuelArenaActivity.FRIEND_REQUEST);
return true;
}
player.getInterfaceManager().open(DuelArenaActivity.DUEL_TYPE_SELECT);
player.setAttribute("duel:staked", false);
player.setAttribute("duel:partner", other);
player.getConfigManager().set(283, 1 << 26);
return true;
}
}
@@ -0,0 +1,595 @@
package content.minigame.duel;
import core.cache.def.impl.SceneryDefinition;
import core.game.container.Container;
import core.game.container.impl.EquipmentContainer;
import core.game.dialogue.DialogueAction;
import core.game.interaction.Option;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.equipment.WeaponInterface;
import core.game.node.entity.impl.PulseManager;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.HintIconManager;
import core.game.node.entity.player.link.prayer.PrayerType;
import content.global.skill.summoning.familiar.Familiar;
import core.game.node.item.GroundItem;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneRestriction;
import core.plugin.Plugin;
import core.tools.RandomFunction;
import core.tools.StringUtils;
import core.ServerConstants;
import core.game.world.GameWorld;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a dueling area.
* @author Vexia
*
*/
public class DuelArea extends MapZone {
/**
* The respawn locations.
*/
public static final Location[] RESPAWN_LOCATIONS = new Location[] { Location.create(3371, 3275, 0), Location.create(3365, 3276, 0), Location.create(3366, 3274, 0), Location.create(3369, 3274, 0), Location.create(3372, 3275, 0), Location.create(3372, 3266, 0), Location.create(3371, 3269, 0), Location.create(3376, 3270, 0), Location.create(3376, 3273, 0), Location.create(3377, 3275, 0) };
/**
* The zone borders set for the area.
*/
private final ZoneBorders border;
/**
* If this area has obstacles.
*/
private final boolean obstacles;
/**
* The center location to determine starting points.
*/
private final Location center;
/**
* The fight option.
*/
private static final Option FIGHT_OPTION = new Option("Fight", 0).setHandler(new OptionHandler() {
@Override
public boolean handle(Player player, Node node, String option) {
player.getProperties().getCombatPulse().attack(node);
return true;
}
@Override
public boolean isWalk() {
return false;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
return this;
}
@Override
public boolean isDelayed(Player player) {
return false;
}
});
/**
* Constructs a new {@Code DuelArea} {@Code Object}
*/
public DuelArea() {
this(-1, null, false, null);
}
/**
* Constructs a new {@Code DuelArea} {@Code Object}
* @param index the index.
* @param border the border.
* @param obstacles if there is obstacles.
*/
public DuelArea(int index, ZoneBorders border, boolean obstacles, Location center) {
super("Duel Area - " + index, true, ZoneRestriction.FIRES, ZoneRestriction.CANNON, ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.FOLLOWERS);
this.obstacles = obstacles;
this.border = border;
this.center = center;
}
/**
* Starts a duel between two players.
* @param session the session.
*/
public void duel(final DuelSession session) {
Location[] locations = getStartLocations(session);
session.getPlayer().teleport(locations[0]);
session.getOther().teleport(locations[1]);
session.getPlayer().getInterfaceManager().close();
session.getPlayer().getInterfaceManager().restoreTabs();
session.getOther().getInterfaceManager().close();
session.getOther().getInterfaceManager().restoreTabs();
session.getPlayer().setAttribute("duel:icon", HintIconManager.registerHintIcon(session.getPlayer(), session.getOther()));
session.getOther().setAttribute("duel:icon", HintIconManager.registerHintIcon(session.getOther(), session.getPlayer()));
session.getPlayer().setAttribute("duel:ammo", new ArrayList<GroundItem>(100));
session.getOther().setAttribute("duel:ammo", new ArrayList<GroundItem>(100));
session.getPlayer().setAttribute("vengeance", false);
session.getOther().setAttribute("vengeance", false);
GameWorld.getPulser().submit(new Pulse(4, session.getPlayer(), session.getOther()) {
int count;
@Override
public boolean pulse() {
String chat = count < 3 ? String.valueOf(3 - count) : "FIGHT!";
session.getPlayer().sendChat(chat);
session.getOther().sendChat(chat);
return count++ >= 3;
}
@Override
public void stop() {
super.stop();
if (session.getPlayer().isActive() && session.getOther().isActive() && session.getFightState() != 2) {
session.setFightState(1);
session.getPlayer().getSkullManager().setSkullCheckDisabled(true);
session.getPlayer().getSkullManager().setWilderness(true);
session.getOther().getSkullManager().setSkullCheckDisabled(true);
session.getOther().getSkullManager().setWilderness(true);
session.getPlayer().getProperties().setMultiZone(true);
session.getOther().getProperties().setMultiZone(true);
}
}
});
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (!e.isPlayer()) {
return true;
}
Player p = e.asPlayer();
final DuelSession session = getSession(p);
if (session == null) {
return true;
}
if (option.getName().equalsIgnoreCase("eat") && session.hasRule(DuelRule.NO_FOOD)) {
p.sendMessage("You can't eat in this fight.");
return true;
}
if (option.getName().equalsIgnoreCase("drink") && session.hasRule(DuelRule.NO_DRINKS)) {
p.sendMessage("You can't drink in this fight.");
return true;
}
if (option.getName().equalsIgnoreCase("wield") || option.getName().equalsIgnoreCase("wear") && target instanceof Item) {
if (session.isRestrictedEquipment(target.asItem())) {
p.sendMessage("You can't equip that during this duel.");
return true;
}
}
if (option.getName().equalsIgnoreCase("Summon") && !session.hasRule(DuelRule.ENABLE_SUMMONING)) {
p.sendMessage("You cannot summon familiars whilst in a duel.");
return true;
}
if (option.getName().equalsIgnoreCase("drop") && target instanceof Item) {
p.sendMessage("You cannot drop items whilst in a duel.");
return true;
}
switch (target.getId()) {
case 3203:
handleForfeit(p);
return true;
}
return super.interact(e, target, option);
}
@Override
public boolean move(Entity entity, Location from, Location to) {
if (entity.isPlayer()) {
Player p = entity.asPlayer();
DuelSession session = getSession(p);
if (session == null) {
return false;
}
return !session.hasRule(DuelRule.NO_MOVEMENT);
}
return super.move(entity, from, to);
}
@Override
public boolean actionButton(Player player, int interfaceId, int buttonId, int slot, int itemId, int opcode) {
DuelSession session = getSession(player);
if (session == null) {
return true;
}
WeaponInterface inter = player.getExtension(WeaponInterface.class);
if (inter != null && interfaceId == inter.getId()) {
switch (buttonId) {
case 8:
case 10:
if (session.hasRule(DuelRule.NO_SPECIAL_ATTACKS)) {
player.sendMessage("You can't use special attacks during a duel.");
return true;
}
break;
}
}
switch (interfaceId) {
case 182:
player.sendMessage("You can't logout during a duel.");
return true;
case 271:
if (session.hasRule(DuelRule.NO_PRAYER)) {
player.getPrayer().toggle(PrayerType.get(buttonId));
player.getPrayer().toggle(PrayerType.get(buttonId));
player.sendMessage("Use of prayer has been turned off for this duel.");
return true;
}
break;
case 430:
if (session.hasRule(DuelRule.NO_MAGIC)) {
player.sendMessage("Use of prayer has been turned off for this duel.");
return true;
}
break;
}
return super.actionButton(player, interfaceId, buttonId, slot, itemId, opcode);
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e.isPlayer() && target instanceof Player && !checkAttack(e.asPlayer(), ((Player) target))) {
return false;
}
if (e instanceof Familiar && target instanceof Player) {
Familiar f = (Familiar) e;
Player o = f.getOwner();
if (o != null && target.asPlayer() != getSession(o).getOpposite(o)) {
return false;
}
}
if (e instanceof Familiar && target instanceof Familiar) {
Familiar f = (Familiar) e;
Familiar t = (Familiar) target;
if (getSession(f.getOwner()).getOpposite(f.getOwner()) != t.getOwner()) {
return false;
}
}
if (e.isPlayer()) {
Player p = e.asPlayer();
DuelSession session = getSession(p);
if (session == null) {
return false;
}
boolean canAttack = true;
switch (style) {
case MAGIC:
canAttack = !session.hasRule(DuelRule.NO_MAGIC);
break;
case MELEE:
canAttack = !session.hasRule(DuelRule.NO_MELEE);
break;
case RANGE:
canAttack = !session.hasRule(DuelRule.NO_RANGE);
break;
}
if (!canAttack) {
p.sendMessage(StringUtils.formatDisplayName(style.name().toLowerCase()) + " has been turned off for this duel.");
return false;
}
if (session.hasRule(DuelRule.FUN_WEAPONS) && (p.getEquipment().get(EquipmentContainer.SLOT_WEAPON) == null || !p.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getConfiguration("fun_weapon", false))) {
p.sendMessages("This is a 'fun weapon' duel. You can only use flowers, basket of eggs, or a", "rubber chicken.");
return false;
}
if (target instanceof Familiar) {
Familiar f = (Familiar) target;
if (f.getOwner() != null && getSession(p).getOpposite(p) != f.getOwner()) {
p.sendMessage("You can't attack that familiar.");
return false;
}
}
}
return true;
}
@Override
public boolean teleport(Entity e, int type, Node node) {
if (e.isPlayer()) {
e.asPlayer().getDialogueInterpreter().sendDialogue("Coward! You can't teleport from a duel.");
}
return false;
}
@Override
public boolean enter(Entity e) {
if (e.isPlayer()) {
getSession(e.asPlayer());
e.getProperties().setSafeZone(true);
e.getProperties().setSpawnLocation(RandomFunction.getRandomElement(RESPAWN_LOCATIONS));
e.asPlayer().getInteraction().remove(DuelArenaActivity.CHALLENGE_OPTION);
e.asPlayer().getInteraction().set(FIGHT_OPTION);
} else if (e instanceof Familiar) {
Familiar f = (Familiar) e;
Player o = f.getOwner();
if (o != null && !o.getFamiliarManager().hasPet()) {
DuelSession s = getSession(f.getOwner());
if (s != null && s.hasRule(DuelRule.ENABLE_SUMMONING)) {
f.transform();
}
}
f.getProperties().setMultiZone(true);
}
return super.enter(e);
}
@SuppressWarnings("deprecation")
@Override
public boolean leave(Entity entity, boolean logout) {
entity.getProperties().setSafeZone(false);
if (entity instanceof Player) {
Player p = entity.asPlayer();
if (logout) {
p.setLocation(RandomFunction.getRandomElement(RESPAWN_LOCATIONS));
}
p.lock(1);
leave(p);
DuelSession session = getSession(p);
if (session == null) {
return true;
}
session.leave(p, logout ? 1 : p.getAttribute("duel:forfeit", false) ? 0 : 2);
remove(session.getOpposite(p));
leave(session.getOpposite(p));
} else if (entity instanceof Familiar) {
Familiar familiar = (Familiar) entity;
if (familiar.isCombatFamiliar()) {
familiar.reTransform();
}
familiar.getProperties().setMultiZone(false);
}
return super.leave(entity, logout);
}
@Override
public void configure() {
register(border);
}
/**
* Handles the leaving of a player.
* @param p the player.
*/
private void leave(Player p) {
p.getProperties().setSafeZone(false);
if (p.getAttribute("duel:ammo", null) != null) {
List<GroundItem> ammo = p.getAttribute("duel:ammo");
Container c = new Container(40);
for (GroundItem item : ammo) {
if (item == null) {
continue;
}
if (item.isActive() && GroundItemManager.getItems().contains(item) && item.droppedBy(p)) {
GroundItemManager.destroy(item);
c.add(item);
}
}
p.getInventory().addAll(c);
}
p.getInteraction().remove(FIGHT_OPTION);
p.getSkullManager().setSkullCheckDisabled(false);
p.getSkullManager().setWilderness(false);
p.getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION);
p.getProperties().setMultiZone(false);
p.getInteraction().set(DuelArenaActivity.CHALLENGE_OPTION);
}
/**
* Forcefully removes a player.
* @param player the player.
*/
private static void remove(Player player) {
HintIconManager.removeHintIcon(player, player.getAttribute("duel:icon", -1));
if (player.getExtension(DuelSession.class) != null) {
player.teleport(RandomFunction.getRandomElement(RESPAWN_LOCATIONS));
}
}
/**
* Handles the forfeit trapdoor.
* @param p the player.
*/
public static void handleForfeit(Player p) {
DuelSession session = getSession(p);
if (session == null) {
return;
}
if (session.getFightState() != 1) {
p.sendMessage("The duel has not started yet!");
return;
}
if (session.hasRule(DuelRule.NO_FORFEIT)) {
p.getDialogueInterpreter().sendDialogue("Forfeit has been turned off for this duel.");
return;
}
p.getDialogueInterpreter().sendOptions("Do you wish to forfeit?", "Yes", "No");
p.getDialogueInterpreter().addAction(new DialogueAction() {
@Override
public void handle(Player player, int buttonId) {
if (buttonId == 2) {
remove(player);
player.setAttribute("duel:forfeit", true);
}
}
});
}
/**
* Gets the starting locations for the session.
* @param session the session.
* @return the locations.
*/
public Location[] getStartLocations(DuelSession session) {
Location start = null;
Location[] locations = new Location[2];
while (start == null) {
start = center.transform(RandomFunction.random(10), RandomFunction.random(session.hasRule(DuelRule.NO_MOVEMENT) ? 6 : 10), 0);
if (isValidLocation(start)) {
locations[locations[0] == null ? 0 : 1] = start;
if (session.hasRule(DuelRule.NO_MOVEMENT)) {
Location l = null;
if (!isValidLocation(l = start.transform(1, 0, 0))) {
if (!isValidLocation(l = start.transform(-1, 0, 0))) {
if (!isValidLocation(l = start.transform(1, 0, 0))) {
if (!isValidLocation(l = start.transform(-1, 0, 0))) {
locations[1] = start;
break;
}
}
}
}
start = l;
locations[1] = l;
break;
}
start = locations[1] == null ? null : start;
} else {
start = null;
}
}
return locations;
}
@Override
public boolean startDeath(Entity entity, Entity killer) {
if (entity instanceof Player) {
Player k = killer instanceof Player ? killer.asPlayer() : killer instanceof Familiar ? ((Familiar) killer).getOwner() : null;
if (k != null) {
k.getImpactHandler().setDisabledTicks(10);
k.getSkills().heal(100);
k.lock(5);
}
}
return true;
}
@Override
public boolean death(Entity e, Entity killer) {
if (e.isPlayer() && (killer.isPlayer() || killer instanceof Familiar)) {
Player k = killer instanceof Familiar ? ((Familiar) killer).getOwner() : killer.asPlayer();
if (k != null) {
k.getSkills().heal(100);
PulseManager.cancelDeathTask(e);
}
}
return super.death(e, killer);
}
/**
* Checks if the location is valid to start on.
* @param location the location.
* @return {@code True} if so.
*/
public boolean isValidLocation(Location location) {
return RegionManager.isTeleportPermitted(location) && RegionManager.getObject(location) == null;
}
/**
* Checks the attack of a player.
* @param player the player.
* @param target the target.
* @return {@code True} if so.
*/
public boolean checkAttack(Player player, Player target) {
DuelSession session = getSession(player);
if (session == null) {
return false;
}
if (session.getOpposite(player) != target) {
player.sendMessage("You can only attack your opponent!");
return false;
}
if (session.getFightState() != 1) {
player.sendMessage("You can't attack yet!");
return false;
}
return true;
}
/**
* Gets the duel session for the player.
* @param player the player.
* @return the duel session.
*/
public static DuelSession getSession(Player player) {
DuelSession session = player.getExtension(DuelSession.class);
if (session == null) {
remove(player);
}
return session;
}
/**
* Gets the obstacles.
* @return the obstacles.
*/
public boolean isObstacles() {
return obstacles;
}
/**
* Gets the border.
* @return the border.
*/
public ZoneBorders getBorder() {
return border;
}
/**
* Gets the center.
* @return the center.
*/
public Location getCenter() {
return center;
}
/**
* Handles the forfeit trapdoor plugin.
* @author Vexia
*
*/
public static class ForfeitTrapdoorPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(3203).getHandlers().put("option:forfeit", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
handleForfeit(player);
return true;
}
@Override
public Location getDestination(Node node, Node n) {
Location loc = null;
if (node instanceof Player) {
DuelSession session = getSession(node.asPlayer());
if (session != null && session.hasRule(DuelRule.NO_MOVEMENT)) {
loc = node.getLocation();
}
}
return loc;
}
}
}
@@ -0,0 +1,229 @@
package content.minigame.duel;
import java.util.ArrayList;
import java.util.List;
import core.game.component.Component;
import core.game.activity.ActivityPlugin;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.impl.PulseManager;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.request.RequestType;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.plugin.Initializable;
import core.plugin.ClassScanner;
import core.tools.RandomFunction;
/**
* Handles the Duel Arena activity.
* @author Emperor
* @author Vexia
*
*/
@Initializable
public final class DuelArenaActivity extends ActivityPlugin {
/**
* The friendly duel request.
*/
public static final RequestType FRIEND_REQUEST = new RequestType("Sending duel offer...", ":duelfriend:", new DuelReqModule(false));
/**
* The staked duel request.
*/
public static final RequestType STAKE_REQUEST = new RequestType("Sending duel offer...", ":duelstake:", new DuelReqModule(true));
/**
* The dueling areas.
*/
public static final DuelArea[] DUEL_AREAS = new DuelArea[] { new DuelArea(0, new ZoneBorders(3332, 3244, 3357, 3258), false, Location.create(3345, 3251, 0)), new DuelArea(1, new ZoneBorders(3364, 3244, 3388, 3259), true, Location.create(3378, 3251, 0)), new DuelArea(2, new ZoneBorders(3333, 3224, 3357, 3239), true, Location.create(3345, 3231, 0)), new DuelArea(3, new ZoneBorders(3364, 3225, 3388, 3240), false, Location.create(3376, 3231, 0)), new DuelArea(4, new ZoneBorders(3333, 3205, 3357, 3220), false, Location.create(3346, 3212, 0)), new DuelArea(5, new ZoneBorders(3364, 3206, 3388, 3221), true, Location.create(3377, 3213, 0)) };
/**
* The challenge option.
*/
public static final Option CHALLENGE_OPTION = new Option("Challenge", 0);
/**
* The select duel type component.
*/
public static final Component DUEL_TYPE_SELECT = new Component(640);
/**
* The overlay.
*/
private static final Component OVERLAY = new Component(638);
/**
* The scoreboard.
*/
private static final String[] SCOREBOARD = new String[50];
/**
* Constructs a new {@code DuelArenaActivity} {@code Object}.
*/
public DuelArenaActivity() {
super("Duel arena", false, false, true);
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInterfaceManager().openOverlay(OVERLAY);
player.getInteraction().set(CHALLENGE_OPTION);
player.getConfigManager().set(286, 0);
}
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInterfaceManager().closeOverlay();
player.getInteraction().remove(CHALLENGE_OPTION);
}
return super.leave(e, logout);
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return this;
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e.isPlayer() && e.asPlayer().getZoneMonitor().getZones().size() > 1) {
return super.continueAttack(e, target, style, message);
}
return false;
}
@Override
public boolean interact(Entity e, Node target, Option o) {
if (e.isPlayer()) {
switch (target.getId()) {
case 3192:
openScoreboard(e.asPlayer());
return true;
}
}
return super.interact(e, target, o);
}
@Override
public boolean death(Entity e, Entity killer) {
if (e.isPlayer() && e.asPlayer().getZoneMonitor().getZones().size() > 1) {
return true;
}
if (e instanceof Player && killer instanceof Player) {
e.getSkills().heal(100);
PulseManager.cancelDeathTask(e);
return true;
}
return true;
}
@Override
public void configure() {
for (DuelArea area : DUEL_AREAS) {
ZoneBuilder.configure(area);
}
parseScoreboard();
register(new ZoneBorders(3325, 3201, 3396, 3280));
ClassScanner.definePlugin(new DuelArea.ForfeitTrapdoorPlugin());
ClassScanner.definePlugins(new DuelSession(null, null, false), new DuelComponentPlugin(), new ChallengeOptionPlugin());
}
/**
* Opens the scoreboard.
* @param player the player.
*/
public static void openScoreboard(Player player) {
player.lock(2);
parseScoreboard();
player.getInterfaceManager().open(new Component(632));
int index = 0;
for (int i = 16; i < 65; i++) {
player.getPacketDispatch().sendString(SCOREBOARD[index] == null ? "" : SCOREBOARD[index], 632, i - 1);
index++;
}
}
/**
* Parses the scoreboard data from the database.
*/
public static void parseScoreboard() {
/*Connection connection = SQLManager.getConnection();
if (connection == null) {
return;
}
java.sql.PreparedStatement statement;
try {
statement = connection.prepareStatement("SELECT * FROM duel_scoreboard WHERE id <= 50");
ResultSet set = statement.executeQuery();
while (set.next()) {
SCOREBOARD[set.getInt(1) - 1] = set.getString(2);
}
statement = connection.prepareStatement("DELETE FROM duel_scoreboard WHERE id > 50");
statement.executeUpdate();
} catch (SQLException e) {
SQLManager.close(connection);
e.printStackTrace();
}
SQLManager.close(connection);*/
}
/**
* Inserts an entry into the scoreboard.
* @param winner the winner.
* @param looser the looser.
*/
public static void insertEntry(Player winner, Player looser) {
/*String entry = winner.getUsername() + " (" + winner.getProperties().getCurrentCombatLevel() + ") beat " + looser.getUsername() + " (" + looser.getProperties().getCurrentCombatLevel() + ")";
Connection connection = SQLManager.getConnection();
if (connection == null) {
return;
}
java.sql.PreparedStatement statement;
try {
statement = connection.prepareStatement("UPDATE duel_scoreboard SET id = ID + 1");
statement.executeUpdate();
statement = connection.prepareStatement("INSERT INTO duel_scoreboard (id,entry) VALUES(?,?)");
statement.setInt(1, 1);
statement.setString(2, entry);
statement.executeUpdate();
} catch (SQLException e) {
SQLManager.close(connection);
e.printStackTrace();
}
SQLManager.close(connection);*/
}
/**
* Gets the dueling area.
* @param obstacles if we're using obstacles.
* @return {@code DuelArea} the area.
*/
public static DuelArea getDuelArea(boolean obstacles) {
List<DuelArea> options = new ArrayList<>(20);
for (DuelArea area : DUEL_AREAS) {
if (!obstacles && area.isObstacles() || obstacles && !area.isObstacles()) {
continue;
}
options.add(area);
}
return options.get(RandomFunction.random(options.size()));
}
}
@@ -0,0 +1,69 @@
package content.minigame.duel;
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.world.GameWorld;
import core.plugin.Plugin;
/**
* Handles the duel arena components.
* @author Vexia
*
*/
public class DuelComponentPlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(640).setPlugin(this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 640:
boolean staked = false;
switch (button) {
case 20:
Player other = player.getAttribute("duel:partner");
if (other == null || other.getExtension(DuelSession.class) != null) {
player.getPacketDispatch().sendMessage("Other player is busy at the moment.");
return true;
}
if (player.getAttribute("duel:staked", false) && other.getIronmanManager().isIronman() && !GameWorld.getSettings().isDevMode()) {
other.sendMessage("You can't accept a staked duel as an Ironman.");
player.sendMessage("You can't duel Ironman players.");
return true;
}
player.getInterfaceManager().close();
if (!player.getAttribute("duel:staked", false)) {
player.getRequestManager().request(other, DuelArenaActivity.FRIEND_REQUEST);
} else {
player.getRequestManager().request(other, DuelArenaActivity.STAKE_REQUEST);
}
return true;
case 18:
case 22:
staked = false;
break;
case 19:
case 21:
staked = true;
if (player.getIronmanManager().isIronman()) {
player.sendMessage("You can't stake as an Iron man.");
staked = false;
}
break;
default:
return false;
}
player.setAttribute("duel:staked", staked);
player.getConfigManager().set(283, (staked ? 2 : 1) << 26);
break;
}
return true;
}
}
@@ -0,0 +1,33 @@
package content.minigame.duel;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.request.RequestModule;
/**
* Handles a duel request getting accepted.
* @author Emperor
*/
public final class DuelReqModule implements RequestModule {
/**
* If the duel request is staked.
*/
private boolean staked;
/**
* Constructs a new {@code DuelReqModule} {@code Object}.
* @param staked If the duel is staked.
*/
public DuelReqModule(boolean staked) {
this.staked = staked;
}
@Override
public void open(Player player, Player target) {
DuelSession session = new DuelSession(player, target, staked);
player.addExtension(DuelSession.class, session);
target.addExtension(DuelSession.class, session);
session.openRules();
}
}
@@ -0,0 +1,72 @@
package content.minigame.duel;
import core.game.container.impl.EquipmentContainer;
/**
* Represents a dueling rule.
* @author Emperor
*/
public enum DuelRule {
NO_RANGE(4, "You cannot use Ranged attacks."), NO_MELEE(5, "You cannot use Melee attacks."), NO_MAGIC(6, "You cannot use Magic attacks."), FUN_WEAPONS(12, "You can only attack with 'fun' weapons."), NO_FORFEIT(0, "You cannot forfeit the duel."), NO_DRINKS(7, "You cannot use potions."), NO_FOOD(8, "You cannot use food."), NO_PRAYER(9, "You cannot use Prayer."), NO_MOVEMENT(1, "You cannot move."), OBSTACLES(10, "There will be obstacles in the arena."), ENABLE_SUMMONING(28, "Familiars will be allowed in the arena."), NO_SPECIAL_ATTACKS(13, "You cannot use special attacks."), NO_HATS(14, "", EquipmentContainer.SLOT_HAT), NO_CAPES(15, "", EquipmentContainer.SLOT_CAPE), NO_AMULET(16, "", EquipmentContainer.SLOT_AMULET), NO_WEAPON(17, "You can't use 2H weapons such as bows.", EquipmentContainer.SLOT_WEAPON), NO_SHIELD(19, "You can't use 2H weapons such as bows.", EquipmentContainer.SLOT_SHIELD), NO_BODY(18, "", EquipmentContainer.SLOT_CHEST), NO_LEGS(21, "", EquipmentContainer.SLOT_LEGS), NO_GLOVES(23, "", EquipmentContainer.SLOT_HANDS), NO_RINGS(26, "", EquipmentContainer.SLOT_RING), NO_BOOTS(24, "", EquipmentContainer.SLOT_FEET), NO_ARROWS(27, "", EquipmentContainer.SLOT_ARROWS);
/**
* The config index.
*/
private final int configIndex;
/**
* The information to display on the second screen.
*/
private final String info;
/**
* The equpment slot.
*/
private int equipmentSlot = -1;
/**
* Constructs a new {@code DuelRule} {@code Object}.
* @param configIndex The config index.
* @param info the info for the second screen.
*/
private DuelRule(int configIndex, String info) {
this.configIndex = configIndex;
this.info = info;
}
/**
* Constructs a new {@code DuelRule} {@code Object}.
* @param configIndex The config index.
* @param info the info for the second screen.
* @param equipmentSlot the equipment slot.
*/
private DuelRule(int configIndex, String info, int equipmentSlot) {
this.configIndex = configIndex;
this.info = info;
this.equipmentSlot = equipmentSlot;
}
/**
* Gets the configIndex.
* @return The configIndex.
*/
public int getConfigIndex() {
return configIndex;
}
/**
* Gets the info.
* @return The info.
*/
public String getInfo() {
return info;
}
/**
* Gets the equipmentSlot.
* @return the equipmentSlot.
*/
public int getEquipmentSlot() {
return equipmentSlot;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,167 @@
package content.minigame.duel;
import core.game.dialogue.DialoguePlugin;
import core.game.dialogue.FacialExpression;
import core.game.node.entity.npc.NPC;
import core.plugin.Initializable;
import core.game.node.entity.player.Player;
/**
* Represents the mubariz dialogue plugin.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class MubarizDialogue extends DialoguePlugin {
/**
* Constructs a new {@code MubarizDialogue {@code Object}.
*/
public MubarizDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code MubarizDialogue} {@code Object}.
* @param player the player.
*/
public MubarizDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new MubarizDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hi!");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Welcome to the Duel Arena!");
stage = 1;
break;
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Thanks! I need some information.");
stage = 2;
break;
case 2:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "What would you like to know?");
stage = 3;
break;
case 3:
interpreter.sendOptions("Information", "What is this place?", "How do I challenge someone to a duel?", "What kind of options are there?", "This place looks really old, where did it come from?");
stage = 4;
break;
case 4:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What is this place?");
stage = 10;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "How do I challenge someone to a duel?");
stage = 20;
break;
case 3:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What kind of options are there?");
stage = 30;
break;
case 4:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "This place looks really old, where did it come from?");
stage = 40;
break;
}
break;
case 20:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "When you go to the arena you'll go up an access ramp", "to the walkways that overlook the duel arenas. From the", "walkways you can watch the duels and challenge other", "players.");
stage = 21;
break;
case 21:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You'll know you're in the right place as you'll have a", "Duel-with option when you right-click a player.");
stage = 22;
break;
case 22:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm there!");
stage = 23;
break;
case 23:
end();
break;
case 30:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You and your opponent can offer items as a stake. If", "you win, you recieve what your opponent staked, but if", "you lose, your opponent will get whatever items you", "staked.");
stage = 31;
break;
case 31:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You can choose to use rules to spice things up a bit.", "For instance if you both agree to use the 'No Magic'", "rule then neither player can use magic to attack the", "other player. The fight will be restricted to ranging and");
stage = 32;
break;
case 32:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "melee only.");
stage = 33;
break;
case 33:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "The rules are fairly self-evident with lots of different", "combinations for you to try out!");
stage = 34;
break;
case 34:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Cool! Thanks!");
stage = 35;
break;
case 35:
end();
break;
case 40:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Now that the archaeologists have moved out, a group of", "warriors, headed by myself, have bought the land and", "converted it to a set of duel arenas. The best fighters", "from around the world come here to fight!");
stage = 41;
break;
case 41:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I challenge you!");
stage = 42;
break;
case 42:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ho! Ho! Ho!");
stage = 43;
break;
case 43:
end();
break;
case 10:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "The Duel Arena has six duel arenas where you can", "fight other players in a controlled enviornment. We", "have our own dedicated hospital where we guarantee to", "put you back together, even if you lose.");
stage = 11;
break;
case 11:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Inbetween the arenas are walkways where you can", "watch the fights and challenge other players");
stage = 13;
break;
case 13:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Sounds great. Thanks!");
stage = 14;
break;
case 14:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "See you in the arenas!");
stage = 15;
break;
case 15:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 957 };
}
}
@@ -0,0 +1,212 @@
package content.minigame.duel;
import core.game.component.Component;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.container.ContainerType;
import core.game.container.SortType;
import core.game.container.access.InterfaceContainer;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.login.PlayerParser;
import core.game.node.item.Item;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
/**
* Represents the staking container.
* @author Vexia
*
*/
public class StakeContainer extends Container {
/**
* The inventory params.
*/
private static final Object[] INVY_PARAMS = new Object[] { "", "", "", "Stake-X", "Stake-All", "Stake-10", "Stake-5", "Stake", -1, 0, 7, 4, 93, (336 << 16) };
/**
* The withdraw options.
*/
private static final String[] WITHDRAW_OPTIONS = new String[] { "Remove-X", "Remove-All", "Remove-10", "Remove-5", "Remove" };
/**
* The overlay interface.
*/
public static final Component OVERLAY = new Component(336);
/**
* The serial version UID.
*/
private static final long serialVersionUID = 3454088488966242754L;
/**
* The player of the container.
*/
private final Player player;
/**
* The dueling session.
*/
private final DuelSession session;
/**
* The stake listener.
*/
private final StakeListener listener;
/**
* If the container has been released.
*/
private boolean released;
/**
* Constructs a new {@Code StakeContainer} {@Code Object}
* @param player the player.
* @param session the session.
*/
public StakeContainer(Player player, DuelSession session) {
super(28, ContainerType.DEFAULT, SortType.ID);
this.player = player;
this.session = session;
this.getListeners().add(listener = new StakeListener());
}
/**
* Opens the staking container.
*/
public void open() {
player.getInterfaceManager().openSingleTab(OVERLAY);
player.getPacketDispatch().sendRunScript(150, "IviiiIssssssss", INVY_PARAMS);
player.getPacketDispatch().sendIfaceSettings(1278, 0, 336, 0, 27);
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, -1, 2, 93, player.getInventory(), false));
}
/**
* Offers an item to the stake.
* @param slot the slot.
* @param amount the amount.
*/
public void offer(final int slot, int amount) {
final Item item = player.getInventory().get(slot);
if (item == null) {
return;
}
if ((slot < 0 || slot > player.getInventory().capacity() || amount < 1)) {
return;
}
if (!item.getDefinition().isTradeable()) {
player.sendMessage("You can't offer that item.");
return;
}
Item remove = new Item(item.getId(), amount);
if (item.getAmount() > getMaximumAdd(item)) {
item.setAmount(getMaximumAdd(item));
if (item.getAmount() < 1) {
return;
}
}
remove.setAmount(amount > player.getInventory().getAmount(item) ? player.getInventory().getAmount(item) : amount);
if (player.getInventory().remove(remove, slot, true)) {
session.resetAccept();
add(remove);
StakeContainer c = session.getOppositeContainer(player);
c.getListener().update(c, c.getEvent());
}
}
/**
* Withdraws an item from the container.
* @param slot the slot.
* @param amount the amount.
*/
public void withdraw(final int slot, int amount) {
final Item item = get(slot);
if (item == null) {
return;
}
if ((slot < 0 || slot > player.getInventory().capacity() || amount < 1)) {
return;
}
if (!item.getDefinition().isTradeable()) {
player.sendMessage("You can't offer that item.");
return;
}
Item remove = new Item(item.getId(), amount);
if (item.getAmount() > getMaximumAdd(item)) {
item.setAmount(getMaximumAdd(item));
if (item.getAmount() < 1) {
return;
}
}
remove.setAmount(amount > getAmount(item) ? getAmount(item) : amount);
if (remove(remove, slot, true) && player.getInventory().add(remove)) {
session.resetAccept();
shift();
StakeContainer c = session.getOppositeContainer(player);
c.getListener().update(c, c.getEvent());
}
}
/**
* Releases the container back to the player.
*/
public void release() {
if (released) {
return;
}
released = true;
if (!player.getInventory().hasSpaceFor(this)) {
player.getBank().addAll(this);
player.sendMessage("Your stake was sent to your bake due to invalid inventory space.");
return;
}
player.getInventory().addAll(this);
PlayerParser.save(player);
}
/**
* Gets the serialversionuid.
* @return the serialversionuid.
*/
public static long getSerialversionuid() {
return serialVersionUID;
}
/**
* Gets the session.
* @return the session.
*/
public DuelSession getSession() {
return session;
}
/**
* Gets the listener.
* @return the listener.
*/
public StakeListener getListener() {
return listener;
}
/**
* Represents the container listener for a players stake session.
* @author Vexia
*
*/
public final class StakeListener implements ContainerListener {
@Override
public void update(Container c, ContainerEvent event) {
InterfaceContainer.generateItems(player, c.toArray(), WITHDRAW_OPTIONS, 631, 103, 12, 3);
InterfaceContainer.generateItems(player, session.getOppositeContainer(player).toArray(), WITHDRAW_OPTIONS, 631, 104, 12, 3);
}
@Override
public void refresh(Container c) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, -1, 2, 93, player.getInventory(), false));
}
}
}
@@ -0,0 +1,65 @@
package content.minigame.duel;
import core.game.dialogue.DialoguePlugin;
import core.game.dialogue.FacialExpression;
import core.game.node.entity.npc.NPC;
import core.plugin.Initializable;
import core.game.node.entity.player.Player;
/**
* Represents the dialogue plugin used for zahwa.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class ZahwaDialogue extends DialoguePlugin {
/**
* Constructs a new {@code ZahwaDialogue} {@code Object}.
*/
public ZahwaDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code ZahwaDialogue} {@code Object}.
* @param player the player.
*/
public ZahwaDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ZahwaDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hi!");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ughhhh....");
stage = 1;
break;
case 1:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 963 };
}
}
@@ -0,0 +1,89 @@
package content.minigame.fishingtrawler
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.build.DynamicRegion
import core.game.world.map.zone.ZoneRestriction
import core.plugin.Initializable
import core.tools.ticksToSeconds
import core.game.activity.ActivityManager
import core.game.activity.ActivityPlugin
import core.tools.colorize
/**
* Handles the fishing trawler "waiting room"
* @author Ceikry
*/
private val WAIT_TIME = if(GameWorld.settings?.isDevMode == true) 10 else 203
private val waitingPlayers = ArrayList<Player>()
private val sessions = ArrayList<FishingTrawlerSession>()
private var activity: FishingTrawlerActivity? = null
private var nextStart = GameWorld.ticks + WAIT_TIME
@Initializable
class FishingTrawlerActivity : ActivityPlugin("fishing trawler",false,false,true,ZoneRestriction.CANNON,ZoneRestriction.FIRES,ZoneRestriction.FOLLOWERS,ZoneRestriction.RANDOM_EVENTS) {
init {
activity = this
}
override fun configure() {
GameWorld.Pulser.submit(
object : Pulse(1){
override fun pulse(): Boolean {
if((nextStart - GameWorld.ticks) % 100 == 0){
for(player in waitingPlayers) {
player.sendMessage (colorize("%R${ticksToSeconds(nextStart - GameWorld.ticks) / 60} minutes until next game."))
}
}
if(GameWorld.ticks >= nextStart && waitingPlayers.isNotEmpty()){
val session = FishingTrawlerSession(DynamicRegion.create(8011), activity!!)
session.start(waitingPlayers)
sessions.add(session)
waitingPlayers.clear()
nextStart = GameWorld.ticks + WAIT_TIME
}
sessions.removeIf { session ->
if(!session.isActive && session.inactiveTicks >= 100){
session.clearNPCs()
true
} else {
if(!session.isActive) {
session.inactiveTicks++
}
false
}
}
return false
}
})
}
override fun start(player: Player?, login: Boolean, vararg args: Any?): Boolean {
player ?: return false
waitingPlayers.add(player)
return true
}
fun addPlayer(player: Player){
if(waitingPlayers.isEmpty()) {
nextStart = GameWorld.ticks + WAIT_TIME
player.dialogueInterpreter.sendDialogue("Trawler will leave in 2 minutes.","If you have a team get them on board now!")
}
waitingPlayers.add(player)
}
fun removePlayer(player: Player){
waitingPlayers.remove(player)
}
override fun newInstance(p: Player?): ActivityPlugin {
ActivityManager.register(this)
return this
}
override fun getSpawnLocation(): Location {
return Location.create(2667, 3161, 0)
}
}
@@ -0,0 +1,236 @@
package content.minigame.fishingtrawler
import core.game.activity.ActivityManager
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import org.rs09.consts.Items
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import core.game.system.command.sets.FISHING_TRAWLER_LEAKS_PATCHED
import core.game.system.command.sets.STATS_BASE
import core.tools.colorize
import kotlin.math.ceil
/**
* Option handler for fishing trawler
* @author Ceikry
*/
class FishingTrawlerInteractionHandler : InteractionListener {
val ENTRANCE_PLANK = 2178
val EXIT_PLANK = 2179
val HOLE = 2167
val NETIDs = intArrayOf(2164,2165)
val REWARD_NET = 2166
val BARREL_IDS = intArrayOf(2159,2160)
val BAILING_BUCKET = 583
val FULL_BAIL_BUCKET = 585
override fun defineListeners() {
on(ENTRANCE_PLANK, IntType.SCENERY, "cross"){ player, _ ->
if(player.skills.getLevel(Skills.FISHING) < 15){
player.dialogueInterpreter.sendDialogue("You need to be at least level 15 fishing to play.")
return@on true
}
player.properties.teleportLocation = Location.create(2672, 3170, 1)
(ActivityManager.getActivity("fishing trawler") as FishingTrawlerActivity).addPlayer(player)
return@on true
}
on(EXIT_PLANK, IntType.SCENERY, "cross"){ player, _ ->
player.properties.teleportLocation = Location.create(2676, 3170, 0)
(ActivityManager.getActivity("fishing trawler") as FishingTrawlerActivity).removePlayer(player)
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
session?.players?.remove(player)
return@on true
}
on(HOLE, IntType.SCENERY, "fill"){ player, node ->
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
session ?: return@on false
player.lock()
player.pulseManager.run(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(Animation(827)).also { player.lock() }
1 -> session.repairHole(player,node.asScenery()).also { player.incrementAttribute("/save:$STATS_BASE:$FISHING_TRAWLER_LEAKS_PATCHED"); player.unlock() }
2 -> return true
}
return false
}
})
return@on true
}
on(NETIDs, IntType.SCENERY, "inspect"){ player, _ ->
player.dialogueInterpreter.open(18237583)
return@on true
}
on(REWARD_NET, IntType.SCENERY, "inspect"){ player, _ ->
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
if(session == null || session.boatSank){
player.dialogueInterpreter.sendDialogues(player, core.game.dialogue.FacialExpression.GUILTY,"I'd better not go stealing other people's fish.")
return@on true
}
player.dialogueInterpreter.open(18237582)
return@on true
}
on(BARREL_IDS, IntType.SCENERY, "climb-on"){ player, _ ->
player.properties.teleportLocation = Location.create(2672, 3222, 0)
player.dialogueInterpreter.sendDialogue("You climb onto the floating barrel and begin to kick your way to the","shore.","You make it to the shore tired and weary.")
player.appearance.setDefaultAnimations()
player.appearance.sync()
return@on true
}
on(FULL_BAIL_BUCKET, IntType.ITEM, "empty"){ player, node ->
player.lock()
player.pulseManager.run(
object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(Animation(2450))
1 -> {
if(player.inventory.remove(node.asItem()))
player.inventory.add(Item(Items.BAILING_BUCKET_583))
player.unlock()
return true
}
}
return false
}
}
)
return@on true
}
on(BAILING_BUCKET, IntType.ITEM, "bail-with") { player, node ->
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
session ?: return@on false
if(!session.isActive){
return@on false
}
if(player.location.z > 0){
player.sendMessage("You can't scoop water out up here.")
return@on true
}
player.lock()
player.pulseManager.run(
object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(Animation(4471))
1 -> if(player.inventory.remove(node.asItem())) {
if (session.waterAmount > 0) {
session.waterAmount -= 20
if (session.waterAmount < 0) session.waterAmount = 0
player.inventory.add(Item(Items.BAILING_BUCKET_585))
} else {
player.sendMessage("There's no water to remove.")
player.inventory.add(node.asItem())
}
}
2 -> player.unlock().also { return true }
}
return false
}
}
)
return@on true
}
}
}
@Initializable
class NetLootDialogue(player: Player? = null): core.game.dialogue.DialoguePlugin(player){
var session: FishingTrawlerSession? = null
var rolls = 0
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
return NetLootDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
session = player.getAttribute("ft-session",null)
if(session == null) return false
rolls = ceil(session!!.fishAmount / session!!.players.size.toDouble()).toInt()
player.dialogueInterpreter.sendOptions("Skip Junk Items?","Yes","No")
stage = 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
val level = player.skills.getLevel(Skills.FISHING)
when(buttonId){
1 -> TrawlerLoot.getLoot(level, rolls, true).forEach {
if(!player.bank.add(it)) GroundItemManager.create(it,player)
}
2 -> TrawlerLoot.getLoot(level, rolls, false).forEach {
if(!player.bank.add(it)) GroundItemManager.create(it,player)
}
}
player.sendMessage(colorize("%RYour reward has been sent to your bank."))
player.skills.addExperience(Skills.FISHING,(((0.015 * player.skills.getLevel(Skills.FISHING))) * player.skills.getLevel(Skills.FISHING)) * rolls)
player.removeAttribute("ft-session")
end()
return true
}
override fun getIds(): IntArray {
return intArrayOf(18237582)
}
}
@Initializable
class NetRepairDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player){
var session: FishingTrawlerSession? = null
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
return NetRepairDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
session = player.getAttribute("ft-session",null)
if(session!!.netRipped){
player.dialogueInterpreter.sendDialogue("The net is ripped and needs repair.")
stage = 10
} else {
player.dialogueInterpreter.sendDialogue("The net is in perfect condition")
stage = 0
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
session ?: return false
when(stage++){
0 -> end()
10 -> player.dialogueInterpreter.sendOptions("Repair the net?","Yes","No")
11 -> when(buttonId){
1 -> {
end()
session!!.repairNet(player)
}
else -> {}
}
12 -> end()
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(18237583)
}
}
@@ -0,0 +1,26 @@
package content.minigame.fishingtrawler
import core.game.node.entity.player.Player
private const val configIndex = 391
private const val interfaceID = 366
private const val netOkayChild = 27
private const val netRippedChild = 28
private const val fishChild = 29
private const val timeChild = 30
/**
* Handles updating the fishing trawler overlay interface
* @author Ceikry
*/
object FishingTrawlerOverlay {
@JvmStatic
fun sendUpdate(player: Player, waterPercent: Int, NetRipped: Boolean, fishCaught: Int, timeLeft: Int){
player.configManager.set(configIndex,waterPercent)
player.packetDispatch.sendInterfaceConfig(interfaceID,if(NetRipped) netRippedChild else netOkayChild, false)
player.packetDispatch.sendInterfaceConfig(interfaceID,if(NetRipped) netOkayChild else netRippedChild, true)
player.packetDispatch.sendString("${if(fishCaught > 0) fishCaught else "Nothing"}", interfaceID, fishChild)
player.packetDispatch.sendString("$timeLeft Minutes", interfaceID, timeChild)
}
}
@@ -0,0 +1,42 @@
package content.minigame.fishingtrawler
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.Plugin
import kotlin.math.ceil
/**
* THIS will have to be implemented at a later date.
* Interface 367 in our cache, for whatever reason, opens correctly but all the children
* are null or cant hold items. This interface cant even be opened in 2 different versions
* of a cache editor I have. Something is completely fucked about this interface
* in particular.
*/
class FishingTrawlerRewardInterface : ComponentPlugin() {
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.put(367,this)
return this
}
override fun open(player: Player?, component: Component?) {
super.open(player, component)
val session: FishingTrawlerSession? = player?.getAttribute("ft-session",null)
session ?: return
val numRolls = ceil(session.fishAmount / session.players.size.toDouble()).toInt()
player?.removeAttribute("ft-session")
val loot = ArrayList<Item>()
for(i in 0 until numRolls){
}
}
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
TODO("Not yet implemented")
}
}
@@ -0,0 +1,304 @@
package content.minigame.fishingtrawler
import core.api.LogoutListener
import core.api.MapArea
import core.api.getRegionBorders
import core.game.component.Component
import core.game.node.entity.Entity
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.state.EntityState
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.map.Location
import core.game.world.map.build.DynamicRegion
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import core.game.world.update.flag.context.Animation
import core.tools.*
import org.rs09.consts.Components
import org.rs09.consts.Items
import core.game.system.command.sets.FISHING_TRAWLER_GAMES_WON
import core.game.system.command.sets.FISHING_TRAWLER_SHIPS_SANK
import core.game.system.command.sets.STATS_BASE
import core.tools.SystemLogger
import core.tools.secondsToTicks
import core.tools.ticksToSeconds
import java.util.concurrent.TimeUnit
import kotlin.random.Random
/**
* Handles a fishing trawler session
* @author Ceikry
*/
private const val OVERLAY_ID = Components.TRAWLER_OVERLAY_366
private const val TUTORIAL_ID = Components.TRAWLER_START_368
private val HOLE_X_COORDS = intArrayOf(29,30,31,32,33,34,35,36)
private const val HOLE_NORTH_Y = 26
private const val HOLE_SOUTH_Y = 23
private const val LEAKING_ID = 2167
private const val PATCHED_ID = 2168
class FishingTrawlerSession(val activity: FishingTrawlerActivity? = null) : LogoutListener, MapArea {
constructor(region: DynamicRegion, activity: FishingTrawlerActivity) : this(activity) {this.region = region; this.base = region.baseLocation}
var players: ArrayList<Player> = ArrayList()
var netRipped = false
var fishAmount = 0
var timeLeft = secondsToTicks(600)
lateinit var region: DynamicRegion
lateinit var base: Location
var isActive = false
var boatSank = false
var hole_locations = ArrayList<Location>()
var used_locations = ArrayList<Location>()
var maxHoles = 0
var waterAmount = 0
var murphy: NPC? = null
val murphyLocations = ArrayList<Location>()
val npcs = ArrayList<NPC>()
var inactiveTicks = 0
fun start(pl: ArrayList<Player>){
if(RandomFunction.roll(2)) {
region.setMusicId(38)
} else {
region.setMusicId(51)
}
this.players.addAll(pl)
isActive = true
initHoles()
initMurphy(29,25)
initGulls()
GameWorld.Pulser.submit(TrawlerPulse(this))
for(player in pl){
player.interfaceManager.openOverlay(Component(OVERLAY_ID))
player.interfaceManager.open(Component(TUTORIAL_ID))
updateOverlay(player)
player.properties.teleportLocation = base.transform(36,24,0)
player.setAttribute("ft-session",this)
player.stateManager.set(EntityState.TELEBLOCK,timeLeft)
}
zone.register(getRegionBorders(region.id))
}
fun swapBoatType(fromRegion: Int){
val newRegion = DynamicRegion.create(fromRegion)
GameWorld.Pulser.submit(SwapBoatPulse(players,newRegion))
}
class SwapBoatPulse(val playerList: ArrayList<Player>,val newRegion: DynamicRegion) : Pulse(3){
override fun pulse(): Boolean {
val session: FishingTrawlerSession? = playerList[0].getAttribute("ft-session",null)
session ?: return true
session.region = newRegion
session.base = newRegion.baseLocation
session.clearNPCs()
session.initMurphy(26,26)
session.initGulls()
for(player in playerList){
player.interfaceManager.closeOverlay()
player.appearance.setAnimations(Animation(188))
player.properties.teleportLocation = session.base.transform(36,24,0)
player.incrementAttribute("/save:$STATS_BASE:$FISHING_TRAWLER_SHIPS_SANK")
player.stateManager.remove(EntityState.TELEBLOCK)
}
return true
}
}
class TrawlerPulse(val session: FishingTrawlerSession) : Pulse(){
var ticks = 0
override fun pulse(): Boolean {
ticks++
session.timeLeft--
if(session.boatSank){
session.tickMurphy()
return true
}
if(ticks % 15 == 0 && !session.netRipped){
if(RandomFunction.random(100) <= 10){
session.ripNet()
session.murphy?.sendChat("Arrh! Check that net!")
} else {
session.fishAmount += 3
}
}
session.waterAmount += (session.getLeakingHoles())
if(session.waterAmount >= 500){
session.boatSank = true
session.isActive = false
session.swapBoatType(7755)
session.zone.unregister(getRegionBorders(session.region.id))
}
if(RandomFunction.random(100) <= 9){
session.spawnHole()
}
if(session.timeLeft <= 0){
session.isActive = false
for(player in session.players){
player.interfaceManager.closeOverlay()
player.properties.teleportLocation = Location.create(2666, 3162, 0)
player.incrementAttribute("/save:$STATS_BASE:$FISHING_TRAWLER_GAMES_WON")
}
session.zone.unregister(getRegionBorders(session.region.id))
}
for(player in session.players){
session.updateOverlay(player)
}
session.tickMurphy()
return !session.isActive
}
}
fun initHoles(){
maxHoles = players.size
if(maxHoles > 16) maxHoles = 16
if(maxHoles < 5) maxHoles = 5
val tempLocationList = ArrayList<Location>()
while(tempLocationList.size < maxHoles){
val x = HOLE_X_COORDS.random()
val y = if(Random.nextBoolean()) HOLE_NORTH_Y else HOLE_SOUTH_Y
val loc = Location.create(x,y,0)
var alreadyHas = false
for(location in tempLocationList){
if(location.equals(loc)) {
alreadyHas = true
break
}
}
if(!alreadyHas) {
tempLocationList.add(base.transform(loc.x, loc.y, 0))
}
}
hole_locations.addAll(tempLocationList)
}
fun initMurphy(localX: Int, localY: Int){
murphy = NPC(463)
murphy?.isWalks = false
murphy?.isPathBoundMovement = true
//29,25 -> 36,25
murphy?.location = base.transform(localX,localY,0)
murphy?.isRespawn = false
for(i in 29..36){
murphyLocations.add(Location.create(base.transform(i,25,0)))
}
murphy?.init()
npcs.add(murphy!!)
}
fun clearNPCs(){
npcs.forEach {
it.clear()
}
npcs.clear()
}
fun tickMurphy(){
var phrase = if(boatSank){
arrayOf("No fishes for you today!","Keep your head above water, shipmate.", "Arrrgh! We sunk!","You'll be joining Davy Jones!").random()
} else if(waterAmount < 200){
arrayOf("Blistering barnacles!","Let's get a net full of fishes!").random()
} else {
arrayOf("We'll all end up in a watery grave!","My mother could bail better than that!","It's a fierce sea today traveller.").random()
}
if(getLeakingHoles() > 0 && RandomFunction.random(100) <= 15){
phrase = "The water is coming in matey!"
}
if(RandomFunction.random(100) <= 10){
murphy?.sendChat(phrase)
}
if(RandomFunction.random(100) <= 6){
val dest = murphyLocations.random()
murphy?.walkingQueue?.reset()
murphy?.walkingQueue?.addPath(dest.x,dest.y,true)
}
}
fun initGulls(){
for(loc in arrayOf(base.transform(38,17,0),base.transform(33,18,0),base.transform(28,16,0),base.transform(28,30,0),base.transform(34,32,0))){
val npc = NPC(1179)
npc.location = loc
npcs.add(npc)
npc.isRespawn = false
npc.isWalks = true
npc.walkRadius = 6
npc.init()
}
}
fun spawnHole(){
if(hole_locations.isEmpty() && used_locations.isEmpty()) return
val holeLocation = hole_locations.random().also { hole_locations.remove(it) }
if(!SceneryBuilder.replace(Scenery(PATCHED_ID, holeLocation), Scenery(LEAKING_ID, holeLocation, if (holeLocation.y == HOLE_NORTH_Y) 1 else 3)) && !SceneryBuilder.replace(Scenery(2177, holeLocation), Scenery(LEAKING_ID, holeLocation, if (holeLocation.y == HOLE_NORTH_Y) 1 else 3))) {
maxHoles -= 1
}
}
fun getLeakingHoles(): Int{
return maxHoles - hole_locations.size
}
fun repairHole(player: Player,obj: Scenery){
if(player.inventory.remove(Item(Items.SWAMP_PASTE_1941))){
SceneryBuilder.replace(obj, Scenery(PATCHED_ID, obj.location, obj.rotation))
hole_locations.add(obj.location)
if(RandomFunction.random(100) <= 30){
murphy?.sendChat("That's the stuff! Fill those holes!")
}
} else {
player.dialogueInterpreter.sendDialogue("You need swamp paste to repair this.")
}
}
fun ripNet(){
netRipped = true
}
fun repairNet(player: Player){
if(player.inventory.remove(Item(Items.ROPE_954))){
netRipped = false
player.dialogueInterpreter.sendDialogue("You repair the net.")
} else {
player.dialogueInterpreter.sendDialogue("You need rope to repair this net.")
}
}
fun updateOverlay(player: Player){
FishingTrawlerOverlay.sendUpdate(player, ((waterAmount / 500.0) * 100).toInt(), netRipped, fishAmount, TimeUnit.SECONDS.toMinutes(ticksToSeconds(timeLeft).toLong()).toInt() + 1)
}
override fun logout(player: Player) {
val session = player.getAttribute<FishingTrawlerSession?>("ft-session",null) ?: return
player.location = Location.create(2667, 3161, 0)
session.players.remove(player)
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf()
}
override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.CANNON, ZoneRestriction.FIRES, ZoneRestriction.RANDOM_EVENTS)
}
override fun areaEnter(entity: Entity) {
super.areaEnter(entity)
SystemLogger.logInfo(this::class.java, "ENTERED FTZ")
}
override fun areaLeave(entity: Entity, logout: Boolean) {
super.areaLeave(entity, logout)
SystemLogger.logInfo(this::class.java, "EXITED FTZ")
}
}
@@ -0,0 +1,74 @@
package content.minigame.fishingtrawler
import content.global.skill.fishing.Fish
import core.game.node.item.Item
import core.game.node.item.WeightedChanceItem
import core.tools.RandomFunction
import org.rs09.consts.Items
/**
* Rolls/stores the loot table for fishing trawler
* @author Ceikry
*/
object TrawlerLoot {
val junkItems = arrayOf(Items.BROKEN_ARMOUR_698, Items.BROKEN_ARROW_687, Items.OLD_BOOT_685, Items.BROKEN_GLASS_1469, Items.BROKEN_STAFF_689, Items.BUTTONS_688,Items.DAMAGED_ARMOUR_697, Items.RUSTY_SWORD_686, Items.EMPTY_POT_1931, Items.OYSTER_407)
val trawlerFish = arrayOf(Fish.MANTA_RAY, Fish.SEA_TURTLE, Fish.SHARK, Fish.SWORDFISH, Fish.LOBSTER, Fish.TUNA, Fish.ANCHOVIE, Fish.SARDINE, Fish.SHRIMP)
fun rollTrawlerFish(fishLevel: Int): Item {
while(true) {
for(f in trawlerFish) {
if(f.level > fishLevel) {
continue
}
val lo = 0.6133
val hi = 0.7852
//val chance = RandomFunction.getSkillSuccessChance(lo, hi, fishLevel)
val chance = (fishLevel.toDouble() - 15.0)*((hi - lo) / (99.0 - 15.0)) + lo
if(RandomFunction.random(0.0, 1.0) < chance) {
return f.item
}
}
}
}
@JvmStatic
fun getLoot(fishLevel: Int, rolls: Int, skipJunk: Boolean): ArrayList<Item>{
val loot = ArrayList<Item>()
for(i in 0 until rolls){
val item = RandomFunction.rollWeightedChanceTable(listOf(*lootTable))
if(item.id == 0) {
val item = rollTrawlerFish(fishLevel)
loot.add(item)
} else {
loot.add(item)
}
}
if(skipJunk){
val removeList = ArrayList<Item>()
for(item in loot){
if(junkItems.contains(item.id)) removeList.add(item)
}
loot.removeAll(removeList)
}
return loot
}
val lootTable = arrayOf(
WeightedChanceItem(0,1,1430),
WeightedChanceItem(Items.BROKEN_ARROW_687,1,70),
WeightedChanceItem(Items.BROKEN_GLASS_1469,1,70),
WeightedChanceItem(Items.BROKEN_STAFF_689,1,70),
WeightedChanceItem(Items.BUTTONS_688,1,80),
WeightedChanceItem(Items.DAMAGED_ARMOUR_697,1,70),
WeightedChanceItem(Items.OLD_BOOT_685,1,60),
WeightedChanceItem(Items.OYSTER_407,1,50),
WeightedChanceItem(Items.EMPTY_POT_1931,1,50),
WeightedChanceItem(Items.RUSTY_SWORD_686,1,50),
//Inauthentic rewards
WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987,1,7),
WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985,1,7),
WeightedChanceItem(Items.CASKET_405,1,60),
WeightedChanceItem(Items.PIRATES_HAT_2651,1,2),
WeightedChanceItem(Items.LUCKY_CUTLASS_7140,1,2)
)
}
@@ -0,0 +1,91 @@
package content.minigame.fog;
import core.cache.def.impl.SceneryDefinition;
import core.game.activity.ActivityPlugin;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneBorders;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
/**
* Represents the fist of guthix activity.
* @author Vexia
*/
public class FOGActivityPlugin extends ActivityPlugin {
/**
* The maximum amount of players in a game.
*/
public static final int MAX_PLAYERS = 250;
/**
* The waiting interface id.
*/
public static final int WAITING_INTERFACE = 731;
/**
* The current fist of guthix round.
*/
private int round;
/**
* Constructs a new {@code FOGActivityPlugin} {@code Object}
*/
public FOGActivityPlugin() {
super("Fist of Guthix", false, true, true);
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return new FOGActivityPlugin();
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public void configure() {
ClassScanner.definePlugin(new FOGLobbyZone());
ClassScanner.definePlugin(new FOGWaitingZone());
ClassScanner.definePlugin(new OptionHandler() {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(30204).getHandlers().put("option:enter", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
switch (node.getId()) {
case 30204:
player.teleport(Location.create(1675, 5599, 0));
return true;
}
return true;
}
});
register(new ZoneBorders(1625, 5638, 1715, 5747));
}
/**
* Gets the round.
* @return the round
*/
public int getRound() {
return round;
}
/**
* Sets the round.
* @param round the round to set.
*/
public void setRound(int round) {
this.round = round;
}
}
@@ -0,0 +1,75 @@
package content.minigame.fog;
import core.game.component.Component;
import core.game.interaction.Option;
import core.game.node.Node;
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.MapZone;
import core.game.world.map.zone.ZoneBuilder;
import core.plugin.Plugin;
/**
* Represents a zone where players can prepare for a game.
* @author Vexia
*/
public class FOGLobbyZone extends MapZone implements Plugin<Object> {
/**
* Constructs a new {@code FOGHallZone} {@code Object}
*/
public FOGLobbyZone() {
super("Fog Lobby", true);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
return this;
}
@Override
public boolean enter(Entity e) {
if (e.isPlayer()) {
sendInterface(e.asPlayer());
}
return super.enter(e);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (!e.isPlayer()) {
return super.interact(e, target, option);
}
Player player = e.asPlayer();
switch (target.getId()) {
case 30203:
player.teleport(Location.create(3242, 3574, 0));
return true;
}
return super.interact(e, target, option);
}
/**
* Sends the fist of guthix lobby interface.
* @param player the player.
*/
private void sendInterface(Player player) {
player.getInterfaceManager().openOverlay(new Component(FOGActivityPlugin.WAITING_INTERFACE));
player.getPacketDispatch().sendInterfaceConfig(FOGActivityPlugin.WAITING_INTERFACE, 17, true);
player.getPacketDispatch().sendInterfaceConfig(FOGActivityPlugin.WAITING_INTERFACE, 26, true);
player.getPacketDispatch().sendString("Rating: " + player.getSavedData().getActivityData().getFogRating(), FOGActivityPlugin.WAITING_INTERFACE, 7);
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
@Override
public void configure() {
super.registerRegion(6743);
}
}
@@ -0,0 +1,104 @@
package content.minigame.fog;
import core.game.node.entity.player.Player;
/**
* Represents a fist of guthix player.
* @author Vexia
*/
public class FOGPlayer {
/**
* The player instance.
*/
private final Player player;
/**
* The target FOG player.
*/
private final FOGPlayer target;
/**
* If the player is hunted or a hunter.
*/
private boolean hunted;
/**
* The amount of fist of guthix charges.
*/
private int charges;
/**
* Constructs a new {@code FOGPlayer} {@code Object}
* @param player the player.
* @param oponent the other player.
*/
public FOGPlayer(Player player, FOGPlayer oponent) {
this.player = player;
this.target = oponent;
}
/**
* Switches the roles of the player.
*/
public void switchRoles() {
hunted = !hunted;
}
/**
* Increments the energy charges.
* @param increment the number to increment.
*/
public void incrementCharges(int increment) {
charges += increment;
}
/**
* Gets the hunted.
* @return the hunted
*/
public boolean isHunted() {
return hunted;
}
/**
* Sets the hunted.
* @param hunted the hunted to set.
*/
public void setHunted(boolean hunted) {
this.hunted = hunted;
}
/**
* Gets the charges.
* @return the charges
*/
public int getCharges() {
return charges;
}
/**
* Sets the charges.
* @param charges the charges to set.
*/
public void setCharges(int charges) {
this.charges = charges;
}
/**
* Gets the player.
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Gets the target.
* @return the target
*/
public FOGPlayer getTarget() {
return target;
}
}
@@ -0,0 +1,124 @@
package content.minigame.fog
import core.cache.def.impl.ItemDefinition
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.SystemLogger
@Initializable
class FOGRewardsInterface : ComponentPlugin(){
class ShopItem(val id: Int,val price: Int,val amount: Int)
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
var choice = ShopItem(0, 0, 0)
when(button){
2 -> choice = Druidic_Mage_Top
7 -> choice = Druidic_Mage_Bottom
12 -> choice = Druidic_Mage_Hood
19 -> choice = Combat_Robe_Top
24 -> choice = Combat_Robe_Bottom
29 -> choice = Combat_Robe_Hood
36 -> choice = Battle_Robe_Top
41 -> choice = Battle_Robe_Bottom
46 -> choice = Battle_Robe_Hood
53 -> choice = Green_Coif
58 -> choice = Blue_Coif
63 -> choice = Red_Coif
68 -> choice = Black_Coif
75 -> choice = Bronze_Gaunt
80 -> choice = Iron_Gaunt
85 -> choice = Steel_Gaunt
90 -> choice = Black_Gaunt
95 -> choice = Mithril_Gaunt
100 -> choice = Adamant_Gaunt
105 -> choice = Rune_Gaunt
110 -> choice = Dragon_Gaunt
117 -> choice = Addy_Spike
122 -> choice = Addy_Beserk
127 -> choice = Rune_Spike
132 -> choice = Rune_Beserk
139 -> choice = Irit_Gloves
144 -> choice = Avantoe_Gloves
149 -> choice = Kwuarm_Gloves
154 -> choice = Cadantine_Gloves
161 -> choice = Swordfish_Gloves
166 -> choice = Shark_Gloves
171 -> choice = Dragon_Gloves
176 -> choice = Air_Gloves
181 -> choice = Water_Gloves
186 -> choice = Earth_Gloves
else -> SystemLogger.logWarn(this::class.java, "Unhandled button ID for FOG interface: $button").also { return true }
}
handleOpcode(choice,opcode,player!!)
return true
}
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.forId(732).plugin = this
return this
}
private fun handleOpcode(item: ShopItem, opcode: Int, player: Player){
when(opcode){
155 -> player.sendMessage("${ItemDefinition.forId(item.id).name.replace("100","")}: costs ${item.price} tokens.")
196 -> handleBuyOption(item,1,player)
124 -> handleBuyOption(item,5,player)
199 -> handleBuyOption(item,10,player)
234 -> player.sendMessage(ItemDefinition.forId(item.id).examine.replace("100",""))
}
}
private fun handleBuyOption(item: ShopItem, amount: Int, player: Player){
val neededTokens = Item(12852,item.price * amount)
if(player.inventory.containsItem(neededTokens)){
if(player.inventory.hasSpaceFor(Item(item.id,amount))){
player.inventory.remove(neededTokens)
player.inventory.add(Item(item.id,amount))
} else {
player.sendMessage("You don't have enough space in your inventory.")
}
}
}
val Druidic_Mage_Top = (ShopItem(12894, 300, 1))
val Druidic_Mage_Hood = (ShopItem(12887, 100, 1))
val Druidic_Mage_Bottom = (ShopItem(12901, 200, 1))
val Combat_Robe_Top = (ShopItem(12971, 150, 1))
val Combat_Robe_Hood = (ShopItem(12964, 50, 1))
val Combat_Robe_Bottom = (ShopItem(12978, 100, 1))
val Battle_Robe_Hood = (ShopItem(12866, 250, 1))
val Battle_Robe_Top = (ShopItem(12873, 1500, 1))
val Battle_Robe_Bottom = (ShopItem(12880, 1000, 1))
val Green_Coif = (ShopItem(12936, 150, 1))
val Blue_Coif = (ShopItem(12943, 200, 1))
val Red_Coif = (ShopItem(12950, 300, 1))
val Black_Coif = (ShopItem(12957, 500, 1))
val Bronze_Gaunt = (ShopItem(12985, 15, 1))
val Iron_Gaunt = (ShopItem(12988, 30, 1))
val Steel_Gaunt = (ShopItem(12991, 50, 1))
val Black_Gaunt = (ShopItem(12994, 75, 1))
val Mithril_Gaunt = (ShopItem(12997, 100, 1))
val Adamant_Gaunt = (ShopItem(13000, 150, 1))
val Rune_Gaunt = (ShopItem(13003, 200, 1))
val Dragon_Gaunt = (ShopItem(13006, 300, 1))
val Addy_Spike = (ShopItem(12908, 50, 1))
val Addy_Beserk = (ShopItem(12915, 100, 1))
val Rune_Spike = (ShopItem(12922, 200, 1))
val Rune_Beserk = (ShopItem(12929, 300, 1))
val Air_Gloves = (ShopItem(12863, 75, 1))
val Water_Gloves = (ShopItem(12864, 75, 1))
val Earth_Gloves = (ShopItem(12865, 75, 1))
val Irit_Gloves = (ShopItem(12856, 75, 1))
val Avantoe_Gloves = (ShopItem(12857, 100, 1))
val Kwuarm_Gloves = (ShopItem(12858, 200, 1))
val Cadantine_Gloves = (ShopItem(12859, 200, 1))
val Swordfish_Gloves = (ShopItem(12860, 200, 1))
val Shark_Gloves = (ShopItem(12861, 200, 1))
val Dragon_Gloves = (ShopItem(12862, 200, 1))
}
@@ -0,0 +1,49 @@
package content.minigame.fog;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBuilder;
import core.plugin.Plugin;
/**
* Represents the zone where players wait for a match.
* @author Vexia
*/
public class FOGWaitingZone extends MapZone implements Plugin<Object> {
/**
* Constructs a new {@code FOGLobbyZone} {@code Object}
*/
public FOGWaitingZone() {
super("Fog Waiting Room", true);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
return this;
}
@Override
public boolean enter(Entity e) {
return super.enter(e);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
return super.interact(e, target, option);
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
@Override
public void configure() {
super.registerRegion(6487);
}
}
@@ -0,0 +1,45 @@
package content.minigame.fog
import core.game.global.action.ClimbActionHandler
import core.game.interaction.DestinationFlag
import core.game.interaction.MovementPulse
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.plugin.Plugin
import core.game.interaction.PluginInteraction
import core.game.interaction.PluginInteractionManager
@Initializable
class FogInteractionHandler : PluginInteraction(30204, 30203){
override fun handle(player: Player?, node: Node?): Boolean {
when(node?.id){
30204 -> player?.pulseManager?.run(ClimbPulse(player,node as Scenery)).also { return true }
30203 -> player?.pulseManager?.run(ClimbPulse(player, node as Scenery)).also { return true }
}
return false
}
class ClimbPulse(val player: Player,val obj: Scenery) : MovementPulse(player,obj, DestinationFlag.OBJECT){
override fun pulse(): Boolean {
player.faceLocation(obj.location)
when(obj.id) {
30204 -> core.game.global.action.ClimbActionHandler.climbLadder(player, obj, "climb-down")
30203 -> core.game.global.action.ClimbActionHandler.climbLadder(player,obj,"climb-up")
}
return true
}
}
override fun fireEvent(identifier: String?, vararg args: Any?): Any {
return Unit
}
override fun newInstance(arg: Any?): Plugin<Any> {
PluginInteractionManager.register(this, PluginInteractionManager.InteractionType.OBJECT)
return this
}
}
@@ -0,0 +1,63 @@
package content.minigame.fog
import core.game.component.Component
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.world.GameWorld
import core.plugin.Initializable
@Initializable
class ReggieDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player){
override fun open(vararg args: Any?): Boolean {
if(GameWorld.settings?.allow_token_purchase == true){
options("Can I see your shop?","Nevermind.","Can I buy some tokens?")
} else {
options("Can I see your shop?","Nevermind.")
}
stage = 0
return true
}
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
FOGRewardsInterface().newInstance(Unit)
return ReggieDialogue(player)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
var buyAmount = 0
when(stage){
0 -> when(buttonId){
1 -> npc("Certainly!").also { stage++ }
2 -> end()
3 -> npc("Sure thing. My tokens are 1000 coins","each.").also { stage = 10 }
}
1 -> end().also { player.interfaceManager.open(Component(732)) }
//Buying tokens with config option set to true
10 -> player?.dialogueInterpreter?.sendOptions("How many?","50","100","250","500").also { stage++ }
11 -> when(buttonId){
1 -> buyAmount = 50
2 -> buyAmount = 100
3 -> buyAmount = 250
4 -> buyAmount = 500
else -> buyAmount = 0
}.also {
if(buyAmount > 0){
if(player?.inventory?.containsItem(Item(995, 1000 * buyAmount))!!) {
player?.inventory?.add(Item(12852, buyAmount))
player?.inventory?.remove(Item(995, 1000 * buyAmount))
} else {
player?.sendMessage("You dont have enough coins for that.")
}
}
end()
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(7601)
}
}
@@ -0,0 +1,32 @@
package content.minigame.gnomecooking
import core.cache.def.impl.ItemDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
@Initializable
class DeliveryBoxHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ItemDefinition.forId(9477).handlers["option:check"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
val jobId = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_JOB_ORDINAL",-1)
if(jobId == -1){
player.dialogueInterpreter.sendDialogue("You do not currently have a job.")
} else {
val job = GnomeCookingJob.values()[jobId]
val item = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_NEEDED_ITEM", Item(0))
player.dialogueInterpreter.sendDialogue("I need to deliver a ${item.name.toLowerCase()} to ${NPC(job.npc_id).name.toLowerCase()},","who is ${job.tip}")
}
return true
}
}
@@ -0,0 +1,41 @@
package content.minigame.gnomecooking
import content.minigame.gnomecooking.GnomeTipper.getTip
import core.game.node.item.Item
import core.game.dialogue.DialogueFile
import core.tools.END_DIALOGUE
import core.tools.colorize
class GCCompletionDialogue(val job: GnomeCookingJob) : DialogueFile() {
override fun handle(componentID: Int, buttonID: Int) {
when(stage){
0 -> {
val neededItem = player!!.getAttribute<Item>("$GC_BASE_ATTRIBUTE:$GC_NEEDED_ITEM", null)
if (neededItem != null && player!!.inventory.containsItem(neededItem)) {
player!!.dialogueInterpreter.sendDialogues(job.npc_id, core.game.dialogue.FacialExpression.OLD_HAPPY, "Thank you!")
player!!.inventory.remove(neededItem)
player!!.inventory.add(getTip(job.level))
player!!.removeAttribute("$GC_BASE_ATTRIBUTE:$GC_JOB_ORDINAL")
player!!.removeAttribute("$GC_BASE_ATTRIBUTE:$GC_NEEDED_ITEM")
var curPoints = player!!.getAttribute("$GC_BASE_ATTRIBUTE:$GC_POINTS", 0)
curPoints += 3
if (curPoints == 12) {
player!!.inventory.add(Item(9474))
player!!.sendMessage(colorize("%RYou have been granted a food delivery token. Use it to have food delivered."))
} else if (curPoints % 12 == 0) {
var curRedeems = player!!.getAttribute("$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD", 0)
player!!.setAttribute(
"/save:$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD",
if (curRedeems != 10) ++curRedeems else curRedeems
)
player!!.sendMessage(colorize("%RYou have been granted a single food delivery charge."))
}
player!!.setAttribute("/save:$GC_BASE_ATTRIBUTE:$GC_POINTS", curPoints)
} else {
player!!.dialogueInterpreter.sendDialogues(job.npc_id, core.game.dialogue.FacialExpression.ANGRY, "Where's my food?!")
}
stage = END_DIALOGUE
}
}
}
}
@@ -0,0 +1,107 @@
package content.minigame.gnomecooking
import core.cache.def.impl.ItemDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.plugin.Initializable
import core.plugin.Plugin
import core.tools.RandomFunction
import org.rs09.consts.Items
import core.game.world.GameWorld
val gnomeItems = arrayOf(
Items.FRUIT_BATTA_2277, Items.TOAD_BATTA_2255, Items.CHEESE_PLUSTOM_BATTA_2259, Items.WORM_BATTA_2253, Items.VEGETABLE_BATTA_2281,
Items.CHOCOLATE_BOMB_2185, Items.VEG_BALL_2195, Items.TANGLED_TOADS_LEGS_2187, Items.WORM_HOLE_2191, Items.TOAD_CRUNCHIES_2217, Items.WORM_CRUNCHIES_2205, Items.CHOCCHIP_CRUNCHIES_2209, Items.SPICY_CRUNCHIES_2213)
@Initializable
class GCRewardTokenHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
val def = ItemDefinition.forId(9474)
def.handlers["option:check"] = this
def.handlers["option:activate"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
option ?: return false
when(option){
"check" -> {
val charges = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD",0)
player.dialogueInterpreter.sendDialogue("You have $charges redeemable charges.")
}
"activate" -> {
player.dialogueInterpreter.open(939382893)
}
}
return true
}
@Initializable
class RewardTokenActivationDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player){
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
return RewardTokenActivationDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
player.dialogueInterpreter.sendOptions("How many charges?","1","5","10")
stage = 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> end().also {
when (buttonId) {
1 -> sendCharges(1, player)
2 -> sendCharges(5, player)
3 -> sendCharges(10, player)
}
}
}
return true
}
fun sendCharges(amount: Int, player: Player){
val playerCharges = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD",0)
if(playerCharges < amount){
player.dialogueInterpreter.sendDialogue("You don't have that many charges.")
return
}
if(player.inventory.freeSlots() < amount){
player.dialogueInterpreter.sendDialogue("You don't have enough space in your inventory.")
return
}
val itemList = ArrayList<Item>()
for(charge in 0 until amount){
itemList.add(Item(gnomeItems.random()))
}
player.dialogueInterpreter.sendDialogue("You put in for delivery of $amount items. Wait a bit...")
GameWorld.Pulser.submit(DeliveryPulse(player,itemList))
player.setAttribute("/save:$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD", playerCharges - amount)
}
class DeliveryPulse(val player: Player,val items: ArrayList<Item>) : Pulse(RandomFunction.random(15,30)){
override fun pulse(): Boolean {
player.inventory.add(*items.toTypedArray())
player.dialogueInterpreter.sendDialogue("Your food delivery has arrived!")
return true
}
}
override fun getIds(): IntArray {
return intArrayOf(939382893)
}
}
}
@@ -0,0 +1,11 @@
package content.minigame.gnomecooking
const val GC_BASE_ATTRIBUTE = "gnome_cooking"
const val GC_TUT_PROG = "gnome-cooking:tutorial:stage"
const val GC_TUT_FIN = "gnome-cooking:tutorial:complete"
const val GC_JOB_ORDINAL = "job:job_ordinal"
const val GC_JOB_COMPLETE = "job:job_complete"
const val GC_HARD_JOB = "job:hard_job"
const val GC_NEEDED_ITEM = "job:needed_item"
const val GC_POINTS = "job:points"
const val GC_REDEEMABLE_FOOD = "job:redeemable_food"
@@ -0,0 +1,19 @@
package content.minigame.gnomecooking
enum class GnomeCookingJob(val level: GnomeTipper.LEVEL, val npc_id: Int, val tip: String) {
CPT_ERRDO(GnomeTipper.LEVEL.EASY,3811, "at the top level of the Grand Tree."),
DALILAH(GnomeTipper.LEVEL.EASY,4588, "sitting in the Gnome Restaurant."),
GULLUCK(GnomeTipper.LEVEL.EASY,602, "on the third level of the Grand Tree."),
ROMETTI(GnomeTipper.LEVEL.EASY,601, "on the second level of the Grand Tree."),
NARNODE(GnomeTipper.LEVEL.EASY,670, "at the base of the Grand Tree."),
MEEGLE(GnomeTipper.LEVEL.EASY,4597, "in the terrorbird enclosure."),
PERRDUR(GnomeTipper.LEVEL.EASY,4587,"sitting in the Gnome Restaurant."),
SARBLE(GnomeTipper.LEVEL.EASY,4599, "in the swamp west of the Grand Tree."),
GIMLEWAP(GnomeTipper.LEVEL.HARD,4580, "upstairs in Ardougne castle."),
BLEEMADGE(GnomeTipper.LEVEL.HARD,3810, "at the top of White Wolf Mountain."),
DALBUR(GnomeTipper.LEVEL.HARD,3809, "by the gnome glider in Al Kharid"),
BOLREN(GnomeTipper.LEVEL.HARD,469, "next to the Spirit Tree in Tree Gnome Village"),
SCHEPBUR(GnomeTipper.LEVEL.HARD,3817, "in the battlefield of Khazar, south of the river."),
IMBLEWYN(GnomeTipper.LEVEL.HARD,4586, "on the ground floor of the Magic Guild."),
ONGLEWIP(GnomeTipper.LEVEL.HARD,4585, "in the Wizard's Tower south of Draynor.")
}
@@ -0,0 +1,68 @@
package content.minigame.gnomecooking
import core.game.node.item.Item
import core.game.node.item.WeightedChanceItem
import core.tools.RandomFunction
import org.rs09.consts.Items
object GnomeTipper {
private val easyTips = arrayListOf(
WeightedChanceItem(995,50,100,30),
WeightedChanceItem(995,23,76,50),
WeightedChanceItem(995,10,250,20)
)
private val hardTips = arrayListOf(
//Uniques Weight = 18
WeightedChanceItem(Items.GNOME_GOGGLES_9472,1,2),
WeightedChanceItem(Items.GNOME_SCARF_9470,1,2),
WeightedChanceItem(Items.GRAND_SEED_POD_9469,5,7),
WeightedChanceItem(Items.MINT_CAKE_9475,1,4),
WeightedChanceItem(Items.GNOMEBALL_751,1,4),
//Herbs Weight = 20
WeightedChanceItem(Items.CLEAN_TOADFLAX_2998,3,10),
WeightedChanceItem(Items.CLEAN_SNAPDRAGON_3000,1,10),
//Uncut Gems Weight = 46
WeightedChanceItem(Items.RED_TOPAZ_1613,1,8),
WeightedChanceItem(Items.DIAMOND_1601,1,7),
WeightedChanceItem(Items.UNCUT_EMERALD_1621,3,5,7),
WeightedChanceItem(Items.UNCUT_JADE_1627,2,3,7),
WeightedChanceItem(Items.UNCUT_SAPPHIRE_1623,6,10,8),
WeightedChanceItem(Items.UNCUT_RUBY_1619,2,3,7),
WeightedChanceItem(Items.UNCUT_OPAL_1625,1,10),
//Runes Weight = 25
WeightedChanceItem(Items.COSMIC_RUNE_564,11,5),
WeightedChanceItem(Items.NATURE_RUNE_561,10,15,5),
WeightedChanceItem(Items.LAW_RUNE_563,10,5),
WeightedChanceItem(Items.DEATH_RUNE_560,11,5),
WeightedChanceItem(Items.SOUL_RUNE_566,9,5),
//Untipped crossbow bolts Weight = 9
WeightedChanceItem(Items.MITHRIL_BOLTS_UNF_9379,5,10,3),
WeightedChanceItem(Items.ADAMANT_BOLTSUNF_9380,3,5,3),
WeightedChanceItem(Items.RUNITE_BOLTS_UNF_9381,1,3,3),
//Other tips
WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987,1,9),
WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985,1,9),
WeightedChanceItem(Items.PURE_ESSENCE_7937,97,3),
WeightedChanceItem(Items.BIRDS_NEST_5072,1,2),
WeightedChanceItem(Items.YEW_SEED_5315,1,6),
WeightedChanceItem(Items.CALQUAT_TREE_SEED_5290,1,6)
)
enum class LEVEL {
EASY,
HARD
}
@JvmStatic
fun getTip(level: LEVEL): Item {
return when(level){
LEVEL.EASY -> RandomFunction.rollWeightedChanceTable(easyTips)
LEVEL.HARD -> RandomFunction.rollWeightedChanceTable(hardTips)
}
}
}
@@ -0,0 +1,66 @@
package content.minigame.gnomecooking.battas
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
import core.game.world.GameWorld
/**
* Handles cook options for battas
* @author Ceikry
*/
@Initializable
class GnomeBattaCooker : UseWithHandler(Items.RAW_BATTA_2250,9478,9480,9482,9483,9485) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(17131, OBJECT_TYPE,this)
addHandler(2728, OBJECT_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used
val product = when(used.id){
Items.RAW_BATTA_2250 -> Item(Items.HALF_BAKED_BATTA_2249)
9478 -> Item(9479)
9480 -> Item(9481)
9483 -> Item(9484)
9485 -> Item(9486)
9482 -> Item(2255)
else -> Item(0)
}
if(product.id == 0) return false
cook(player,used.asItem(),product)
return true
}
fun cook(player: Player, raw: Item, product: Item){
GameWorld.Pulser.submit(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.lock().also { player.animator.animate(Animation(883)) }
2 -> {
if(player.inventory.containsItem(raw)) {
player.inventory.remove(raw)
player.inventory.add(product)
if(product.id == 2255) player.skills.addExperience(Skills.COOKING,82.0)
else player.skills.addExperience(Skills.COOKING,40.0)
}
player.unlock()
return true
}
}
return false
}
})
}
}
@@ -0,0 +1,36 @@
package content.minigame.gnomecooking.battas
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
private const val GIANNE_DOUGH = 2171
private const val BATTA_MOULD = 2164
private const val RAW_CRUNCHIES = 2202
/**
* Fills gnome batta dishes
* @author Ceikry
*/
@Initializable
class GnomeBattaDishFiller : UseWithHandler(GIANNE_DOUGH) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(BATTA_MOULD, ITEM_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used
val with = event.usedWith
player.inventory.remove(used.asItem())
player.inventory.remove(with.asItem())
player.inventory.add(Item(Items.RAW_BATTA_2250))
return true
}
}
@@ -0,0 +1,51 @@
package content.minigame.gnomecooking.battas
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
/**
* Handles garnishing of battas
* @author Ceikry
*/
@Initializable
class GnomeBattaGarnisher : UseWithHandler(9479,9481,9484,9486) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(Items.EQUA_LEAVES_2128, ITEM_TYPE,this)
addHandler(Items.GNOME_SPICE_2169, ITEM_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used.asItem()
val with = event.usedWith.asItem()
var product = -1
when(with.id){
Items.EQUA_LEAVES_2128 -> {
when(used.id){
9486 -> product = Items.WORM_BATTA_2253
9484 -> product = Items.VEGETABLE_BATTA_2281
9479 -> product = Items.CHEESE_PLUSTOM_BATTA_2259
}
}
Items.GNOME_SPICE_2169 -> {
when(used.id){
9481 -> product = Items.FRUIT_BATTA_2277
}
}
}
if(product == -1) return false
player.inventory.remove(used)
player.inventory.remove(with)
player.inventory.add(Item(product))
player.skills.addExperience(Skills.COOKING,88.0)
return true
}
}
@@ -0,0 +1,97 @@
package content.minigame.gnomecooking.battas
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.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
private const val WORM_BATTA = 2219
private const val TOAD_BATTA = 2221
private const val CHEESE_TOM_BATTA = 2223
private const val FRUIT_BATTA = 2225
private const val VEG_BATTA = 2227
/**
* Handles the gnome batta interface
* @author Ceikry
*/
@Initializable
class GnomeBattaInterface : ComponentPlugin() {
override fun open(player: Player?, component: Component?) {
component ?: return
player ?: return
super.open(player, component)
player.packetDispatch.sendItemOnInterface(FRUIT_BATTA,component.id,component.id,3)
player.packetDispatch.sendItemOnInterface(TOAD_BATTA,component.id,component.id,14)
player.packetDispatch.sendItemOnInterface(WORM_BATTA,component.id,component.id,25)
player.packetDispatch.sendItemOnInterface(VEG_BATTA,component.id,component.id,34)
player.packetDispatch.sendItemOnInterface(CHEESE_TOM_BATTA,component.id,component.id,47)
}
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
player ?: return false
component ?: return false
when(button){
3 -> attemptMake(CookedProduct.HALF_MADE_FR,player)
14 -> attemptMake(CookedProduct.HALF_MADE_TO,player)
25 -> attemptMake(CookedProduct.HALF_MADE_WO,player)
34 -> attemptMake(CookedProduct.HALF_MADE_VE,player)
47 -> attemptMake(CookedProduct.HALF_MADE_CT,player)
}
return true
}
private fun attemptMake(batta: CookedProduct, player: Player){
if(!player.inventory.containsItem(Item(Items.GNOME_SPICE_2169)) && (batta == CookedProduct.HALF_MADE_TO || batta == CookedProduct.HALF_MADE_WO) ){
player.dialogueInterpreter.sendDialogue("You need gnome spices for this.")
return
}
if(player.skills.getLevel(Skills.COOKING) < batta.levelReq){
player.dialogueInterpreter.sendDialogue("You don't have the needed level to make this.")
return
}
var hasAll = true
for(item in batta.requiredItems){
if(!player.inventory.containsItem(item)){
hasAll = false
break
}
}
if(!hasAll){
player.dialogueInterpreter.sendDialogue("You don't have all the ingredients needed for this.")
return
}
player.inventory.remove(*batta.requiredItems)
player.inventory.remove(Item(Items.HALF_BAKED_BATTA_2249))
player.inventory.add(Item(batta.product))
player.skills.addExperience(Skills.COOKING,batta.experience)
player.interfaceManager.close()
}
internal enum class CookedProduct(val product: Int,val levelReq: Int, val experience: Double, val requiredItems: Array<Item>){
HALF_MADE_CT(9478,29,40.0, arrayOf(Item(Items.TOMATO_1982), Item(Items.CHEESE_1985))),
HALF_MADE_FR(9480,25,40.0, arrayOf(Item(Items.EQUA_LEAVES_2128,4), Item(Items.LIME_CHUNKS_2122), Item(Items.ORANGE_CHUNKS_2110), Item(Items.PINEAPPLE_CHUNKS_2116))),
HALF_MADE_TO(9482,26,40.0, arrayOf(Item(Items.EQUA_LEAVES_2128), Item(Items.CHEESE_1985), Item(Items.TOADS_LEGS_2152))),
HALF_MADE_VE(9483,28,40.0, arrayOf(Item(Items.TOMATO_1982,2), Item(Items.CHEESE_1985), Item(Items.DWELLBERRIES_2126), Item(Items.ONION_1957), Item(Items.CABBAGE_1965))),
HALF_MADE_WO(9485,27,40.0, arrayOf(Item(Items.KING_WORM_2162), Item(Items.CHEESE_1985)))
}
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.put(434,this)
return this
}
}
@@ -0,0 +1,29 @@
package content.minigame.gnomecooking.battas
import core.cache.def.impl.ItemDefinition
import core.game.component.Component
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
/**
* Handles the prepare option for gnome battas
* @author Ceikry
*/
@Initializable
class GnomeBattaPrepareHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ItemDefinition.forId(Items.HALF_BAKED_BATTA_2249).handlers["option:prepare"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
player.interfaceManager.open(Component(434))
return true
}
}
@@ -0,0 +1,64 @@
package content.minigame.gnomecooking.bowls
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
import core.game.world.GameWorld
@Initializable
class GnomeBowlCooker : UseWithHandler(Items.RAW_GNOMEBOWL_2178,9558,9559,9561,9563) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(17131, OBJECT_TYPE,this)
addHandler(2728, OBJECT_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used
val product = when(used.id){
Items.RAW_GNOMEBOWL_2178 -> Item(Items.HALF_BAKED_BOWL_2177)
9558 -> Item(9560)
9559 -> Item(Items.TANGLED_TOADS_LEGS_2187)
9561 -> Item(9562)
9563 -> Item(9564)
else -> Item(0)
}
if(product.id == 0) return false
cook(player,used.asItem(),product)
return true
}
fun cook(player: Player, raw: Item, product: Item){
GameWorld.Pulser.submit(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.lock().also { player.animator.animate(Animation(883)) }
2 -> {
if(player.inventory.containsItem(raw)) {
if(product.id > 2180){
player.inventory.add(Item(Items.GNOMEBOWL_MOULD_2166))
}
player.inventory.remove(raw)
player.inventory.add(product)
player.skills.addExperience(Skills.COOKING,30.0)
}
player.unlock()
return true
}
}
return false
}
})
}
}
@@ -0,0 +1,59 @@
package content.minigame.gnomecooking.bowls
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
/**
* Handles garnishing of gnomebowls
* @author Ceikry
*/
@Initializable
class GnomeBowlGarnisher : UseWithHandler(9560,9562,9564) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(Items.EQUA_LEAVES_2128, ITEM_TYPE,this)
addHandler(Items.POT_OF_CREAM_2130, ITEM_TYPE,this)
addHandler(Items.CHOCOLATE_DUST_1975, ITEM_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used.asItem()
val with = event.usedWith.asItem()
var product = -1
when(with.id){
Items.EQUA_LEAVES_2128 -> {
when(used.id){
9562 -> product = Items.VEG_BALL_2195
9564 -> product = Items.WORM_HOLE_2191
}
}
Items.POT_OF_CREAM_2130,Items.CHOCOLATE_DUST_1975 -> {
when(used.id){
9560 -> product = Items.CHOCOLATE_BOMB_2185
}
}
}
if(product == Items.CHOCOLATE_BOMB_2185){
val reqCream = Item(Items.POT_OF_CREAM_2130,2)
val reqChoc = Item(Items.CHOCOLATE_DUST_1975)
if(!player.inventory.containsItem(reqChoc) || !player.inventory.containsItem(reqCream)){
player.dialogueInterpreter.sendDialogue("You don't have enough ingredients to finish that.")
return true
}
player.inventory.remove(reqCream)
player.inventory.remove(reqChoc)
}
if(product == -1) return false
player.inventory.remove(used)
player.inventory.remove(with)
player.inventory.add(Item(product))
return true
}
}
@@ -0,0 +1,71 @@
package content.minigame.gnomecooking.bowls
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.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
@Initializable
class GnomeBowlInterface : ComponentPlugin() {
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
player ?: return false
component ?: return false
when(button){
3 -> attemptMake(PreparedProduct.HALF_MADE_WOR_HO,player)
12 -> attemptMake(PreparedProduct.HALF_MADE_VEG_BA,player)
21 -> attemptMake(PreparedProduct.HALF_MADE_TAN_TO,player)
34 -> attemptMake(PreparedProduct.HALF_MADE_CHOC_B,player)
}
return true
}
private fun attemptMake(bowl: PreparedProduct, player: Player){
if(!player.inventory.containsItem(Item(Items.GNOME_SPICE_2169)) && (bowl != PreparedProduct.HALF_MADE_CHOC_B) ){
player.dialogueInterpreter.sendDialogue("You need gnome spices for this.")
return
}
if(player.skills.getLevel(Skills.COOKING) < bowl.levelReq){
player.dialogueInterpreter.sendDialogue("You don't have the needed level to make this.")
return
}
var hasAll = true
for(item in bowl.requiredItems){
if(!player.inventory.containsItem(item)){
hasAll = false
break
}
}
if(!hasAll){
player.dialogueInterpreter.sendDialogue("You don't have all the ingredients needed for this.")
return
}
player.inventory.remove(*bowl.requiredItems)
player.inventory.remove(Item(Items.HALF_BAKED_BOWL_2177))
player.inventory.add(Item(bowl.product))
player.interfaceManager.close()
}
internal enum class PreparedProduct(val product: Int,val levelReq: Int, val requiredItems: Array<Item>){
HALF_MADE_CHOC_B(9558,42, arrayOf(Item(Items.CHOCOLATE_BAR_1973,4),Item(Items.EQUA_LEAVES_2128))),
HALF_MADE_TAN_TO(9559,40, arrayOf(Item(Items.TOADS_LEGS_2152,4),Item(Items.CHEESE_1985,2),Item(Items.DWELLBERRIES_2126),Item(Items.EQUA_LEAVES_2128,2))),
HALF_MADE_VEG_BA(9561,35, arrayOf(Item(Items.POTATO_1942,2),Item(Items.ONION_1957,2))),
HALF_MADE_WOR_HO(9563,30, arrayOf(Item(Items.KING_WORM_2162,4),Item(Items.ONION_1957,2)))
}
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.put(435,this)
return this
}
}
@@ -0,0 +1,25 @@
package content.minigame.gnomecooking.bowls
import core.cache.def.impl.ItemDefinition
import core.game.component.Component
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
@Initializable
class GnomeBowlPrepareHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ItemDefinition.forId(Items.HALF_BAKED_BOWL_2177).handlers["option:prepare"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
player.interfaceManager.open(Component(435))
return true
}
}
@@ -0,0 +1,31 @@
package content.minigame.gnomecooking.bowls
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
private const val GNOME_BOWL_MOLD = 2166
private const val GIANNE_DOUGH = 2171
@Initializable
class GnomebowlMouldFiller : UseWithHandler(GIANNE_DOUGH) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(GNOME_BOWL_MOLD, ITEM_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used.asItem()
val with = event.usedWith.asItem()
player.inventory.remove(used)
player.inventory.remove(with)
player.inventory.add(Item(Items.RAW_GNOMEBOWL_2178))
return true
}
}
@@ -0,0 +1,61 @@
package content.minigame.gnomecooking.cocktails
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
private const val UNCOOKED_CHOC_SAT = 9572
private const val UNCOOKED_DRUN_DRA = 9576
/**
* Handles the cooking of certain cocktail products
* @author Ceikry
*/
@Initializable
class CocktailCooker : UseWithHandler(UNCOOKED_CHOC_SAT, UNCOOKED_DRUN_DRA) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(17131, OBJECT_TYPE,this)
addHandler(2728, OBJECT_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
when(event?.used?.id){
UNCOOKED_CHOC_SAT -> cook(CookedDrinks.COOKED_CHOC_SAT,event.player,event.usedItem)
UNCOOKED_DRUN_DRA -> cook(CookedDrinks.COOKED_DRUN_DRA,event.player,event.usedItem)
}
return true
}
private fun cook(drink: CookedDrinks, player: Player, raw: Item){
GameWorld.Pulser.submit(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.lock().also { player.animator.animate(Animation(883)) }
2 -> {
if(player.inventory.containsItem(raw)) {
player.inventory.remove(raw)
player.inventory.add(Item(drink.product))
}
player.unlock()
return true
}
}
return false
}
})
}
internal enum class CookedDrinks(val product: Int){
COOKED_CHOC_SAT(9573),
COOKED_DRUN_DRA(2092)
}
}
@@ -0,0 +1,61 @@
package content.minigame.gnomecooking.cocktails
import core.cache.def.impl.ItemDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
private const val UNF_CHOC_SAT = 9573
private const val UNF_DRUN_DRA = 9575
/**
* Handles adding the final ingredients to a couple cocktails
* @author Ceikry
*/
@Initializable
class CocktailFinisher : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ItemDefinition.forId(UNF_CHOC_SAT).handlers["option:add-ingreds"] = this
ItemDefinition.forId(UNF_DRUN_DRA).handlers["option:add-ingreds"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
when(node.id){
UNF_CHOC_SAT -> attemptMake(FinishedDrinks.FIN_CHOC_SAT,player,node)
UNF_DRUN_DRA -> attemptMake(FinishedDrinks.FIN_DRUN_DRA,player,node)
}
return true
}
private fun attemptMake(drink: FinishedDrinks, player: Player, node: Node){
var hasAll = true
for(item in drink.requiredItems){
if(!player.inventory.containsItem(item)){
hasAll = false
break
}
}
if(!hasAll){
player.dialogueInterpreter.sendDialogue("You don't have the ingredients for this.")
return
}
player.inventory.remove(*drink.requiredItems)
player.inventory.remove(node.asItem())
player.inventory.add(Item(drink.product))
}
internal enum class FinishedDrinks(val product: Int, val requiredItems: Array<Item>){
FIN_CHOC_SAT(2074, arrayOf(Item(Items.CHOCOLATE_DUST_1975),Item(Items.POT_OF_CREAM_2130))),
FIN_DRUN_DRA(9576, arrayOf(Item(Items.PINEAPPLE_CHUNKS_2116),Item(Items.POT_OF_CREAM_2130)))
}
}
@@ -0,0 +1,29 @@
package content.minigame.gnomecooking.cocktails
import core.cache.def.impl.ItemDefinition
import core.game.component.Component
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.plugin.Plugin
/**
* Handles the mix-cocktail option for the cocktail shaker
* @author Ceikry
*/
@Initializable
class CocktailShakerHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ItemDefinition.forId(2025).handlers["option:mix-cocktail"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
player.interfaceManager.open(Component(436)) //Gnome cocktail interface
return true
}
}
@@ -0,0 +1,98 @@
package content.minigame.gnomecooking.cocktails
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.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
private const val WIZARD_BLIZZARD = 2054
private const val SHORT_GREEN_GUY = 2080
private const val FRUIT_BLAST = 2084
private const val PINEAPPLE_PUNCH = 2048
private const val DRUNK_DRAGON = 2092
private const val CHOC_SATURDAY = 2074
private const val BLURBERRY_SPECIAL = 2064
/**
* Handles the gnome cocktail interface
* @author Ceikry
*/
@Initializable
class GnomeCocktailInterface : ComponentPlugin() {
override fun open(player: Player?, component: Component?) {
player ?: return
component ?: return
super.open(player, component)
player.packetDispatch.sendItemOnInterface(WIZARD_BLIZZARD,1,component.id,3)
player.packetDispatch.sendItemOnInterface(SHORT_GREEN_GUY,1,component.id,16)
player.packetDispatch.sendItemOnInterface(FRUIT_BLAST,1,component.id,23)
player.packetDispatch.sendItemOnInterface(PINEAPPLE_PUNCH,1,component.id,32)
player.packetDispatch.sendItemOnInterface(DRUNK_DRAGON,1,component.id,41)
player.packetDispatch.sendItemOnInterface(CHOC_SATURDAY,1,component.id,50)
player.packetDispatch.sendItemOnInterface(BLURBERRY_SPECIAL,1,component.id,61)
}
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
player ?: return false
when(button){
3 -> attemptMake(FruitCocktail.WIZARD_BLIZZARD,player)
16 -> attemptMake(FruitCocktail.SHORT_GREEN_GUY, player)
23 -> attemptMake(FruitCocktail.FRUIT_BLAST, player)
32 -> attemptMake(FruitCocktail.PINEAPPLE_PUNCH,player)
41 -> attemptMake(FruitCocktail.DRUNK_DRAGON,player)
50 -> attemptMake(FruitCocktail.CHOC_SATURDAY,player)
61 -> attemptMake(FruitCocktail.BLURBERRY_SPEC,player)
}
return true
}
private fun attemptMake(cocktail: FruitCocktail, player: Player){
var hasAll = true
val cookingLevel = player.skills.getLevel(Skills.COOKING)
if(cookingLevel < cocktail.levelReq){
player.dialogueInterpreter.sendDialogue("You don't have the necessary level to make that.")
return
}
for(ingredient in cocktail.requiredItems){
if(!player.inventory.containsItem(ingredient)){
hasAll = false
break
}
}
if(!hasAll){
player.dialogueInterpreter.sendDialogue("You don't have the ingredients to make that.")
return
}
player.inventory.remove(*cocktail.requiredItems)
player.inventory.remove(Item(Items.COCKTAIL_SHAKER_2025))
player.inventory.add(Item(cocktail.product))
player.skills.addExperience(Skills.COOKING,cocktail.experience)
player.interfaceManager.close()
}
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.put(436,this)
return this
}
internal enum class FruitCocktail(val levelReq: Int, val experience: Double, val product: Int, val requiredItems: Array<Item>){
FRUIT_BLAST(6,50.0,9568, arrayOf(Item(Items.PINEAPPLE_2114),Item(Items.LEMON_2102),Item(Items.ORANGE_2108))),
PINEAPPLE_PUNCH(8,70.0,9569, arrayOf(Item(Items.PINEAPPLE_2114,2),Item(Items.LEMON_2102),Item(Items.ORANGE_2108))),
WIZARD_BLIZZARD(18,110.0, 9566, arrayOf(Item(Items.VODKA_2015,2),Item(Items.GIN_2019),Item(Items.LIME_2120),Item(Items.LEMON_2102),Item(Items.ORANGE_2108))),
SHORT_GREEN_GUY(20,120.0,9567, arrayOf(Item(Items.VODKA_2015),Item(Items.LIME_2120,3))),
DRUNK_DRAGON(32,160.0,9574, arrayOf(Item(Items.VODKA_2015),Item(Items.GIN_2019),Item(Items.DWELLBERRIES_2126))),
CHOC_SATURDAY(33,170.0,9571, arrayOf(Item(Items.WHISKY_2017),Item(Items.CHOCOLATE_BAR_1973),Item(Items.EQUA_LEAVES_2128),Item(Items.BUCKET_OF_MILK_1927))),
BLURBERRY_SPEC(37,180.0,9570, arrayOf(Item(Items.VODKA_2015),Item(Items.BRANDY_2021),Item(Items.GIN_2019),Item(Items.LEMON_2102,2),Item(Items.ORANGE_2108)))
}
}
@@ -0,0 +1,86 @@
package content.minigame.gnomecooking.cocktails
import core.cache.def.impl.ItemDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
private const val WIZ_BLIZ_MIX = 9566
private const val SGG_MIX = 9567
private const val F_BLAST_MIX = 9568
private const val P_PUNCH_MIX = 9569
private const val BLU_SPEC_MIX = 9570
private const val CHOC_SAT_MIX = 9571
private const val DRUNK_DRAG_MIX = 9574
private val mixers = arrayOf(WIZ_BLIZ_MIX, SGG_MIX, F_BLAST_MIX, P_PUNCH_MIX, BLU_SPEC_MIX, CHOC_SAT_MIX, DRUNK_DRAG_MIX)
/**
* Handles the pouring of mixed drinks into cocktail glasses
* @author Ceikry
*/
@Initializable
class PourMixerPlugin : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
for(mixer in mixers){
ItemDefinition.forId(mixer).handlers["option:pour"] = this
}
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
when(node.id){
WIZ_BLIZ_MIX -> attemptMake(PouredDrink.WIZ_BLIZZ,player,node)
SGG_MIX -> attemptMake(PouredDrink.SHORT_G_G,player,node)
F_BLAST_MIX -> attemptMake(PouredDrink.FRUIT_BLAST,player,node)
P_PUNCH_MIX -> attemptMake(PouredDrink.PINE_PUNCH,player,node)
BLU_SPEC_MIX -> attemptMake(PouredDrink.BLUR_SPEC, player,node)
CHOC_SAT_MIX -> attemptMake(PouredDrink.CHOC_SAT,player,node)
DRUNK_DRAG_MIX -> attemptMake(PouredDrink.DRUNK_DRAG,player,node)
}
return true
}
private fun attemptMake(drink: PouredDrink, player: Player, node: Node){
if(!player.inventory.containsItem(Item(Items.COCKTAIL_GLASS_2026))){
player.dialogueInterpreter.sendDialogue("You need a glass to pour this into.")
return
}
var hasAll = true
for(ingredient in drink.requiredItems){
if(!player.inventory.containsItem(ingredient)){
hasAll = false
}
}
if(!hasAll){
player.dialogueInterpreter.sendDialogue("You don't have the garnishes for this.")
return
}
player.inventory.remove(*drink.requiredItems)
player.inventory.remove(node.asItem())
player.inventory.remove(Item(Items.COCKTAIL_GLASS_2026))
player.inventory.add(Item(drink.product))
player.inventory.add(Item(Items.COCKTAIL_SHAKER_2025))
player.skills.addExperience(Skills.COOKING,50.0)
}
internal enum class PouredDrink(val product: Int, val requiredItems: Array<Item>){
FRUIT_BLAST(9514, arrayOf(Item(Items.LEMON_SLICES_2106))),
PINE_PUNCH(9512, arrayOf(Item(Items.LIME_CHUNKS_2122),Item(Items.PINEAPPLE_CHUNKS_2116),Item(Items.ORANGE_SLICES_2112))),
WIZ_BLIZZ(9508, arrayOf(Item(Items.PINEAPPLE_CHUNKS_2116),Item(Items.LIME_SLICES_2124))),
SHORT_G_G(9510, arrayOf(Item(Items.LIME_SLICES_2124),Item(Items.EQUA_LEAVES_2128))),
DRUNK_DRAG(9575, arrayOf()),
CHOC_SAT(9572, arrayOf()),
BLUR_SPEC(9520, arrayOf(Item(Items.LEMON_CHUNKS_2104),Item(Items.ORANGE_CHUNKS_2110),Item(Items.EQUA_LEAVES_2128),Item(Items.LIME_SLICES_2124))),
}
}
@@ -0,0 +1,71 @@
package content.minigame.gnomecooking.crunchies
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import core.game.node.entity.skill.Skills
private const val UNFINISHED_CRUNCHY_CHOC = 9578
private const val UNFINISHED_CRUNCHY_SPICY = 9580
private const val UNFINISHED_CRUNCHY_TOAD = 9582
private const val UNFINISHED_CRUNCHY_WORM = 9584
/**
* handles cooking gnome crunchies, don't wanna use standard
* cooking stuff because no experience and no burn chance
* @author Ceikry
*/
@Initializable
class GnomeCrunchyCooker : UseWithHandler(9577,9579,9581,9583, 2202){
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(17131, OBJECT_TYPE,this)
addHandler(2728, OBJECT_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val used = event.used.asItem()
val with = event.usedWith
val player = event.player
when(used.id){
9577 -> cook(UNFINISHED_CRUNCHY_CHOC,used,player)
9579 -> cook(UNFINISHED_CRUNCHY_SPICY,used,player)
9581 -> cook(UNFINISHED_CRUNCHY_TOAD,used,player)
9583 -> cook(UNFINISHED_CRUNCHY_WORM,used,player)
2202 -> cook(2201,used,player)
}
return true
}
private fun cook(product: Int, raw: Item, player: Player){
GameWorld.Pulser.submit(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.lock().also { player.animator.animate(Animation(883)) }
2 -> {
if(player.inventory.containsItem(raw)) {
player.inventory.remove(raw)
player.inventory.add(Item(product))
if(raw.id != 2202) player.inventory.add(Item(2165))
}
if(raw.id == 2202){
player.skills.addExperience(Skills.COOKING,30.0)
}
player.unlock()
return true
}
}
return false
}
})
}
}
@@ -0,0 +1,67 @@
package content.minigame.gnomecooking.crunchies
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
/**
* Handles garnishing gnome crunchies
* @author Ceikry
*/
@Initializable
class GnomeCrunchyGarnisher : UseWithHandler(9578,9580,9582,9584) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(Items.CHOCOLATE_DUST_1975, ITEM_TYPE,this)
addHandler(Items.GNOME_SPICE_2169, ITEM_TYPE, this)
addHandler(Items.EQUA_LEAVES_2128, ITEM_TYPE, this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used.asItem()
val with = event.usedWith.asItem()
val product = when(with.id){
Items.CHOCOLATE_DUST_1975 -> {
when(used.id){
9578 -> Items.CHOCCHIP_CRUNCHIES_2209
else -> -1
}
}
Items.GNOME_SPICE_2169 -> {
when(used.id){
9584 -> Items.WORM_CRUNCHIES_2205
9580 -> Items.SPICY_CRUNCHIES_2213
else -> -1
}
}
Items.EQUA_LEAVES_2128 -> {
when(used.id){
9582 -> Items.TOAD_CRUNCHIES_2217
else -> -1
}
}
else -> -1
}
if(product == -1) return false
player.inventory.remove(used)
if(with.id != Items.GNOME_SPICE_2169)
player.inventory.remove(with)
player.inventory.add(Item(product))
player.skills.addExperience(Skills.COOKING,64.0)
return true
}
}
@@ -0,0 +1,91 @@
package content.minigame.gnomecooking.crunchies
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.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
private const val TOAD_CRUNCHIES = 9538
private const val SPICE_CRUNCHIES = 9540
private const val CHOC_CHIP_CRUNCHIES = 9544
private const val WORM_CRUNCHIES = 9542
private const val HALF_BAKED_CRUNCHY = 2201
/**
* Handles the gnome crunchy interface
* @author Ceikry
*/
@Initializable
class GnomeCrunchyInterface : ComponentPlugin() {
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
player ?: return false
when(button){
3 -> attemptMake(HalfMadeCrunchy.TOAD,player)
10 -> attemptMake(HalfMadeCrunchy.SPICY,player)
17 -> attemptMake(HalfMadeCrunchy.WORM,player)
26 -> attemptMake(HalfMadeCrunchy.CHOCCHIP,player)
}
return true
}
private fun attemptMake(crunchy: HalfMadeCrunchy, player: Player){
var hasAll = true
if(player.skills.getLevel(Skills.COOKING) < crunchy.reqLevel){
player.dialogueInterpreter.sendDialogue("You don't have the required level to make these.")
return
}
if(!player.inventory.containsItem(Item(Items.GNOME_SPICE_2169))){
player.dialogueInterpreter.sendDialogue("You need some gnome spice to make these.")
return
}
for(item in crunchy.requiredItems){
if(!player.inventory.containsItem(item)){
hasAll = false
break;
}
}
if(!hasAll){
player.dialogueInterpreter.sendDialogue("You don't have the required ingredients to make these.")
return
}
player.inventory.remove(*crunchy.requiredItems)
player.inventory.remove(Item(HALF_BAKED_CRUNCHY))
player.inventory.add(Item(crunchy.product))
player.skills.addExperience(Skills.COOKING,30.0)
player.interfaceManager.close()
}
override fun open(player: Player?, component: Component?) {
player ?: return
component ?: return
super.open(player, component)
player.packetDispatch.sendItemOnInterface(TOAD_CRUNCHIES,1,component.id,3)
player.packetDispatch.sendItemOnInterface(SPICE_CRUNCHIES,1,component.id,10)
player.packetDispatch.sendItemOnInterface(WORM_CRUNCHIES,1,component.id,17)
player.packetDispatch.sendItemOnInterface(CHOC_CHIP_CRUNCHIES,1,component.id,26)
}
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.put(437,this)
return this
}
internal enum class HalfMadeCrunchy(val product: Int,val reqLevel: Int, val requiredItems: Array<Item>){
CHOCCHIP(9577, 16, arrayOf(Item(Items.CHOCOLATE_BAR_1973,2))),
SPICY(9579, 12, arrayOf(Item(Items.EQUA_LEAVES_2128,2))),
TOAD(9581, 10, arrayOf(Item(Items.TOADS_LEGS_2152,2))),
WORM(9583, 14, arrayOf(Item(Items.EQUA_LEAVES_2128),Item(Items.KING_WORM_2162,2)))
}
}
@@ -0,0 +1,29 @@
package content.minigame.gnomecooking.crunchies
import core.cache.def.impl.ItemDefinition
import core.game.component.Component
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.plugin.Plugin
private const val HALF_BAKED_CRUNCHY = 2201
private const val CRUNCHY_INTERFACE = 437
/**
* Opens the gnome crunchy interface
*/
@Initializable
class GnomeCrunchyPrepareHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ItemDefinition.forId(HALF_BAKED_CRUNCHY).handlers["option:prepare"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
player.interfaceManager.open(Component(CRUNCHY_INTERFACE))
return true
}
}
@@ -0,0 +1,32 @@
package content.minigame.gnomecooking.crunchies
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
private const val GIANNE_DOUGH = 2171
private const val CRUNCHY_TRAY = 2165
private const val RAW_CRUNCHIES = 2202
/**
* Handles adding GIANNE_DOUGH to CRUNCHY_TRAY to produce RAW_CRUNCHIES
* @author Ceikry
*/
@Initializable
class GnomeCrunchyTrayFiller : UseWithHandler(GIANNE_DOUGH) {
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(CRUNCHY_TRAY, ITEM_TYPE,this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
event.player.inventory.remove(event.used.asItem())
event.player.inventory.remove(event.usedWith.asItem())
event.player.inventory.add(Item(RAW_CRUNCHIES))
return true
}
}
@@ -0,0 +1,138 @@
package content.minigame.magearena;
import core.game.dialogue.DialoguePlugin;
import content.data.GodType;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
/**
* Handles the chamber guardian dialogue.
* @author Vexia
*/
public final class ChamberGuardianDialogue extends DialoguePlugin {
/**
* The god type.
*/
private GodType godType;
/**
* Constructs a new {@code ChamberGuardianDialogue} {@code Object}.
*/
public ChamberGuardianDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code ChamberGuardianDialogue} {@code Object}.
* @param player the player.
*/
public ChamberGuardianDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ChamberGuardianDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
if (player.getSavedData().getActivityData().hasRecievedKolodionReward()) {
player("Hello again.");
return true;
} else if (player.getSavedData().getActivityData().hasKilledKolodion()) {
npc("Hello adventurer, have you made your choice?");
return true;
}
npc("YOU SHOULD NOT BE IN HERE!");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
if (player.getSavedData().getActivityData().hasRecievedKolodionReward()) {
switch (stage) {
case 0:
npc("Hello adventurer, are you looking for another staff?");
stage++;
break;
case 1:
options("What do you have to offer?", "No thanks.");
stage++;
break;
case 2:
switch (buttonId) {
case 1:
end();
npc.openShop(player);
break;
case 2:
player("No thanks.");
stage++;
break;
}
break;
case 3:
npc("Well let me know if you need one.");
stage++;
break;
case 4:
end();
break;
}
return true;
} else if (player.getSavedData().getActivityData().hasKilledKolodion()) {
switch (stage) {
case 0:
godType = GodType.getCape(player);
if (godType == null) {
player("Sorry, I'm still looking.");
stage++;
} else {
player("I have.");
stage += 2;
}
break;
case 1:
end();
break;
case 2:
npc("Good, good, I hope you have chosen well. I will now", "present you with a magic staff. This, along with the", "cape awarded to you by your chosen god, are all the", "weapons and armour you will need here.");
stage++;
break;
case 3:
if (!player.getInventory().hasSpaceFor(godType.getStaff())) {
player("Sorry, I don't have enough inventory space.");
stage = 1;
return true;
}
if (player.getInventory().containsItem(godType.getCape()) || player.getEquipment().containsItem(godType.getCape())) {
stage++;
player.getInventory().add(godType.getStaff());
player.getSavedData().getActivityData().setKolodionStage(3);
interpreter.sendItemMessage(godType.getStaff(), "The guardian hands you an ornate magic staff.");
} else {
end();
}
break;
case 4:
end();
break;
}
return true;
} else {
end();
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 904 };
}
}
@@ -0,0 +1,253 @@
package content.minigame.magearena;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
/**
* Handles the kolodion dialogue.
* @author Vexia
*/
public final class KolodionDialogue extends DialoguePlugin {
/**
* Constructs a new {@code KolodionDialogue} {@code Object}.
*/
public KolodionDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code KolodionDialogue} {@code Object}.
* @param player the player.
*/
public KolodionDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new KolodionDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
if (player.getSavedData().getActivityData().hasStartedKolodion()) {
player("Hi.");
return true;
}
if (player.getSavedData().getActivityData().hasKilledKolodion()) {
player("Hello, Kolodion.");
return true;
}
player("Hello there. What is this place?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
if (player.getSavedData().getActivityData().hasStartedKolodion()) {
switch (stage) {
case 0:
npc("You return, young conjurer. You obviously have a", "taste for the dark side of magic.");
stage++;
break;
case 1:
startFight(player);
end();
break;
}
return true;
}
if (player.getSavedData().getActivityData().hasRecievedKolodionReward()) {
switch (stage) {
case 0:
npc("Hey there, how are you? Are you enjoying the", "bloodshed?");
stage++;
break;
case 1:
player("I think I've had enough for now.");
stage++;
break;
case 2:
npc("A shame. You're a good battle mage. I hope", "to see you soon.");
stage++;
break;
case 3:
end();
break;
}
return true;
} else if (player.getSavedData().getActivityData().hasKilledKolodion()) {
switch (stage) {
case 0:
npc("Hello, you mage. You're a tough one.");
stage++;
break;
case 1:
player("What now?");
stage++;
break;
case 2:
npc("Step into the magic pool. It will take you to a chamber.", "There, you must decide which god you will represent in", "the arena.");
stage++;
break;
case 3:
player("Thanks, Kolodion.");
stage++;
break;
case 4:
npc("That's what I'm here for.");
stage++;
break;
case 5:
end();
break;
}
return true;
}
switch (stage) {
case 0:
if (player.getSkills().getStaticLevel(Skills.MAGIC) < 60) {
npc("Do not waste my time with trivial questions. I am the", "Great Kolodion, master of battle magic. I have an arena", "to run.");
stage++;
} else {
npc("I am the great Kolodion, master of battle magic, and", "this is my battle arena. Top wizards travel from all over", GameWorld.getSettings().getName() + " to fight here.");
stage = 4;
}
break;
case 1:
player("Can I enter?");
stage++;
break;
case 2:
npc("Hah! A wizard of your level? Don't be absurd.");
stage++;
break;
case 3:
end();
break;
case 4:
options("Can I fight here?", "What's the point of that?", "That's barbaric!");
stage++;
break;
case 5:
switch (buttonId) {
case 1:
player("Can I fight here?");
stage = 10;
break;
case 2:
player("What's the point of that?");
stage = 20;
break;
case 3:
player("That's barbaric!");
stage = 30;
break;
}
break;
case 10:
npc("My arena is open to any high level wizard, but this is", "no game. Many wizards fall in this arena, never to rise", "again. The strongest mages have been destroyed.");
stage++;
break;
case 11:
npc("If you're sure you want in?");
stage++;
break;
case 12:
options("Yes indeedy.", "No I don't.");
stage++;
break;
case 13:
switch (buttonId) {
case 1:
player("Yes indeedy.");
stage++;
break;
case 2:
end();
break;
}
break;
case 14:
npc("Good, good. You have a healthy sense of competition.");
stage++;
break;
case 15:
npc("Remember, traveller - in my arena, hand-to-hand", "combat is useless. Your strength will diminish as you", "enter the arena, but the spells you can learn are", "amongst the most powerful in all of " + GameWorld.getSettings().getName() + ".");
stage++;
break;
case 16:
npc("Before I can accept you in, we must duel.");
stage++;
break;
case 17:
options("Okay, let's fight.", "No thanks.");
stage++;
break;
case 18:
switch (buttonId) {
case 1:
player("Okay, let's fight.");
stage++;
break;
case 2:
end();
break;
}
break;
case 19:
npc("I must first check that you are up to scratch.");
stage = 40;
break;
case 40:
player("You don't need to worry about that.");
stage++;
break;
case 41:
npc("Not just any magician can enter - only the most", "powerful and most feared. Before you can use the", "power of this arena, you must prove yourself against", "me.");
stage++;
break;
case 42:
startFight(player);
end();
break;
case 20:
npc("They want to crown themselves the best", "mage in all of " + GameWorld.getSettings().getName() + "!");
stage = 30;
break;
case 30:
end();
break;
}
return true;
}
/**
* Starts the fight.
* @param player the player.
*/
private void startFight(final Player player) {
player.getSavedData().getActivityData().setKolodionStage(1);
player.lock();
npc.animate(Animation.create(811));
player.teleport(Location.create(3105, 3934, 0), 3);
player.visualize(Animation.create(1816), Graphics.create(301, 100));
KolodionSession.create(player).start();
}
@Override
public int[] getIds() {
return new int[] { 905 };
}
}
@@ -0,0 +1,374 @@
package content.minigame.magearena;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.BattleState;
import core.game.node.entity.combat.spell.CombatSpell;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.npc.AbstractNPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.system.task.Pulse;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.tools.RandomFunction;
import core.game.node.entity.combat.CombatSwingHandler;
import core.game.node.entity.combat.MagicSwingHandler;
import core.game.world.GameWorld;
/**
* Handles the kolodion npc.
* @author Vexia
*/
public final class KolodionNPC extends AbstractNPC {
/**
* The combat swing handler.
*/
private static final CombatSwingHandler SWING_HANDLER = new MagicSwingHandler() {
@Override
public void impact(Entity entity, Entity victim, BattleState state) {
super.impact(entity, victim, state);
if (RandomFunction.random(10) < 4) {
((KolodionNPC) entity).setRandomSpell();
}
}
};
/**
* The spell ids.
*/
private static final int[] SPELL_IDS = new int[] { 41, 42, 43 };
/**
* The session.
*/
private final KolodionSession session;
/**
* The kolodion type.
*/
private KolodionType type;
/**
* If the fight has commenced.
*/
private boolean commenced;
/**
* Constructs a new {@code KolodionNPC} {@code Object}.
*/
public KolodionNPC() {
this(0, null, null);
}
/**
* Constructs a new {@code KolodionNPC} {@code Object}.
* @param id the id.
* @param location the location.
*/
public KolodionNPC(int id, Location location, final KolodionSession session) {
super(id, location);
this.setWalks(true);
this.session = session;
this.setRespawn(false);
this.type = KolodionType.forId(id);
}
@Override
public void init() {
super.init();
setRandomSpell();
}
@Override
public void handleTickActions() {
super.handleTickActions();
if (session == null) {
return;
}
if (!session.getPlayer().isActive()) {
clear();
return;
}
if (commenced && !getProperties().getCombatPulse().isAttacking()) {
getProperties().getCombatPulse().attack(session.getPlayer());
}
}
@Override
public void startDeath(Entity killer) {
if (killer == session.getPlayer()) {
type.transform(this, session.getPlayer());
return;
}
super.startDeath(killer);
}
/**
* Sets a random spell.
*/
public void setRandomSpell() {
CombatSpell spell = (CombatSpell) SpellBook.MODERN.getSpell(SPELL_IDS[RandomFunction.random(SPELL_IDS.length)]);
getProperties().setSpell(spell);
getProperties().setAutocastSpell(spell);
}
@Override
public CombatSwingHandler getSwingHandler(boolean swing) {
return SWING_HANDLER;
}
@Override
public AbstractNPC construct(int id, Location location, Object... objects) {
return new KolodionNPC(id, location, null);
}
@Override
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
if (style != CombatStyle.MAGIC) {
return false;
}
if (session == null) {
return false;
}
if (session.getPlayer() != entity) {
return false;
}
return true;
}
@Override
public boolean canSelectTarget(Entity target) {
if (target instanceof Player) {
Player p = (Player) target;
if (p != session.getPlayer()) {
return false;
}
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 907, 908, 909, 910, 911 };
}
/**
* Gets the session.
* @return The session.
*/
public KolodionSession getSession() {
return session;
}
/**
* Gets the commenced.
* @return The commenced.
*/
public boolean isCommenced() {
return commenced;
}
/**
* Sets the commenced.
* @param commenced The commenced to set.
*/
public void setCommenced(boolean commenced) {
this.commenced = commenced;
}
/**
* Gets the type.
* @return The type.
*/
public KolodionType getType() {
return type;
}
/**
* Sets the type.
* @param type The type to set.
*/
public void setType(KolodionType type) {
this.type = type;
}
/**
* Represents a kolodion type.
* @author Vexia
*/
public enum KolodionType {
HUMAN(907, null, -1, "You must prove yourself... now!"), OGRE(908, null, 188, "This is only the beginning; you can't beat me!"), SPIDER(909, new Animation(5324), 190, "Foolish mortal; I am unstoppable."), GHOST(910, new Animation(715), 188, "Now you feel it.. The dark energy."), DEMON(911, new Animation(4623), 190, "Aaaaaaaarrgghhhh! The power!"), END(906, null, 188, null);
/**
* The npc id.
*/
private final int npcId;
/**
* The appear animation.
*/
private final Animation appearAnimation;
/**
* The graphic id.
*/
private final int graphcId;
/**
* The appeared message.
*/
private final String appearMessage;
/**
* The spell ids.
*/
private final int[] spellIds;
/**
* Constructs a new {@code KolodionType} {@code Object}.
* @param npcId the npc id.
* @param appearMessage the message.
*/
private KolodionType(int npcId, final Animation appearAnimation, final int graphicId, String appearMessage, int... spellIds) {
this.npcId = npcId;
this.appearMessage = appearMessage;
this.appearAnimation = appearAnimation;
this.graphcId = graphicId;
this.spellIds = spellIds;
}
/**
* Transforms the new npc.
*/
public void transform(final KolodionNPC kolodion, final Player player) {
final KolodionType newType = next();
kolodion.lock();
kolodion.getPulseManager().clear();
kolodion.getWalkingQueue().reset();
kolodion.getImpactHandler().setDisabledTicks(50);
player.getSavedData().getActivityData().setKolodionBoss(newType.ordinal());
if (newType == END) {
player.lock();
}
player.lock(2);
GameWorld.getPulser().submit(new Pulse(1, kolodion, player) {
int counter;
@Override
public boolean pulse() {
switch (++counter) {
case 1:
if (newType != GHOST) {
kolodion.getAnimator().forceAnimation(kolodion.getProperties().getDeathAnimation());
}
break;
case 3:
if (newType == GHOST) {
kolodion.getAnimator().forceAnimation(kolodion.getProperties().getDeathAnimation());
}
break;
case 4:
player.getPacketDispatch().sendPositionedGraphic(newType.getGraphcId(), 0, 0, kolodion.getLocation());
if (newType.getAppearAnimation() != null) {
kolodion.animate(newType.getAppearAnimation());
}
break;
case 5:
kolodion.unlock();
kolodion.getAnimator().reset();
kolodion.fullRestore();
kolodion.setType(newType);
kolodion.transform(newType.getNpcId());
kolodion.getImpactHandler().setDisabledTicks(1);
if (newType != END) {
kolodion.getProperties().getCombatPulse().attack(player);
}
break;
case 6:
if (newType.getAppearMessage() != null) {
kolodion.sendChat(newType.getAppearMessage());
}
if (newType == END) {
return false;
}
return true;
case 7:
player.unlock();
player.getSavedData().getActivityData().setKolodionStage(2);
player.getProperties().setTeleportLocation(Location.create(2540, 4717, 0));
return true;
}
return false;
}
});
}
/**
* Gets the kolodion type for the id.
* @param id the id.
* @return the kolodion type.
*/
public static KolodionType forId(int id) {
for (KolodionType type : values()) {
if (type.getNpcId() == id) {
return type;
}
}
return null;
}
/**
* Gets the next type.
* @return the type.
*/
public KolodionType next() {
return values()[ordinal() + 1];
}
/**
* Gets the npcId.
* @return The npcId.
*/
public int getNpcId() {
return npcId;
}
/**
* Gets the appearMessage.
* @return The appearMessage.
*/
public String getAppearMessage() {
return appearMessage;
}
/**
* Gets the spellIds.
* @return The spellIds.
*/
public int[] getSpellIds() {
return spellIds;
}
/**
* Gets the appearAnimation.
* @return The appearAnimation.
*/
public Animation getAppearAnimation() {
return appearAnimation;
}
/**
* Gets the graphcId.
* @return The graphcId.
*/
public int getGraphcId() {
return graphcId;
}
}
}
@@ -0,0 +1,120 @@
package content.minigame.magearena;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
/**
* Represents a session with kolodion.
* @author Vexia
*/
public final class KolodionSession {
/**
* The player.
*/
private final Player player;
/**
* The kolodion npc.
*/
private final KolodionNPC kolodion;
/**
* Constructs a new {@code ExperimentSession} {@code Object}.
* @param player the player.
*/
public KolodionSession(final Player player) {
this.player = player;
this.kolodion = new KolodionNPC(KolodionNPC.KolodionType.values()[player.getSavedData().getActivityData().getKolodionBoss()].getNpcId(), Location.create(3106, 3934, 0), this);
if (player.getExtension(KolodionSession.class) != null) {
player.removeExtension(KolodionSession.class);
}
player.addExtension(KolodionSession.class, this);
}
/**
* Creates the kolodion session.
* @param player the player.
* @return the session.
*/
public static KolodionSession create(Player player) {
return new KolodionSession(player);
}
/**
* Starts the session.
*/
public void start() {
if (kolodion.getType().ordinal() > 0) {
kolodion.init();
kolodion.sendChat("Let us continue with our battle.");
kolodion.getProperties().getCombatPulse().attack(player);
player.unlock();
player.getAnimator().reset();
return;
}
GameWorld.getPulser().submit(new Pulse(1, player) {
int count;
@Override
public boolean pulse() {
switch (++count) {
case 3:
player.getAnimator().reset();
break;
case 5:
player.getPacketDispatch().sendPositionedGraphic(86, 1, 0, Location.create(3106, 3934, 0));
break;
case 6:
kolodion.init();
kolodion.faceTemporary(player, 1);
break;
case 7:
kolodion.sendChat("You must prove yourself... now!");
break;
case 9:
player.unlock();
kolodion.setCommenced(true);
return true;
}
return false;
}
});
}
/**
* Closes the session.
*/
public void close() {
kolodion.clear();
player.removeExtension(KolodionSession.class);
}
/**
* Gets the kolodion session.
* @param player the player.
* @return the session.
*/
public static KolodionSession getSession(Player player) {
return player.getExtension(KolodionSession.class);
}
/**
* Gets the player.
* @return The player.
*/
public Player getPlayer() {
return player;
}
/**
* Gets the kolodion.
* @return The kolodion.
*/
public NPC getKolodion() {
return kolodion;
}
}
@@ -0,0 +1,103 @@
package content.minigame.magearena;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
/**
* Handles the lundail dialogue.
* @author Vexia
*/
public final class LundailDialogue extends DialoguePlugin {
/**
* Constructs a new {@code LundailDialogue} {@code Object}.
*/
public LundailDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code LundailDialogue} {@code Object}.
* @param player the player.
*/
public LundailDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new LundailDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
npc("Hello sir.");
stage = 1;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 1:
npc("How can I help you, brave adventurer?");
stage++;
break;
case 2:
options("What are you selling?", "What's that big old building above us?");
stage++;
break;
case 3:
switch (buttonId) {
case 1:
player("What are you selling?");
stage = 10;
break;
case 2:
player("What's that big old building above us?");
stage = 20;
break;
}
break;
case 10:
npc("I sell rune stones. I've got some good stuff, some really", "powerful little rocks. Take a look.");
stage++;
break;
case 11:
npc.openShop(player);
end();
break;
case 20:
npc("That, my friend is the mage battle arena. Top mages", "come from all over " + GameWorld.getSettings().getName() + " to compete in the arena.");
stage++;
break;
case 21:
player("Wow.");
stage++;
break;
case 22:
npc("Few return, most get fried, hence the smell.");
stage++;
break;
case 23:
player("Hmmm... I did notice.");
stage++;
break;
case 24:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 903 };
}
}
@@ -0,0 +1,104 @@
package content.minigame.magearena;
import content.data.GodType;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.spell.CombatSpell;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.npc.AbstractNPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.world.map.Location;
import core.tools.RandomFunction;
/**
* A mage arena npc.
* @author Vexia
*/
public final class MageArenaNPC extends AbstractNPC {
/**
* The god type.
*/
private final GodType type;
/**
* Constructs a new {@code MageArenaNPC} {@code Object}.
*/
public MageArenaNPC() {
super(0, null);
this.type = null;
}
/**
* Constructs a new {@code MageArenaNPC} {@code Object}.
* @param id the id.
* @param location the location.
*/
public MageArenaNPC(int id, Location location) {
super(id, location);
this.setWalks(true);
this.type = GodType.forId(id);
}
@Override
public AbstractNPC construct(int id, Location location, Object... objects) {
return new MageArenaNPC(id, location);
}
@Override
public void init() {
super.init();
CombatSpell spell = (CombatSpell) SpellBook.MODERN.getSpell(41 + type.ordinal());
getProperties().setSpell(spell);
getProperties().setAutocastSpell(spell);
getProperties().getCombatPulse().setStyle(CombatStyle.MAGIC);
}
@Override
public void handleTickActions() {
super.handleTickActions();
if (getProperties().getCombatPulse().isAttacking() && RandomFunction.random(20) < 6) {
sendChat(getWrathMessage());
} else if (getProperties().getCombatPulse().isInCombat() && RandomFunction.random(60) < 10) {
sendChat(getHailMessage());
}
}
@Override
public boolean canSelectTarget(Entity target) {
if (target instanceof Player) {
Player p = (Player) target;
if (type.isFriendly(p)) {
return false;
}
if (p.getZoneMonitor().isInZone("mage arena")) {
if (MageArenaPlugin.MAGE_ARENA.hasSession(p)) {
return false;
}
}
}
return true;
}
/**
* Gets the hail message.
* @return the message.
*/
public String getHailMessage() {
return "Hail " + type.getName() + "!";
}
/**
* Gets the wrath message.
* @return the message.
*/
public String getWrathMessage() {
return "Feel the wrath of " + type.getName() + ".";
}
@Override
public int[] getIds() {
// sara, zammy, guthix
return new int[] { 913, 912, 914 };
}
}
@@ -0,0 +1,209 @@
package content.minigame.magearena;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.SceneryDefinition;
import core.game.dialogue.DialogueAction;
import content.data.GodType;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import content.global.skill.agility.AgilityHandler;
import core.game.node.item.GroundItem;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.global.action.PickupHandler;
import core.game.world.GameWorld;
import core.plugin.ClassScanner;
/**
* Handles the mage arena activity.
* @author Vexia
*/
@Initializable
public final class MageArenaPlugin extends OptionHandler {
/**
* The pool destinations.
*/
private static final Location[] POOL_DESTINATIONS = new Location[] { Location.create(2542, 4718, 0), Location.create(2509, 4689, 0) };
/**
* The mage arena zone.
*/
public static final MageArenaZone MAGE_ARENA = new MageArenaZone();
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ClassScanner.definePlugin(MAGE_ARENA);
ClassScanner.definePlugin(new KolodionNPC());
ClassScanner.definePlugin(new MageArenaNPC());
ClassScanner.definePlugin(new LundailDialogue());
ClassScanner.definePlugin(new KolodionDialogue());
ClassScanner.definePlugin(new ChamberGuardianDialogue());
ItemDefinition.forId(2412).getHandlers().put("option:drop", this);
ItemDefinition.forId(2413).getHandlers().put("option:drop", this);
ItemDefinition.forId(2414).getHandlers().put("option:drop", this);
ItemDefinition.forId(2412).getHandlers().put("option:take", this);
ItemDefinition.forId(2413).getHandlers().put("option:take", this);
ItemDefinition.forId(2414).getHandlers().put("option:take", this);
SceneryDefinition.forId(2873).getHandlers().put("option:pray at", this);
SceneryDefinition.forId(2874).getHandlers().put("option:pray at", this);
SceneryDefinition.forId(2875).getHandlers().put("option:pray at", this);
SceneryDefinition.forId(2878).getHandlers().put("option:step-into", this);
SceneryDefinition.forId(2879).getHandlers().put("option:step-into", this);
return this;
}
@Override
public boolean handle(final Player player, final Node node, String option) {
switch (node.getId()) {
case 2879:
case 2878:
final Location destination = POOL_DESTINATIONS[2879 - node.getId()];
if (player.getSavedData().getActivityData().hasKilledKolodion()) {
player.getDialogueInterpreter().sendDialogue("You step into the pool of sparkling water. You feel energy rush", "through your veins.");
player.getDialogueInterpreter().addAction(new DialogueAction() {
@Override
public void handle(Player player, int buttonId) {
handlePool(player, true, destination, (Scenery) node);
}
});
return true;
}
player.lock(1);
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
handlePool(player, false, destination, (Scenery) node);
return true;
}
});
break;
case 2873:
case 2874:
case 2875:
GodType.forObject(node.getId()).pray(player, (Scenery) node);
break;
case 2412:
case 2413:
case 2414:
GodType type = GodType.forCape(((Item) node));
if (option.toLowerCase().equals("take")) {
GroundItem g = (GroundItem) node;
if (GodType.hasAny(player)) {
GroundItemManager.destroy(g);
player.sendMessages("You may only possess one sacred cape at a time.", "The conflicting powers of the capes drive them apart.");
} else {
PickupHandler.take(player, g);
}
return true;
} else {
if (type != null) {
player.sendMessage(type.getDropMessage());
player.getInventory().remove(type.getCape());
}
}
break;
}
return true;
}
@Override
public boolean isWalk(Player player, Node node) {
if (node instanceof GroundItem) {
return true;
}
return !(node instanceof Item);
}
@Override
public boolean isWalk() {
return false;
}
@Override
public Location getDestination(Node node, Node n) {
switch (n.getId()) {
case 2878:
int y = node.getLocation().getY(),
x = node.getLocation().getX();
Location dest = Location.create(2544, 4720, 0);
Direction dir = Direction.WEST;
if (y <= 4718) {
dest = Location.create(2542, 4718, 0);
dir = Direction.NORTH;
} else if (y == 4722) {
dest = Location.create(2542, 4722, 0);
dir = Direction.SOUTH;
} else if (x <= 2541) {
dest = Location.create(2540, 4720, 0);
dir = Direction.EAST;
}
((Player) node).setAttribute("mb-loc", dest);
((Player) node).setAttribute("mb-dir", dir);
return dest;
case 2873:
case 2874:
case 2875:
return n.getLocation().transform(0, -2, 0);
}
return null;
}
/**
* Handles the pool.
* @param player the player.
* @param enter if entered.
* @param dest the destination.
*/
public void handlePool(final Player player, boolean enter, final Location dest, final Scenery object) {
final Location start = player.getAttribute("mb-loc", player.getLocation());
final Location end = player.getLocation().transform(player.getAttribute("mb-dir", Direction.NORTH), 1);
player.removeAttribute("mc-loc");
player.removeAttribute("mb-dir");
if (enter) {
final Location middle = object.getId() == 2879 ? Location.create(2509, 4687, 0) : Location.create(2542, 4720, 0);
player.lock();
AgilityHandler.walk(player, -1, start, middle, new Animation(1426), 0.0, null);
GameWorld.getPulser().submit(new Pulse(1, player) {
int counter;
@Override
public boolean pulse() {
switch (++counter) {
case 3:
player.getPacketDispatch().sendPositionedGraphic(68, 1, 0, middle);
break;
case 4:
player.unlock();
player.getProperties().setTeleportLocation(dest);
return true;
}
return false;
}
});
return;
}
player.sendMessage("You step into the pool.");
AgilityHandler.walk(player, -1, start, end, new Animation(1426), 0.0, "Your boots get wet.");
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
player.getAppearance().setDefaultAnimations();
player.getAppearance().sync();
player.getProperties().setTeleportLocation(start);
return true;
}
});
}
}
@@ -0,0 +1,137 @@
package content.minigame.magearena;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
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.MapZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.game.world.map.zone.ZoneRestriction;
import core.plugin.Plugin;
/**
* Handles the mage arena zone.
* @author Vexia
*/
public final class MageArenaZone extends MapZone implements Plugin<Object> {
/**
* Constructs a new {@code MageArenaZone} {@code Object}.
*/
public MageArenaZone() {
super("mage arena", true, ZoneRestriction.RANDOM_EVENTS);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
return this;
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
@Override
public boolean enter(Entity e) {
return super.enter(e);
}
@SuppressWarnings("deprecation")
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
final Player p = (Player) e;
if (!logout) {
GameWorld.getPulser().submit(new Pulse(1, e) {
@Override
public boolean pulse() {
if (!p.getZoneMonitor().isInZone("mage arena")) {
if (hasSession(p)) {
getSession(p).close();
}
}
return true;
}
});
return true;
}
if (hasSession(p)) {
getSession(p).close();
}
if (logout && hasSession(p)) {
p.setLocation(Location.create(2540, 4717, 0));
}
}
return super.leave(e, logout);
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (style != CombatStyle.MAGIC) {
return false;
}
if (target instanceof Player) {
final Player t = (Player) target;
if (hasSession(t) && !(e instanceof KolodionNPC)) {
return false;
}
}
return super.continueAttack(e, target, style, message);
}
/**
* Gets the session.
* @param player the player.
* @return the session.
*/
public KolodionSession getSession(Player player) {
return KolodionSession.getSession(player);
}
/**
* Checks if the player has a session.
* @param player the player.
* @return {@code True} if so.
*/
public boolean hasSession(final Player player) {
return KolodionSession.getSession(player) != null;
}
@Override
public void configure() {
register(new ZoneBorders(3093, 3914, 3115, 3952));// the main
register(new ZoneBorders(3084, 3923, 3086, 3942));
register(new ZoneBorders(3118, 3924, 3126, 3941));
register(new ZoneBorders(3082, 3921, 3096, 3942));
int x = 3089, y = 3914, x2 = 3089, y2 = 3949;
for (int i = 0; i < 7; i++) {
register(new ZoneBorders(x - i, y + i, x2 - i, y2 - i));
}
register(new ZoneBorders(3119, 3942, 3123, 3945));
register(new ZoneBorders(3115, 3944, 3119, 3949));
register(new ZoneBorders(3119, 3942, 3119, 3952));
register(new ZoneBorders(3120, 3940, 2125, 3945));
register(new ZoneBorders(3114, 3944, 3120, 3949));
register(new ZoneBorders(3114, 3942, 3117, 3952));
x = 3118;
y = 3914;
x2 = 3118;
y2 = 3950;
for (int i = 0; i < 7; i++) {
register(new ZoneBorders(x + i, y + i, x2 + i, y2 - i));
}
register(new ZoneBorders(3107, 3931, 3118, 3947));
register(new ZoneBorders(3108, 3919, 3123, 3932));
register(new ZoneBorders(3108, 3921, 3123, 3932));
register(new ZoneBorders(3104, 3933, 3117, 3948));
register(new ZoneBorders(3106, 3920, 3117, 3937));
register(new ZoneBorders(3115, 3928, 3120, 3942));
}
}
@@ -0,0 +1,122 @@
package content.minigame.mta;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
/**
* Handles the alchemy guardian dialogue.
* @author Vexia
*/
public class AlchemyGuardianDialogue extends DialoguePlugin {
/**
* Constructs a new {@code AlchemyGuardianDialogue} {@code Object}
*/
public AlchemyGuardianDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code AlchemyGuardianDialogue} {@code Object}
* @param player the player.
*/
public AlchemyGuardianDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new AlchemyGuardianDialogue(player);
}
@Override
public boolean open(Object... args) {
player("Hi.");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
options("What do I have to do in this room?", "What are the rewards?", "Got any tips that may help me?", "Thanks, bye!");
stage++;
break;
case 1:
switch (buttonId) {
case 1:
player("What do I have to do in this room?");
stage = 10;
break;
case 2:
player("What are the rewards?");
stage = 20;
break;
case 3:
player("Got any tips that may help me?");
stage = 30;
break;
case 4:
player("Thanks, bye!");
stage = 40;
break;
}
break;
case 10:
npc("In this room you will see various cupboards. It is your", "task to search the cupboards to find items to turn into", "gold using your low or high alchemy spells. You must", "deposit the money in the receptacle at the end of the");
stage++;
break;
case 11:
npc("hall in order to receive your Alchemist Pizazz Points,", "otherwise the money will be taken from you as you", "leave through the portal. This money is used for the", "upkeep of the training arena as well as magic shops all");
stage++;
break;
case 12:
npc("around Keldagrim. Keep an eye on the cost of each", "items as these will change from time-to-time, as will the", "location of the items. Occasionally one of the items will", "be indicated as costing no runestones to convert to");
stage++;
break;
case 13:
npc("money.");
stage = 0;
break;
case 20:
npc("You will get experience from casting the alchemist", "spells, as well as 1 Alchemist Pizazz Point for every 100", "coins you deposit, and 10% of the coins you deposit will", "be given to you as you leave. Keep in mind that you");
stage++;
break;
case 21:
npc("will not be able to take more than 1000 coins back out", "with you.");
stage = 0;
break;
case 30:
npc("You must remember to keep ane eye on the various", "costs of the itmes. If you watch the movements of the", "other players, you might be able to guess which are the", "best places to visit. You will get 1 Pizazz Point for");
stage++;
break;
case 31:
npc("every 100 coins, so if you have 190 coins, why not get", "an extra 10?");
stage++;
break;
case 32:
player("I see.");
stage++;
break;
case 33:
npc("Oh, and a word of warning: should you decide to leave", "this room by a method other than the exit portals, you", "will be teleported to the entrance and have any items", "that you picked up in the room removed.");
stage = 0;
break;
case 34:
end();
break;
case 40:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 3099 };
}
}
@@ -0,0 +1,123 @@
package content.minigame.mta;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
/**
* Handles the charmed warrior dialogue.
* @author Vexia
*/
public class CharmedWarriorDialogue extends DialoguePlugin {
/**
* Constructs a new {@Code CharmedWarriorDialogue} {@Code
* Object}
*/
public CharmedWarriorDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@Code CharmedWarriorDialogue} {@Code
* Object}
* @param player the player.
*/
public CharmedWarriorDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new CharmedWarriorDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
switch (npc.getId()) {
case 3105:
case 3104:
player("Is there anybody there?");
break;
default:
player("Hello?");
break;
}
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (npc.getId()) {
case 3107:
switch (stage) {
case 0:
npc("Can't you see I'm busy?");
stage++;
break;
case 1:
player("Well, I can't really see YOU.");
stage++;
break;
case 2:
end();
break;
}
break;
case 3106:
switch (stage) {
case 0:
npc("Hey! You haven't paid for your Magic Training Arena", "Membership money!");
stage++;
break;
case 1:
player("You're lying. I can see right through you!");
stage++;
break;
case 2:
npc("Oh, HA HA, very funny.");
stage++;
break;
case 3:
end();
break;
}
break;
case 3105:
switch (stage) {
case 0:
npc("Wooo wooo! Be afraid for I'm a scary ghost. Wooo!");
stage++;
break;
case 1:
player("Er, whatever.");
stage++;
break;
case 2:
end();
break;
}
break;
case 3104:
switch (stage) {
case 0:
npc("What do you think?");
stage++;
break;
case 1:
end();
break;
}
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 3106, 3107, 3104, 3105 };
}
}
@@ -0,0 +1,232 @@
package content.minigame.mta
import content.minigame.mta.impl.EnchantingZone.Shapes
import core.game.node.Node
import core.game.node.entity.Entity
import core.game.node.entity.combat.spell.SpellType
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.SpellBookManager.SpellBook
import core.game.node.entity.player.link.audio.Audio
import core.game.node.entity.combat.spell.MagicSpell
import core.game.node.entity.combat.spell.Runes
import core.game.node.item.Item
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics
import core.plugin.Plugin
import org.rs09.consts.Items
/**
* Represents the enchant spells.
* @author Ceikry
*/
class EnchantSpell : MagicSpell {
/**
* The enchantable jewellery array.
*/
private val jewellery: Map<Int,Item>?
/**
* Constructs a new `EnchantSpell` `Object`.
*/
constructor() {
jewellery = null
}
/**
* Constructs a new `EnchantSpell` `Object`.
* @param level The level required.
* @param jewellery The jewellery this spell is able to echant.
* @param runes The runes required.
*/
constructor(level: Int, experience: Double, jewellery: Map<Int,Item>, runes: Array<Item>?) : super(SpellBook.MODERN, level, experience, ANIMATION, GRAPHIC, Audio(115, 1, 0), runes) {
this.jewellery = jewellery
}
override fun cast(entity: Entity, target: Node): Boolean {
if (target !is Item || entity !is Player) {
return false
}
entity.interfaceManager.setViewedTab(6)
val enchanted = jewellery?.getOrDefault(target.id,null)
if (enchanted == null) {
entity.packetDispatch.sendMessage("You can't use this spell on this item.")
return false
}
if (!meetsRequirements(entity, true, true)) {
return false
}
if (entity.inventory.remove(target)) {
visualize(entity, target)
entity.inventory.add(enchanted)
}
//MTA-Specific Code
if (entity.zoneMonitor.isInZone("Enchantment Chamber")) {
entity.graphics(Graphics.create(237, 110))
var pizazz = 0
if (target.id == 6903) {
pizazz = (if (getSpellId() == 5) 1 else if (getSpellId() == 16) 2 else if (getSpellId() == 28) 3 else if (getSpellId() == 36) 4 else if (getSpellId() == 51) 5 else 6) * 2
} else {
val shape = Shapes.forItem(target)
if (shape != null) {
var convert = entity.getAttribute("mta-convert", 0)
convert += 1
if (convert >= 10) {
pizazz = if (getSpellId() == 5) 1 else if (getSpellId() == 16) 2 else if (getSpellId() == 28) 3 else if (getSpellId() == 36) 4 else if (getSpellId() == 51) 5 else 6
convert = 0
}
entity.setAttribute("mta-convert", convert)
if (shape == content.minigame.mta.impl.EnchantingZone.BONUS_SHAPE) {
pizazz += 1
entity.sendMessage("You get " + pizazz + " bonus point" + (if (pizazz != 1) "s" else "") + "!")
}
}
}
if (pizazz != 0) {
content.minigame.mta.impl.EnchantingZone.ZONE.incrementPoints(entity, content.minigame.mta.MTAType.ENCHANTERS.ordinal, pizazz)
}
}
return true
}
override fun getDelay(): Int {
return 1
}
override fun getExperience(player: Player): Double {
return if (player.zoneMonitor.isInZone("Enchantment Chamber")) {
experience - experience * 0.25
} else experience
}
override fun newInstance(arg: SpellType?): Plugin<SpellType>? {
/**
* Enchant Sapphire Jewelry (Lvl-1 Enchant)
*/
SpellBook.MODERN.register(5, EnchantSpell(7, 17.5,
mapOf(
//Begin Jewelry Enchantments
Items.SAPPHIRE_RING_1637 to Item(Items.RING_OF_RECOIL_2550),
Items.SAPPHIRE_NECKLACE_1656 to Item(Items.GAMES_NECKLACE8_3853),
Items.SAPPHIRE_AMULET_1694 to Item(Items.AMULET_OF_MAGIC_1727),
Items.SAPPHIRE_BRACELET_11072 to Item(Items.BRACELET_OF_CLAY_11074),
//Begin MTA-specific enchantments
Items.CUBE_6899 to Item(Items.ORB_6902),
Items.CYLINDER_6898 to Item(Items.ORB_6902),
Items.ICOSAHEDRON_6900 to Item(Items.ORB_6902),
Items.PENTAMID_6901 to Item(Items.ORB_6902),
Items.DRAGONSTONE_6903 to Item(Items.ORB_6902)
),
arrayOf(Item(Items.COSMIC_RUNE_564,1), Item(Items.WATER_RUNE_555,1))))
/**
* Enchant Emerald Jewelry (Lvl-2 Enchant)
*/
SpellBook.MODERN.register(16, EnchantSpell(27, 37.0,
mapOf(
//Begin Jewelry Enchantments
Items.EMERALD_RING_1639 to Item(Items.RING_OF_DUELLING8_2552),
Items.EMERALD_NECKLACE_1658 to Item(Items.BINDING_NECKLACE_5521),
Items.EMERALD_AMULET_1696 to Item(Items.AMULET_OF_DEFENCE_1729),
Items.EMERALD_BRACELET_11076 to Item(Items.CASTLEWAR_BRACE3_11079),
//Begin MTA-Specific Enchantments
Items.CUBE_6899 to Item(Items.ORB_6902),
Items.CYLINDER_6898 to Item(Items.ORB_6902),
Items.ICOSAHEDRON_6900 to Item(Items.ORB_6902),
Items.PENTAMID_6901 to Item(Items.ORB_6902),
Items.DRAGONSTONE_6903 to Item(Items.ORB_6902)
),
arrayOf(Item(Runes.COSMIC_RUNE.id, 1), Item(Runes.AIR_RUNE.id, 3))))
/**
* Enchant Ruby Jewelry (Lvl-3 Enchant)
*/
SpellBook.MODERN.register(28, EnchantSpell(49, 59.0,
mapOf(
//Begin Jewelry Enchantments
Items.RUBY_RING_1641 to Item(Items.RING_OF_FORGING_2568),
Items.RUBY_NECKLACE_1660 to Item(Items.DIGSITE_PENDANT_5_11194),
Items.RUBY_AMULET_1698 to Item(Items.AMULET_OF_STRENGTH_1725),
Items.RUBY_BRACELET_11085 to Item(Items.INOCULATION_BRACE_11088),
//Begin MTA-Specific Enchantments
Items.CUBE_6899 to Item(Items.ORB_6902),
Items.CYLINDER_6898 to Item(Items.ORB_6902),
Items.ICOSAHEDRON_6900 to Item(Items.ORB_6902),
Items.PENTAMID_6901 to Item(Items.ORB_6902),
Items.DRAGONSTONE_6903 to Item(Items.ORB_6902)
),
arrayOf(Item(Runes.COSMIC_RUNE.id, 1), Item(Runes.FIRE_RUNE.id, 5))))
/**
* Enchant Diamond Jewelry (Lvl-4 Enchant)
*/
SpellBook.MODERN.register(36, EnchantSpell(57, 67.0,
mapOf(
Items.DIAMOND_RING_1643 to Item(Items.RING_OF_LIFE_2570),
Items.DIAMOND_NECKLACE_1662 to Item(Items.PHOENIX_NECKLACE_11090),
Items.DIAMOND_AMULET_1700 to Item(Items.AMULET_OF_POWER_1731),
Items.DIAMOND_BRACELET_11092 to Item(Items.FORINTHRY_BRACE5_11095),
//Begin MTA-Specific Enchantments
Items.CUBE_6899 to Item(Items.ORB_6902),
Items.CYLINDER_6898 to Item(Items.ORB_6902),
Items.ICOSAHEDRON_6900 to Item(Items.ORB_6902),
Items.PENTAMID_6901 to Item(Items.ORB_6902),
Items.DRAGONSTONE_6903 to Item(Items.ORB_6902)
),
arrayOf(Item(Runes.COSMIC_RUNE.id, 1), Item(Runes.EARTH_RUNE.id, 10))))
/**
* Enchant Dragonstone Jewelry (Lvl-5 Enchant)
*/
SpellBook.MODERN.register(51, EnchantSpell(68, 78.0,
mapOf(
//Begin Jewelry Enchantment
Items.DRAGONSTONE_RING_1645 to Item(14646),
Items.DRAGON_NECKLACE_1664 to Item(Items.SKILLS_NECKLACE4_11105),
Items.DRAGONSTONE_AMMY_1702 to Item(Items.AMULET_OF_GLORY4_1712),
Items.DRAGON_BRACELET_11115 to Item(Items.COMBAT_BRACELET4_11118),
//Begin MTA-Specific Enchantments
Items.CUBE_6899 to Item(Items.ORB_6902),
Items.CYLINDER_6898 to Item(Items.ORB_6902),
Items.ICOSAHEDRON_6900 to Item(Items.ORB_6902),
Items.PENTAMID_6901 to Item(Items.ORB_6902),
Items.DRAGONSTONE_6903 to Item(Items.ORB_6902)
),
arrayOf(Item(Runes.COSMIC_RUNE.id, 1), Item(Runes.WATER_RUNE.id, 15), Item(Runes.EARTH_RUNE.id, 15))))
/**
* Enchant Onyx Jewelry (Lvl-6 Enchant)
*/
SpellBook.MODERN.register(61, EnchantSpell(87, 97.0,
mapOf(
//Begin Jewelry Enchantments
Items.ONYX_RING_6575 to Item(Items.RING_OF_STONE_6583),
Items.ONYX_NECKLACE_6577 to Item(Items.BERSERKER_NECKLACE_11128),
Items.ONYX_AMULET_6581 to Item(Items.AMULET_OF_FURY_6585),
Items.ONYX_BRACELET_11130 to Item(Items.REGEN_BRACELET_11133),
//Begin MTA-Specific Enchantments
Items.CUBE_6899 to Item(Items.ORB_6902),
Items.CYLINDER_6898 to Item(Items.ORB_6902),
Items.ICOSAHEDRON_6900 to Item(Items.ORB_6902),
Items.PENTAMID_6901 to Item(Items.ORB_6902),
Items.DRAGONSTONE_6903 to Item(Items.ORB_6902)
),
arrayOf(Item(Runes.COSMIC_RUNE.id, 1), Item(Runes.FIRE_RUNE.id, 20), Item(Runes.EARTH_RUNE.id, 20))))
return this
}
companion object {
/**
* The animation.
*/
private val ANIMATION = Animation.create(712)
/**
* The graphic.
*/
private val GRAPHIC = Graphics(114, 96)
}
}
@@ -0,0 +1,120 @@
package content.minigame.mta;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
/**
* Handles the enchantment guardian dialogue.
* @author Vexia
*/
public class EnchantmentGuardianDialogue extends DialoguePlugin {
/**
* Constructs a new {@Code EnchantmentGuardianDialogue} {@Code
* Object}
*/
public EnchantmentGuardianDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@Code EnchantmentGuardianDialogue} {@Code
* Object}
* @param player the player.
*/
public EnchantmentGuardianDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new EnchantmentGuardianDialogue(player);
}
@Override
public boolean open(Object... args) {
npc("Greetings young one. How can I enlighten you?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
options("What do I have to do in this room?", "What are the rewards?", "Got any tips that may help me?", "Thanks, bye!");
stage++;
break;
case 1:
switch (buttonId) {
case 1:
player("What do I have to do in this room?");
stage = 10;
break;
case 2:
player("What are the rewards?");
stage = 20;
break;
case 3:
player("Got any tips that may help me?");
stage = 30;
break;
case 4:
player("Thanks, bye!");
stage = 40;
break;
}
break;
case 10:
npc("In this chamber you will see various piles of shapes. You", "can pick up these shapes and enchant them using the", "enchant jewelry spells. By enchanting these shapes,", "you'll be converting them into orbs which you can be");
stage++;
break;
case 11:
npc("placed in the hole in the centre. You will get", "Enchantment Pizazz Points for every ten shapes that", "you convert and the points you get depends on the", "level of enchantment spell you cast. You will get a");
stage++;
break;
case 12:
npc("bonus Pizazz Point for enchanting a certain shape at a", "certain time, which I will periodically shout out. You will", "also be rewarded with an item for every so many orbs", "you deposit into the hole.");
stage = 0;
break;
case 20:
npc("As well as the magic experience from casting your", "enchantment spells, you will get Enchantment Pizazz", "Points for converting so many shapes, plus a bonus", "point for converting shape of the correct type. You");
stage++;
break;
case 21:
npc("should also note that you will occasionally be rewarded", "with items when you put one of the enchanted orbs in", "the floor.");
stage = 0;
break;
case 30:
npc("Try to guess or keep track of the time between the", "change of the best shape to enchant. This means you", "can be ready to run to a different shape when you", "know it is about to change. Look out for the dragon");
stage++;
break;
case 31:
npc("gems, as these will get you more Pizazz Points!");
stage++;
break;
case 32:
player("I see.");
stage++;
break;
case 33:
npc("Oh, and a word of warning: should you decide to leave", "this room by a method other than the exit portals, you", "will be teleported to the entrance and have any items", "that you picked up in the room removed.");
stage = 0;
break;
case 34:
end();
break;
case 40:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 3100 };
}
}
@@ -0,0 +1,320 @@
package content.minigame.mta;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
/**
* Handles the entrance guardian dialogue.
* @author Vexia
*/
public class EntranceGuardianDialogue extends DialoguePlugin {
/**
* Constructs a new {@Code EntranceGuardianDialogue} {@Code
* Object}
*/
public EntranceGuardianDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@Code EntranceGuardianDialogue} {@Code
* Object}
* @param player the player.
*/
public EntranceGuardianDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new EntranceGuardianDialogue(player);
}
@Override
public boolean open(Object... args) {
player("Hi.");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
npc("Greetings. What wisdom do you seek?");
stage++;
if (player.getSavedData().getActivityData().isStartedMta()) {
stage = 30;
}
break;
case 1:
options("I'm new to this place. Where am I?", "None, I don't really care.");
stage++;
break;
case 2:
if (buttonId == 1) {
player("I'm new to this place. Where am I?");
stage++;
break;
}
end();
break;
case 3:
npc("Well young one, you have entered the Magic Training", "Arena. It was built at the start of the Fifth Age, when", "runestones were first discovered. It was made because", "of the many pointless accidents caused by inexperienced");
stage++;
break;
case 4:
npc("mages.");
stage++;
break;
case 5:
player("Who created it?");
stage++;
break;
case 6:
npc("Good question. It was originally made by the ancestors", "of the wizards in the Wizards Tower. However, it was", "destroyed by melee and ranged warriors who took", "offence at the use of this new 'Magic Art'. Recently");
stage++;
break;
case 7:
npc("the current denizens of the Wizards Tower have", "resurrected the arena including various Guardians you", "will see as you look around. We are here to help and to", "ensure things run smoothly.");
stage++;
break;
case 8:
player("Interesting. So what can I do here?");
stage++;
break;
case 9:
npc("You may train up your skills in the magic arts by", "travelling through one of the portals at the back of this", "entrance hall. By training up in one of these areas you", "will be awarded special Pizazz Points unique to each.");
stage++;
break;
case 10:
npc("room. With these points you may claim a variety of", "items from my fellow guardian up the stairs.");
stage++;
break;
case 11:
player("How do you record the points I have earned?");
stage++;
break;
case 12:
if (player.getSavedData().getActivityData().isStartedMta()) {
npc("With the Pizazz Progress Hat I gave you, of course.");
stage = 40;
break;
}
npc("You really are full of questions! You will need a special", "Pizzaz Progress Hat! I can give you one if you so", "wish to train here.");
stage++;
break;
case 13:
player("Yes Please!");
stage++;
break;
case 14:
player.getSavedData().getActivityData().setStartedMta(true);
player.getInventory().add(MageTrainingArenaPlugin.PROGRESS_HAT, player);
npc("Here you go. Talk to the hat to find out your current", "Pizzaz Points totals.");
stage++;
break;
case 15:
player("Talk to it?");
stage++;
break;
case 16:
npc("Well of course, it's a magic Pizazz Progress Hat! Mind", "your manners though, hats have feelings too!");
stage++;
break;
case 17:
player("Er... if you insist.");
stage++;
break;
case 18:
npc("Oh, and a word of warning: should you decide to leave", "the rooms by any method other than the exit portals,", "you will be teleported to the entrance and have any", "items that you picked up in the room removed.");
stage++;
break;
case 19:
player("Okay. Thanks!");
stage++;
break;
case 20:
end();
break;
case 30:
options("Can you tell me about this place again?", "Can you explain the different portals?", "About the progress hat...", "Thanks, bye!");
stage++;
break;
case 31:
switch (buttonId) {
case 1:
player("Can you tell me about this place again?");
stage = 3;
break;
case 2:
player("Can you explain the different portals?");
stage = 50;
break;
case 3:
player("About the progress hat...");
stage = 100;
break;
case 4:
end();
break;
}
break;
case 100:
if (!player.hasItem(MageTrainingArenaPlugin.PROGRESS_HAT)) {
npc("You want another one don't you.");
stage = 110;
break;
}
npc("Which you have stored somewhere I'm sure.");
stage++;
break;
case 101:
player("Yes. What's it for?");
stage++;
break;
case 102:
npc("Collect Pizazz Points from the various areas and the", "hat will remember your totals. Talk to the hat at any", "time to find out what points you have. Go upstairs and", "talk to the Rewards Guardian to claim items for the");
stage++;
break;
case 103:
npc("points.");
stage = 30;
break;
case 110:
player("Sorry, can I?");
stage++;
break;
case 111:
player.getInventory().add(MageTrainingArenaPlugin.PROGRESS_HAT, player);
npc("Here you go. Talk to the hat to find out your current", "Pizazz Point totals.");
stage = 30;
break;
case 40:
player("OK.");
stage++;
break;
case 41:
npc("Oh, and a word of warning: should you decide to log", "out whilst in any of the rooms in the arena, you will be", "teleported to the entrance and have any items that you", "picked up in the room removed.");
stage = 30;
break;
case 50:
npc("They lead to four areas to train your magic: The", "Telekinetic Theatre, The Alchemists' Playground, The", "Enchanting Chamber, and The Creature Graveyard.");
stage++;
break;
case 51:
options("What's the Telekinetic Theatre?", "What's the Alchemists' Playground?", "What's the Enchanting CHamber?", "What's the Creature Gaveyard?", "Thanks, bye!");
stage++;
break;
case 52:
switch (buttonId) {
case 1:
player("What's the Telekinetic Theatre?");
stage = 60;
break;
case 2:
player("What's the Alchemists' Playground?");
stage = 70;
break;
case 3:
player("What's the Enchanting Chamber?");
stage = 80;
break;
case 4:
player("What's the Creature Gaveyard?");
stage = 90;
break;
case 5:
end();
break;
}
break;
case 60:
npc("In there you can earn Telekinetic Pizazz Points for", "trde upstairs.");
stage++;
break;
case 61:
player("What will I be doing in there?");
stage++;
break;
case 62:
npc("That depends on how much of a time-waster you are!", "You are required to use the Telekinetic Grab spell in", "order to move a statue throuhh a maze. Casting the", "spell will move the statue towards you until it reaches a");
stage++;
break;
case 63:
npc("wall. So by standing on the different sides of the maze", "you can move the statue Nort, East, South or West.", "You will be rewarded Pizazz Points for each maze", "successfully solved.");
stage = 51;
break;
case 70:
npc("In the playground you can earn Alchemist Pizazz", "Points for trading with the rewards guardian upstairs.");
stage++;
break;
case 71:
player("What's in there?");
stage++;
break;
case 72:
npc("You'll find eight cupboards containing items you can", "turn to gold using the low and high alchemy spells. The", "money you earn will be taken from you upon leaving", "the playground to pay for the upkeep of this training");
stage++;
break;
case 73:
npc("arena and to help fund magic shops around " + GameWorld.getSettings().getName() + ".", "You will be rewarded with 1 Pizazz Point for every", "100 coins deposited and a percentage of the money you", "create. Keep in mind that you will not be able to take");
stage++;
break;
case 74:
npc("more than 1000 coins back out with you.");
stage++;
break;
case 75:
player("Sounds simple.");
stage = 51;
break;
case 80:
npc("In here you will be able to earn Enchantment Pizazz", "Points for trade upstairs.");
stage++;
break;
case 81:
player("What will I have to do?");
stage++;
break;
case 82:
npc("You will find yourself amongst various piles of shapes.", "You can pick up these shapes and use on of your", "enchanting spells upon it to morph it into an orb. You'll", "also see a hole in the centre of the room; put the orbs");
stage++;
break;
case 83:
npc("in here and for every 20 we will credit you with a gift,", "You will get Pizazz Points for every 10 shapes that", "you convert and the amount of points depends on the", "spell you use.");
stage = 51;
break;
case 90:
npc("In here you will be able to earn Graveyard Pizazz", "Points for trade upstairs.");
stage++;
break;
case 91:
player("But what do I have to do in there?");
stage++;
break;
case 92:
npc("Patience young one. A great many creatures die in", "this world and much of their remainds can cause clutter.", "We have taken it upon ourselves to teleport many", "bones from these creatures into this graveyard for a");
stage++;
break;
case 93:
npc("use. It's up to you to practice your bones to bannanas", "spell in order to put these bones into immediate use -", "nutritious food for monsters! Just convert the bones", "and put them in the holes in the walls. There is a");
stage++;
break;
case 94:
npc("drawback to this room however, the bones often fall on", "people so you may want to eat some of those bannas", "to stay alive. When people die we confiscate Pizazz", "Points for the effort of teleporting incompetent mages.");
stage = 51;
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 3097 };
}
}
@@ -0,0 +1,120 @@
package content.minigame.mta;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
/**
* Handles the graveyard guardian dialogue.
* @author Vexia
*/
public class GraveyardGuardianDialogue extends DialoguePlugin {
/**
* Constructs a new {@Code GraveyardGuardianDialogue} {@Code
* Object}
*/
public GraveyardGuardianDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@Code GraveyardGuardianDialogue} {@Code
* Object}
* @param player the player.
*/
public GraveyardGuardianDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new GraveyardGuardianDialogue(player);
}
@Override
public boolean open(Object... args) {
player("Hello.");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
options("What do I have to do in this room?", "What are the rewards?", "Got any tips that may help me?", "Thanks, bye!");
stage++;
break;
case 1:
switch (buttonId) {
case 1:
player("What do I have to do in this room?");
stage = 10;
break;
case 2:
player("What are the rewards?");
stage = 20;
break;
case 3:
player("Got any tips that may help me?");
stage = 30;
break;
case 4:
player("Thanks, bye!");
stage = 40;
break;
}
break;
case 10:
npc("Have you noticed all the bones around the room? These", "are teleported here from all over Keldagrim to help", "clean up the landscape of countless bones left behind", "from combat. What better use for these bones than to");
stage++;
break;
case 11:
npc("convert them to nutritious fruit to be eaten by you", "mortals? You have to use your Bones to Bannas spell", "to convert the bones and then place them in the holes", "on the walls to earn Graveyard Pizazz Points.");
stage++;
break;
case 12:
npc("Unluckily for you, your health will constantly decrease", "from getting hit by these dropping bones so you will", "probably want to eat some of the bananas yourself to", "increase your stay here.");
stage = 0;
break;
case 20:
npc("You will get experience from casting your bones to", "bananas spell and you will get Graveyard Pizazz Points", "when you put the bananas though the wall.", "Occasionally you will also be credited with a runestone");
stage++;
break;
case 21:
npc("to help you in your future spell casting.");
stage = 0;
break;
case 30:
npc("Different bones will provide you with different numbers", "of bananas, so try to find the best type. Collect enough", "points and you will be able to buy a 'Bones to Peaches'", "spell from my fellow guardian above the entrance hall.");
stage++;
break;
case 31:
npc("This spell can be used here just like the bones to", "bananas spell, except this spell will give you even more", "experience and the peaches will restore more health!");
stage++;
break;
case 32:
player("I see.");
stage++;
break;
case 33:
npc("Oh, and a word of warning: should you decide to leave", "this room by a method other than the exit portals, you", "will be teleported to the entrance and have any items", "that you picked up in the room removed.");
stage = 0;
break;
case 34:
end();
break;
case 40:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 3101 };
}
}
@@ -0,0 +1,106 @@
package content.minigame.mta
import content.global.skill.magic.SpellListener
import content.global.skill.magic.spellconsts.Modern
import core.game.node.item.Item
import core.game.world.map.Direction
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
class MTAListeners : InteractionListener {
override fun defineListeners() {
on(NPCs.MAZE_GUARDIAN_3102, IntType.NPC, "talk-to"){ player, node ->
player.dialogueInterpreter.open(node.id, node)
return@on true
}
setDest(IntType.NPC, intArrayOf(NPCs.MAZE_GUARDIAN_3102), "talk-to") { player, node ->
return@setDest node.location.transform(Direction.getDirection(player.location, node.location), -1);
}
}
}
class MTASpellListeners : SpellListener("modern"){
private val LOW_ALCH_ANIM = Animation(712)
private val LOW_ALCH_GFX = Graphics(112,5)
private val HIGH_ALCH_ANIM = Animation(713)
private val HIGH_ALCH_GFX = Graphics(113,5)
private val MTA_ALCH_ITEMS = content.minigame.mta.impl.AlchemistZone.AlchemistItem.values().map{it.item.id}.toIntArray()
override fun defineListeners() {
onCast(Modern.HIGH_ALCHEMY,ITEM,*MTA_ALCH_ITEMS){ p, node ->
val item = node?.asItem() ?: return@onCast
requires(p,55)
val alchItem = content.minigame.mta.impl.AlchemistZone.AlchemistItem.forItem(item.id) ?: return@onCast
val coins = Item(content.minigame.mta.impl.AlchemistZone.COINS.id, alchItem.cost)
val freeAlch = alchItem == content.minigame.mta.impl.AlchemistZone.freeConvert
if (p.inventory.getAmount(content.minigame.mta.impl.AlchemistZone.COINS.id) + alchItem.cost > 10000) {
p.dialogueInterpreter.sendDialogue("Warning: You can't deposit more than 12000 coins at a time.")
}
if (coins.amount > 1 && !p.inventory.hasSpaceFor(coins)) {
p.packetDispatch.sendMessage("Not enough space in your inventory!")
return@onCast
}
if(!freeAlch){
requires(p,55,arrayOf(Item(Items.FIRE_RUNE_554,5),Item(Items.NATURE_RUNE_561,1)))
}
p.lock(3)
p.visualize(HIGH_ALCH_ANIM,HIGH_ALCH_GFX)
if(p.inventory.remove(Item(item.id,1))){
p.audioManager.send(97)
if (coins.amount != 0) {
p.inventory.add(coins)
}
}
showMagicTab(p)
addXP(p,65.0)
setDelay(p,false)
removeRunes(p)
}
onCast(Modern.LOW_ALCHEMY,ITEM,*MTA_ALCH_ITEMS){p, node ->
val item = node?.asItem() ?: return@onCast
requires(p,21)
val alchItem = content.minigame.mta.impl.AlchemistZone.AlchemistItem.forItem(item.id) ?: return@onCast
val coins = Item(content.minigame.mta.impl.AlchemistZone.COINS.id, alchItem.cost)
val freeAlch = alchItem == content.minigame.mta.impl.AlchemistZone.freeConvert
if (p.inventory.getAmount(content.minigame.mta.impl.AlchemistZone.COINS.id) + alchItem.cost > 10000) {
p.dialogueInterpreter.sendDialogue("Warning: You can't deposit more than 12000 coins at a time.")
}
if (coins.amount > 1 && !p.inventory.hasSpaceFor(coins)) {
p.packetDispatch.sendMessage("Not enough space in your inventory!")
return@onCast
}
if(!freeAlch){
requires(p,21,arrayOf(Item(Items.FIRE_RUNE_554,3),Item(Items.NATURE_RUNE_561,1)))
}
p.lock(3)
p.visualize(LOW_ALCH_ANIM,LOW_ALCH_GFX)
if(p.inventory.remove(Item(item.id,1))){
p.audioManager.send(97)
if (coins.amount != 0) {
p.inventory.add(coins)
}
}
showMagicTab(p)
addXP(p,31.0)
setDelay(p,false)
removeRunes(p)
}
}
}
@@ -0,0 +1,259 @@
package content.minigame.mta;
import core.api.ContainerisedItem;
import core.game.component.CloseEvent;
import core.game.component.Component;
import core.game.component.ComponentPlugin;
import core.game.container.Container;
import core.game.container.ContainerType;
import core.game.container.access.InterfaceContainer;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.plugin.Plugin;
import core.game.world.GameWorld;
import java.util.ArrayList;
import java.util.List;
import static core.api.ContentAPIKt.hasAnItem;
/**
* Represents the mage training arena shop.
* @author Vexia
*/
public class MTAShop {
/**
* The magic training arena shop items.
*/
private static final Item[] ITEMS = new Item[] { new Item(6908, 100), new Item(6910, 100), new Item(6912, 100), new Item(6914, 100), new Item(6916, 100), new Item(6918, 100), new Item(6920, 100), new Item(6922, 100), new Item(6924, 100), new Item(6889, 100), new Item(6926, 100), new Item(4695, 100), new Item(4696, 100), new Item(4697, 100), new Item(4698, 100), new Item(4694, 100), new Item(4699, 100), new Item(564, 100), new Item(562, 100), new Item(561, 100), new Item(560, 100), new Item(563, 100), new Item(566, 100), new Item(565, 100) };
/**
* The prices.
*/
private static final int[][] PRICES = new int[][] { { 30, 30, 300, 30 }, { 60, 60, 600, 60 }, { 150, 200, 1500, 150 }, { 240, 240, 2400, 240 }, { 400, 450, 4000, 400 }, { 350, 400, 3000, 350 }, { 120, 120, 1200, 120 }, { 175, 225, 1500, 175 }, { 450, 500, 5000, 450 }, { 500, 550, 6000, 500 }, { 200, 300, 2000, 200 }, { 1, 1, 15, 1 }, { 1, 1, 15, 1 }, { 1, 1, 15, 1 }, { 1, 1, 15, 1 }, { 1, 1, 15, 1 }, { 1, 1, 15, 1 }, { 0, 0, 5, 0 }, { 0, 1, 5, 1 }, { 0, 1, 0, 1 }, { 2, 1, 20, 1 }, { 2, 0, 0, 0 }, { 2, 2, 25, 2 }, { 2, 2, 25, 2 } };
/**
* The container.
*/
private final Container container = new Container(ITEMS.length, ContainerType.SHOP);
/**
* The mage training arena shop plugin.
*/
private final MTAShopPlugin shopPlugin = new MTAShopPlugin();
/**
* The viewers.
*/
private final List<Player> viewers = new ArrayList<>(100);
/**
* The shop component.
*/
private final Component component = new Component(197).setCloseEvent(new CloseEvent() {
@Override
public boolean close(Player player, Component c) {
if (player == null) {
return true;
}
viewers.remove(player);
return true;
}
});
/**
* Constructs a new {@Code MTAShop} {@Code Object}
*/
public MTAShop() {
container.add(ITEMS);
component.setPlugin(shopPlugin);
GameWorld.getPulser().submit(new Pulse(100) {
@Override
public boolean pulse() {
for (int i = 0; i < container.toArray().length; i++) {
final boolean main = true;
final Item item = container.toArray()[i];
if (item == null) {
continue;
}
if (main) {
if (item.getAmount() < 100) {
item.setAmount(item.getAmount() + 1);
}
MTAShop.this.update();
}
}
return false;
}
});
}
/**
* Opens the shop.
* @param player the player.
*/
public void open(final Player player) {
viewers.add(player);
player.getInterfaceManager().open(component);
update();
updatePoints(player);
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
updatePoints(player);
return true;
}
});
}
/**
* Updates the viewers.
*/
private void update() {
for (Player p : viewers) {
if (p == null || !p.isActive()) {
continue;
}
InterfaceContainer.generateItems(p, container.toArray(), new String[] { "Buy", "Value" }, 197, 16, 4, 7);
}
}
/**
* The item to purchase.
* @param player the player.
* @param item the item.
*/
public void buy(Player player, Item item, int slot) {
int[] prices = PRICES[slot];
if (item.getAmount() < 1) {
player.sendMessage("The shop has ran out of stock.");
return;
}
item = new Item(item.getId(), 1);
if (!player.getInventory().hasSpaceFor(item)) {
player.sendMessage("You don't have enough inventory space.");
return;
}
for (int i = 0; i < prices.length; i++) {
if (getPoints(player, i) < prices[i]) {
player.sendMessage("You cannot afford that item.");
return;
}
}
if (item.getId() == 6926 && player.getSavedData().getActivityData().isBonesToPeaches()) {
player.sendMessage("You already unlocked that spell.");
return;
}
ContainerisedItem itemToRemove = null;
if (slot >= 1 && slot <= 3) {
Item required = ITEMS[slot - 1];
itemToRemove = hasAnItem(player, required.getId());
if (!itemToRemove.exists() && !player.hasItem(new Item(6914, 1))) {
player.sendMessage("You don't have the required wand in order to buy this upgrade.");
return;
}
}
if (container.getAmount(item) - 1 <= 0) {
container.get(slot).setAmount(0);
} else {
container.remove(item);
}
if (item.getId() == 6926) {
player.getSavedData().getActivityData().setBonesToPeaches(true);
player.getDialogueInterpreter().sendDialogue("The guardian teaches you how to use the Bones to Peaches spell!");
} else {
if (itemToRemove == null || itemToRemove.remove())
player.getInventory().add(item);
}
for (int i = 0; i < prices.length; i++) {
decrementPoints(player, i, prices[i]);
}
updatePoints(player);
update();
}
/**
* Values an item.
* @param player the player.
* @param item the item.
*/
public void value(Player player, Item item, int slot) {
int[] prices = PRICES[slot];
player.sendMessage("The " + item.getName() + " costs " + prices[0] + " Telekinetic, " + prices[1] + " Alchemist,");
player.sendMessage(prices[2] + " Enchantment and " + prices[3] + " Graveyard Pizazz Points.");
}
/**
* Updates the points.
* @param player the player.
*/
public void updatePoints(Player player) {
player.getPacketDispatch().sendString("" + getPoints(player, 0), 197, 8);// tele
player.getPacketDispatch().sendString("" + getPoints(player, 2), 197, 9);// enchant
player.getPacketDispatch().sendString("" + getPoints(player, 1), 197, 10);// alch
player.getPacketDispatch().sendString("" + getPoints(player, 3), 197, 11);// grave
}
/**
* Increments the pizazz points.
* @param player the player.
* @param index the index.
* @param increment the increment.
*/
public void incrementPoints(Player player, int index, int increment) {
player.getSavedData().getActivityData().incrementPizazz(index, increment);
}
/**
* Decrements the pizazz points.
* @param player the player.
* @param index the index.
* @param decrement the decrement.
*/
public void decrementPoints(Player player, int index, int decrement) {
player.getSavedData().getActivityData().decrementPizazz(index, decrement);
}
/**
* Gets the points.
* @param player the player.
* @param index the index.
* @return the points.
*/
public int getPoints(Player player, int index) {
return player.getSavedData().getActivityData().getPizazzPoints(index);
}
/**
* The mta shop plugin.
* @author Vexia
*/
public class MTAShopPlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
return null;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
Item item = container.get(slot);
if (item == null) {
return true;
}
if (opcode == 155) {
value(player, item, slot);
} else if (opcode == 196) {
buy(player, item, slot);
}
return true;
}
}
}
@@ -0,0 +1,216 @@
package content.minigame.mta;
import content.minigame.mta.impl.AlchemistZone;
import content.minigame.mta.impl.EnchantingZone;
import content.minigame.mta.impl.GraveyardZone;
import content.minigame.mta.impl.TelekineticZone;
import core.game.component.Component;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.map.Location;
import content.minigame.mta.impl.AlchemistZone;
import content.minigame.mta.impl.EnchantingZone;
import content.minigame.mta.impl.GraveyardZone;
import content.minigame.mta.impl.TelekineticZone;
/**
* A magic training arena game type.
* @author Vexia
*/
public enum MTAType {
TELEKINETIC(10778, new Component(198), null, Location.create(3363, 3316, 0), new TelekineticZone()) {
@Override
public boolean hasRequirement(Player player) {
if (!player.getSkills().hasLevel(Skills.MAGIC, 33)) {
player.getDialogueInterpreter().sendDialogue("You need to be able to cast the Telekinetic Grab spell in order to", "enter.");
return false;
}
return true;
}
},
ALCHEMISTS(10780, new Component(194), new Location(3366, 9623, 2), new Location(3363, 3320, 0), AlchemistZone.ZONE) {
@Override
public boolean hasRequirement(Player player) {
if (!player.getSkills().hasLevel(Skills.MAGIC, 21)) {
player.getDialogueInterpreter().sendDialogue("You need to be able to cast the Telekinetic Grab spell in order to", "enter.");
return false;
}
if (player.getInventory().contains(995, 1)) {
player.getDialogueInterpreter().sendDialogue("You cannot take money into the Alchemists' Playground.");
return false;
}
return true;
}
@Override
public void exit(Player player) {
int earn = player.getAttribute("alch-earn", 0);
if (earn != 0) {
Item coins = new Item(995, earn);
if (player.getBank().hasSpaceFor(coins)) {
player.getBank().add(coins);
}
player.getDialogueInterpreter().sendDialogue("You've been awarded " + earn + " coins straight into your bank as a reward!");
}
super.exit(player);
}
},
ENCHANTERS(10779, new Component(195), new Location(3363, 9649, 0), new Location(3361, 3318, 0), EnchantingZone.ZONE) {
@Override
public boolean hasRequirement(Player player) {
if (!player.getSkills().hasLevel(Skills.MAGIC, 7)) {
player.getDialogueInterpreter().sendDialogue("You need to be able to cast the Lvl-1 Enchant spell in order to", "enter.");
return false;
}
return true;
}
},
GRAVEYARD(10781, new Component(196), new Location(3363, 9639, 1), new Location(3365, 3318, 0), GraveyardZone.ZONE) {
@Override
public boolean hasRequirement(Player player) {
if (!player.getSkills().hasLevel(Skills.MAGIC, 15)) {
player.getDialogueInterpreter().sendDialogue("You need to be able to cast the Bones to Bananas spell in order to", "enter.");
return false;
}
if (player.getInventory().contains(1963, 1) || player.getInventory().contains(6883, 1)) {
player.getDialogueInterpreter().sendDialogue("You can't take bananas or peaches into the arena.");
return false;
}
return true;
}
};
/**
* The object id.
*/
private final int objectId;
/**
* The overlay component.
*/
private final Component overlay;
/**
* The start location.
*/
private final Location startLocation;
/**
* The end location.
*/
private final Location endLocation;
/**
* The mage training arena zone.
*/
private final MTAZone zone;
/**
* Constructs a new {@Code MTAType} {@Code Object}
* @param objectId the object id.
* @param overlay the overlay.
* @param zone the zone.
*/
private MTAType(int objectId, Component overlay, Location startLocation, Location endLocation, MTAZone zone) {
this.objectId = objectId;
this.overlay = overlay;
this.zone = zone;
this.startLocation = startLocation;
this.endLocation = endLocation;
}
/**
* Enters the mage training arena game.
* @param player the player.
*/
public void enter(Player player) {
if (!player.getSavedData().getActivityData().isStartedMta() || (!player.getInventory().containsItem(MageTrainingArenaPlugin.PROGRESS_HAT) && !player.getEquipment().containsItem(MageTrainingArenaPlugin.PROGRESS_HAT))) {
player.getDialogueInterpreter().sendDialogue("You need a Pizazz Progress Hat in order to enter. Talk to the", "Entrance Guardian if you don't have one.");
return;
}
if (!hasRequirement(player)) {
return;
}
if (this != TELEKINETIC) {
player.teleport(startLocation);
} else {
TelekineticZone.start(player);
}
player.sendMessage("You've entered the " + zone.getName() + ".");
}
/**
* Exits the zone area.
* @param player the player.
*/
public void exit(Player player) {
player.teleport(endLocation);
}
/**
* Checks if the player has the requirements.
* @param player the player.
* @return {@code True} if so.
*/
public boolean hasRequirement(Player player) {
return false;
}
/**
* Gets the mta type for the zone.
* @param mtaZone the zone.
* @return the type.
*/
public static MTAType forZone(MTAZone mtaZone) {
for (MTAType type : values()) {
if (type == null) {
continue;
}
if (type.getZone() == mtaZone) {
return type;
}
}
return TELEKINETIC;
}
/**
* Gets the mtat type.
* @param id the id.
* @return the mtat type.
*/
public static MTAType forId(int id) {
for (MTAType t : values()) {
if (t.getObjectId() == id) {
return t;
}
}
return null;
}
/**
* Gets the objectId.
* @return the objectId
*/
public int getObjectId() {
return objectId;
}
/**
* Gets the zone.
* @return the zone
*/
public MTAZone getZone() {
return zone;
}
/**
* Gets the overlay.
* @return the overlay
*/
public Component getOverlay() {
return overlay;
}
}
@@ -0,0 +1,167 @@
package content.minigame.mta;
import core.ServerConstants;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.request.RequestType;
import core.game.node.item.Item;
import core.game.world.map.Location;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneRestriction;
import core.game.world.map.zone.ZoneType;
/**
* Represents a magic training arena zone.
* @author Vexia
*/
public class MTAZone extends MapZone {
/**
* The items.
*/
private final Item[] items;
/**
* The mage training arena type.
*/
private MTAType type;
/**
* Constructs a new {@Code MTAZone} {@Code Object}
* @param name the name.
* @param items the items.
*/
public MTAZone(String name, Item[] items) {
super(name, false, ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.FOLLOWERS);
this.items = items;
this.setZoneType(ZoneType.SAFE.getId());
}
@Override
public boolean enter(Entity entity) {
if (entity instanceof Player) {
Player player = entity.asPlayer();
if (player == null) {
return true;
}
if (type == null) {
type = MTAType.forZone(this);
}
if (type != null) {
player.getInterfaceManager().openOverlay(type.getOverlay());
update(player);
}
player.getProperties().setSpawnLocation(new Location(3363, 3302, 0));
}
return super.enter(entity);
}
@Override
public boolean canRequest(RequestType type, Player player, Player target) {
player.getDialogueInterpreter().sendDialogue("You can't do that right now.");
return false;
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (e instanceof Player) {
if (target.getId() == 10782) {
getType().exit(e.asPlayer());
return true;
}
}
return super.interact(e, target, option);
}
@Override
public boolean teleport(Entity e, int type, Node node) {
if (e instanceof Player) {
if (type != -1) {
e.asPlayer().sendMessage("You can't teleport out of the training arena!");
return false;
}
}
return super.teleport(e, type, node);
}
@SuppressWarnings("deprecation")
@Override
public boolean leave(Entity entity, boolean logout) {
if (entity instanceof Player) {
Player player = entity.asPlayer();
if (logout) {
player.setLocation(new Location(3363, 3302, 0));
} else {
player.getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION);
}
cleanItems(player);
player.getInterfaceManager().closeOverlay();
}
return super.leave(entity, logout);
}
@Override
public void configure() {
}
/**
* Cleans the items.
*/
private void cleanItems(Player player) {
if (player == null) {
return;
}
for (Item item : items) {
if (item == null) {
continue;
}
if (player.getInventory().containsItem(item)) {
player.getInventory().remove(new Item(item.getId(), player.getInventory().getAmount(item)));
}
if (player.getEquipment().containsItem(item)) {
player.getEquipment().remove(new Item(item.getId(), player.getEquipment().getAmount(item)));
}
}
}
/**
* Increments the pizazz points of a player.
* @param player the player.
* @param index the index.
* @param amount the amount.
*/
public void incrementPoints(Player player, int index, int amount) {
player.getSavedData().getActivityData().incrementPizazz(index, amount);
update(player);
}
/**
* Updates the player.
* @param player the player.
*/
public void update(Player player) {
if (type == null) {
return;
}
player.getPacketDispatch().sendString("" + player.getSavedData().getActivityData().getPizazzPoints(type.ordinal()), type.getOverlay().getId(), 9);
}
/**
* Gets the items.
* @return the items
*/
public Item[] getItems() {
return items;
}
/**
* Gets the type.
* @return the type
*/
public MTAType getType() {
return type;
}
}
@@ -0,0 +1,126 @@
package content.minigame.mta;
import content.minigame.mta.impl.TelekineticZone;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.NPCDefinition;
import core.cache.def.impl.SceneryDefinition;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityHandler;
import core.game.node.item.GroundItem;
import core.game.node.item.Item;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneBuilder;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import content.minigame.mta.EnchantSpell;
import core.plugin.ClassScanner;
/**
* Handles the mage training area interactions.
* @author Vexia
*/
@Initializable
public class MageTrainingArenaPlugin extends OptionHandler {
/**
* The progress hat.
*/
public static final Item PROGRESS_HAT = new Item(6885);
/**
* The mage training arena shop.
*/
public static final MTAShop SHOP = new MTAShop();
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ItemDefinition.forId(6885).getHandlers().put("option:destroy", this);
ItemDefinition.forId(6885).getHandlers().put("option:talk-to", this);
SceneryDefinition.forId(10721).getHandlers().put("option:enter", this);
NPCDefinition.forId(3103).getHandlers().put("option:trade-with", this);
for (MTAType type : MTAType.values()) {
if (type.getZone() != null) {
ZoneBuilder.configure(type.getZone());
}
SceneryDefinition.forId(type.getObjectId()).getHandlers().put("option:enter", this);
}
ItemDefinition.forId(TelekineticZone.STATUE).getHandlers().put("option:observe", this);
ItemDefinition.forId(TelekineticZone.STATUE).getHandlers().put("option:reset", this);
NPCDefinition.forId(3102).getHandlers().put("option:talk-to", this);
ClassScanner.definePlugins(new CharmedWarriorDialogue(), new EntranceGuardianDialogue(), new RewardsGuardianDialogue(), new ProgressHatDialogue(), new EnchantmentGuardianDialogue(), new EnchantSpell(), new GraveyardGuardianDialogue(), new AlchemyGuardianDialogue(), new TelekineticGrabSpell(), new TelekineticGuardianDialogue(), new MazeGuardianDialogue());
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
switch (node.getId()) {
case 10721:
if (!player.getSkills().hasLevel(Skills.MAGIC, 7)) {
player.getDialogueInterpreter().sendDialogue("You need a Magic level of at least 7 to enter the guild.");
break;
}
AgilityHandler.walk(player, -1, player.getLocation(), player.getLocation().transform(Direction.getDirection(player.getLocation(), node.getLocation()), 2), new Animation(1426), 0.0, null);
break;
case 3103:
if (!player.getSavedData().getActivityData().isStartedMta()) {
player.getDialogueInterpreter().open(3103, this, true, true);
} else {
SHOP.open(player);
}
break;
case 6885:
player.getDialogueInterpreter().open(3096, option.equals("destroy") ? new Object[] { node, true, true } : new Object[] {});
break;
case 3102:
player.getDialogueInterpreter().open(node.getId(), node);
break;
}
switch (option) {
case "enter":
MTAType type = MTAType.forId(node.getId());
if (type != null) {
type.enter(player);
}
break;
case "reset":
case "observe":
TelekineticZone zone = TelekineticZone.getZone(player);
if (option.equals("reset")) {
zone.reset(player);
} else {
zone.observe(player);
}
break;
}
return true;
}
@Override
public boolean isWalk(Player player, Node n) {
if (!(n instanceof GroundItem)) {
return true;
}
if (n.getId() == TelekineticZone.STATUE) {
return false;
}
return true;
}
@Override
public Location getDestination(Node node, Node n) {
if (n.getId() == 3102) {
return n.getLocation().transform(Direction.getDirection(node.getLocation(), n.getLocation()), -1);
}
return null;
}
@Override
public boolean isWalk() {
return false;
}
}
@@ -0,0 +1,93 @@
package content.minigame.mta;
import content.minigame.mta.impl.TelekineticZone;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import content.minigame.mta.impl.TelekineticZone;
/**
* Handles the maze guardian dialogue.
* @author Vexia
*/
public class MazeGuardianDialogue extends DialoguePlugin {
/**
* Constructs a new {@code MazeGuardianDialogue} {@code Object}
*/
public MazeGuardianDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code MazeGuardianDialogue} {@code Object}
* @param player the player.
*/
public MazeGuardianDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new MazeGuardianDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
player("Hi!");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
npc("Well done on releasing me. Would you like to try", "another maze?");
stage++;
break;
case 1:
options("Yes please!", "No thanks.");
stage++;
break;
case 2:
switch (buttonId) {
case 1:
player("Yes please!");
stage = 5;
break;
case 2:
player("No thanks.");
stage++;
break;
}
break;
case 3:
npc("Very well. Talk to me if you want to move onto the", "next maze, or you can return to the entrance hall", "through the portal.");
stage++;
break;
case 4:
end();
break;
case 5:
npc("Very well, I shall teleport you.");
stage++;
break;
case 6:
npc.clear();
TelekineticZone.getZone(player).setUp();
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 3102 };
}
}
@@ -0,0 +1,117 @@
package content.minigame.mta;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
/**
* Handles the progress hat dialogue.
* @author Vexia
*/
public class ProgressHatDialogue extends DialoguePlugin {
/**
* The progress hat.
*/
private Item progressHat;
/**
* Constructs a new {@Code ProgressHatDialogue} {@Code Object}
*/
public ProgressHatDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@Code ProgressHatDialogue} {@Code Object}
* @param player the player.
*/
public ProgressHatDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ProgressHatDialogue(player);
}
@Override
public boolean open(Object... args) {
if (args.length > 1) {
progressHat = (Item) args[0];
npc("How dare you destroy me? You'll lose your Pizazz", "Points!");
stage = 50;
return true;
}
player("Mr Progress Hat... sir?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
npc("Can't you see I'm busy?");
stage++;
break;
case 1:
player("But you're just a hat? Can you tell me my Pizazz", "Point totals?");
stage++;
break;
case 2:
npc("Ok, I suppose it's my job. You have:", getPoints(0) + " Telekinetic, " + getPoints(1) + " Alchemist,", getPoints(2) + " Enchantment, and " + getPoints(3) + " Graveyard Pizazz Points.");
stage++;
break;
case 3:
player("Thank you!");
stage++;
break;
case 4:
end();
break;
case 50:
interpreter.sendOptions("Destroy Hat?", "Yes", "No");
stage++;
break;
case 51:
switch (buttonId) {
case 1:
if (progressHat == null) {
end();
return true;
}
if (!player.getInventory().containsItem(progressHat)) {
end();
return true;
}
player.getInventory().remove(progressHat);
interpreter.sendDialogue("The hat whispers as you destroy it. You can get another from the", "Entrance Guardian.");
stage = 4;
break;
case 2:
npc("I think so too!");
stage = 4;
break;
}
break;
}
return true;
}
/**
* Gets the pizzaz points.
* @param index the index.
* @return the points.
*/
public int getPoints(int index) {
return player.getSavedData().getActivityData().getPizazzPoints(index);
}
@Override
public int[] getIds() {
return new int[] { 3096 };
}
}

Some files were not shown because too many files have changed in this diff Show More