Redwings Drop III.5: Tutorial Island, Tribal Totem

This commit is contained in:
skelsoft
2022-03-19 22:54:15 +00:00
committed by Ceikry
parent 0b9d540d45
commit a4ca46d262
127 changed files with 4044 additions and 4167 deletions
+6 -4
View File
@@ -7,8 +7,6 @@ import core.game.container.impl.EquipmentContainer
import core.game.content.dialogue.FacialExpression
import core.game.content.global.action.SpecialLadders
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.game.node.entity.Entity
import core.game.node.entity.combat.ImpactHandler
import core.game.node.entity.impl.Animator
@@ -19,12 +17,15 @@ import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager
import core.game.node.entity.player.link.audio.Audio
import core.game.node.entity.player.link.emote.Emotes
import core.game.node.entity.player.link.quest.Quest
import core.game.node.entity.player.link.quest.QuestRepository
import core.game.node.entity.skill.Skills
import core.game.node.entity.skill.gather.SkillingTool
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.node.scenery.SceneryBuilder
import core.game.system.task.Pulse
import core.game.world.map.Direction
import core.game.world.map.Location
@@ -39,10 +40,10 @@ import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics
import rs09.game.content.dialogue.DialogueFile
import rs09.game.content.dialogue.SkillDialogueHandler
import rs09.game.content.global.GlobalKillCounter;
import rs09.game.content.global.GlobalKillCounter
import rs09.game.interaction.InteractionListeners
import rs09.game.system.SystemLogger
import rs09.game.system.config.ItemConfigParser;
import rs09.game.system.config.ItemConfigParser
import rs09.game.world.GameWorld
import rs09.game.world.GameWorld.Pulser
import rs09.game.world.repository.Repository
@@ -1289,6 +1290,7 @@ fun questStage(player: Player, quest: String): Int{
fun setQuestStage(player: Player, quest: String, stage: Int) {
player.questRepository.setStage(QuestRepository.getQuests()[quest]!!, stage)
player.questRepository.syncronizeTab(player)
}
/**
+3 -1
View File
@@ -8,4 +8,6 @@ data class ResourceGatheredEvent(val itemId: Int, val amount: Int, val source: N
data class NPCKillEvent(val npc: NPC) : Event
data class TeleportEvent(val type: TeleportType, val source: Int = -1) : Event
data class LitFireEvent(val logId: Int) : Event
data class InteractionEvent(val target: Node, val option: String) : Event
data class InteractionEvent(val target: Node, val option: String) : Event
data class ButtonClickedEvent(val iface: Int, val buttonId: Int) : Event
data class UsedWithEvent(val used: Int, val with: Int) : Event
@@ -169,8 +169,10 @@ class ServerConstants {
arrayOf(Location.create(2711, 10132, 0), "brine rats"),
arrayOf(Location.create(2328, 3677, 0), "piscatoris"),
arrayOf(Location.create(2660, 3158, 0), "fishing trawler", "trawler"),
arrayOf(Location.create(2800, 3667, 0), "mountain camp")
arrayOf(Location.create(2800, 3667, 0), "mountain camp"),
arrayOf(Location.create(2575, 3250, 0), "clocktower")
)
//arrayOf(Location.create(0, 0, 0), ""),
@JvmField
var DATABASE: Database? = null
@@ -8,4 +8,6 @@ object Event {
val Teleport = TeleportEvent::class.java
val FireLit = LitFireEvent::class.java
val Interaction = InteractionEvent::class.java
val ButtonClicked = ButtonClickedEvent::class.java
val UsedWith = UsedWithEvent::class.java
}
@@ -23,7 +23,7 @@ class WGuildListeners : InteractionListener() {
return@onEquip false
}
player.interfaceManager.hideTabs(2, 3, 5, 6, 7, 11, 12)
player.interfaceManager.removeTabs(2, 3, 5, 6, 7, 11, 12)
player.interfaceManager.openTab(4, Component(411))
player.interfaceManager.setViewedTab(4)
player.interfaceManager.open(Component(410))
@@ -1,5 +1,6 @@
package rs09.game.content.ame
import api.getAttribute
import core.game.node.entity.player.Player
import core.game.world.map.zone.ZoneRestriction
import core.tools.RandomFunction
@@ -17,7 +18,7 @@ class RandomEventManager(val player: Player) {
fun tick() {
if (player.isArtificial) return
if (GameWorld.ticks > nextSpawn) fireEvent()
if (GameWorld.ticks > nextSpawn && getAttribute(player, "tutorial:complete", false)) fireEvent()
}
fun fireEvent() {
@@ -55,7 +55,7 @@ class LostTribeCutscene(val pl: Player? = null) : CutscenePlugin("Lost Tribe Cut
override fun open() {
player.setAttribute("cutscene:original-loc",player.location)
player.setAttribute("real-end",Location.create(3207, 3221, 0))
player.interfaceManager.hideTabs(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)
player.interfaceManager.removeTabs(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)
if(player.settings.isRunToggled){
player.settings.toggleRun()
}
@@ -0,0 +1,163 @@
package rs09.game.content.quest.members.tribaltotem
import core.game.content.dialogue.book.BookLine
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.book.Book
import core.game.content.dialogue.book.Page
import core.game.content.dialogue.book.PageSet
import core.game.node.entity.player.Player
import core.plugin.Initializable
/**
* This was some code for a post-tutorial RSPS guide book a long ass
* time ago, but it was using the ID for the guide book for Tribal Totem
* and I kind of need that, bro
*
* @author Splinter
* @author Phil
*/
@Initializable
class ArdougneGuideBook : Book {
/**
* Constructs a new `ShieldofArravBook` `Object`.
*/
constructor(player: Player?) : super(player, "Ardougne Guide Book", 1856, *PAGES) {}
/**
* Constructs a new `ShieldofArravBook` `Object`.
*/
constructor() {
/**
* empty.
*/
}
override fun finish() {}
override fun display(set: Array<Page>) {
player.lock()
player.interfaceManager.open(getInterface())
player.packetDispatch.sendString("Previous", getInterface().id, 77)
player.packetDispatch.sendString("Next", getInterface().id, 78)
for (i in 55..76) {
player.packetDispatch.sendString("", getInterface().id, i)
}
player.packetDispatch.sendString(getName(), getInterface().id, 6)
for (page in set) {
for (line in page.lines) {
player.packetDispatch.sendString(line.message, getInterface().id, line.child)
}
}
val lastPage = index == sets.size - 1
if (lastPage) {
finish()
}
player.unlock()
}
override fun newInstance(player: Player): DialoguePlugin {
return ArdougneGuideBook(player)
}
override fun getIds(): IntArray {
return intArrayOf(ID)
}
companion object {
/**
* Represents the book id
*/
var ID = 387454
/**
* Represents the array of pages for this book.
*/
private val PAGES = arrayOf(
PageSet(
Page(
BookLine("Introduction", 57),
BookLine("This book is your guide to", 59),
BookLine("the vibrant city of Ardougne.", 60),
BookLine("Ardougne is known as an", 61),
BookLine("exciting modern city located", 62),
BookLine("on the sun drenched southern", 63),
BookLine("coast of Kandarin", 64),
),
Page(
BookLine("Ardougne: City of Shopping!", 66),
BookLine("Come sample the delights of", 67),
BookLine("the Ardougne market - the", 68),
BookLine("biggest in the known world!", 69),
BookLine("From spices to silk, there", 70),
BookLine("is something here for", 71),
BookLine("everybody! Other popular", 72),
BookLine("shopping destinations in", 73),
BookLine("the area include the Armoury", 74),
BookLine("and the ever popular", 75),
BookLine("Adventurers' supply store.", 76)
)
),
PageSet(
Page(
BookLine("Ardougne: City of Fun!", 55),
BookLine("If you're looking for", 56),
BookLine("entertainment in Ardougne,", 57),
BookLine("why not pay a visit to the", 58),
BookLine("Ardougne City zoo? Or relax", 59),
BookLine("with a drink in the ever", 60),
BookLine("popular Flying Horse Inn?", 61),
BookLine("And for the adventurous,", 62),
BookLine("there are always rats to be", 63),
BookLine("slaughtered in the expansive", 64),
BookLine("and vermin-ridden sewers", 65)
),
Page(
BookLine("There is something truly",66),
BookLine("for everybody here!",67)
)
),
PageSet(
Page(
BookLine("Ardougne: City of History!", 55),
BookLine("Ardougne is renowned as an", 56),
BookLine("important city of historical", 57),
BookLine("interest. One historic building", 58),
BookLine("is the magnificent Handelmort", 59),
BookLine("Mansion, currently owned by", 60),
BookLine("Lord Francis Kurt Handelmort.", 61),
BookLine("Also of historical interest is", 62),
BookLine("Ardougne Castle in the east of", 63),
BookLine("the city recently opened to the", 64),
BookLine("public. And of course the Holy", 65)
),
Page(
BookLine("Order of Paladins still wander",66),
BookLine("the streets of Ardougne, and",67),
BookLine("are often of interest to",68),
BookLine("tourists.",69)
)
),
PageSet(
Page(
BookLine("Further Fields", 55),
BookLine("", 56),
BookLine("The area surrounding Ardougne", 57),
BookLine("is also of great interest to", 58),
BookLine("the cultural tourist. If you", 59),
BookLine("want to go further afield, why", 60),
BookLine("not have a look at the ominous", 61),
BookLine("Pillars of Zanash, the", 62),
BookLine("mysterious marble pillars", 63),
BookLine("located just West of the city?", 64),
BookLine("Or perhaps the town of Brimhaven,", 65)
),
Page(
BookLine("on the exotic island of Karamja?", 66),
BookLine("It's only a short boat trip with", 67),
BookLine("regular transport leaving from", 68),
BookLine("Ardougne harbor at all times", 69),
BookLine("of the day, all year round.", 70)
)
)
)
}
}
@@ -0,0 +1,134 @@
package rs09.game.content.quest.members.tribaltotem
import api.findNPC
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.impl.Projectile
import core.game.node.entity.npc.NPC
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.game.world.update.flag.context.Graphics
import core.plugin.Initializable
import org.rs09.consts.NPCs
import rs09.game.content.global.travel.EssenceTeleport
import rs09.game.world.GameWorld
@Initializable
class CrompertyDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
npcl(FacialExpression.HAPPY,"Hello ${player.name}, I'm Cromperty. Sedridor has told me about you. As a wizard and an inventor he has aided me in my great invention!")
stage = 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> options("Two jobs? that's got to be tough","So what have you invented?","Can you teleport me to the Rune Essence?").also { stage++ }
1 ->when(buttonId){
1 -> playerl(FacialExpression.HAPPY,"Two jobs? That's got to be tough.").also { stage = 5 }
2 -> playerl(FacialExpression.ASKING,"So, what have you invented?").also { stage = 10 }
3 -> playerl(FacialExpression.HAPPY,"Can you teleport me to the Rune Essence?").also {
if(player.questRepository.isComplete("Rune Mysteries")){
EssenceTeleport.teleport(npc,player)
end()
}
else stage = 2
}
}
2 -> npcl(FacialExpression.THINKING,"I have no idea what you're talking about.")
5 -> npcl(FacialExpression.HAPPY,"Not when you combine them it isn't! Invent MAGIC things!").also { stage++ }
6 -> options("So what have you invented?","Well I shall leave you to your inventing").also { stage++ }
7 -> when(buttonId){
1 -> playerl(FacialExpression.ASKING,"So, what have you invented?").also { stage = 10 }
2 -> playerl(FacialExpression.HAPPY,"Well I shall leave you to your inventing").also { stage++ }
}
8 -> npcl(FacialExpression.HAPPY,"Thanks for dropping by! Stop again anytime!").also { stage = 1000 }
10 -> npcl(FacialExpression.HAPPY,"Ah! My latest invention is my patent pending teleportation block! It emits a low level magical signal,").also { stage++ }
11 -> npcl(FacialExpression.HAPPY,"that will allow me to locate it anywhere in the world, and teleport anything directly to it! I hope to revolutionize the entire teleportation system!").also { stage++ }
12 -> npcl(FacialExpression.HAPPY,"Don't you think I'm great? Uh, I mean it's great?").also { stage++ }
13 -> options("So where is the other block?","Can I be teleported please?").also { stage++ }
14 -> when(buttonId){
1 -> playerl(FacialExpression.ASKING,"So where is the other block?").also { stage = 15 }
2 -> playerl(FacialExpression.ASKING,"Can I be teleported please?").also { stage = 25 }
}
15 -> npcl(FacialExpression.THINKING,"Well...Hmm. I would guess somewhere between here and the Wizards' Tower in Misthalin.").also { stage++ }
16 -> npcl(FacialExpression.HAPPY,"All I know is that it hasn't got there yet as the wizards there would have contacted me.").also { stage++ }
17 -> npcl(FacialExpression.THINKING,"I'm using the GPDT for delivery. They assured me it would be delivered promptly.").also { stage++ }
18 -> playerl(FacialExpression.ASKING,"Who are the GPDT?").also { stage++ }
19 -> npcl(FacialExpression.HAPPY,"The Gielinor Parcel Delivery Team. They come very highly recommended.").also { stage++ }
20 -> npcl(FacialExpression.HAPPY,"Their motto is: \"We aim to deliver your stuff at some point after you have paid us!\"").also { stage = 1000 }
25 -> npcl(FacialExpression.HAPPY,"By all means! I'm afraid I can't give you any specifics as to where you will come out however. Presumably wherever the other block is located.").also { stage++ }
26 -> options("Yes, that sounds good. Teleport me!","That sounds dangerous. Leave me here.").also { stage++ }
27 -> when(buttonId){
1 -> playerl(FacialExpression.HAPPY,"Yes, that sounds good. Teleport me!").also { stage = 30 }
2 -> playerl(FacialExpression.THINKING,"That sounds dangerous. Leave me here.").also { stage++ }
}
28 -> npcl(FacialExpression.HAPPY,"As you wish.").also { stage = 1000 }
30 -> npcl(FacialExpression.HAPPY,"Okey dokey! Ready?").also {
stage = if(player.questRepository.hasStarted("Tribal Totem") && player.questRepository.getStage("Tribal Totem") < 50) {
35
}
else 31
}
31 -> npcl(FacialExpression.THINKING,"Hmmm... that's odd... I can't seem to get a signal...").also { stage++ }
32 -> playerl(FacialExpression.SAD,"Oh well, never mind.").also { stage = 1000 }
35 -> npcl(FacialExpression.HAPPY,"Okay, I got a signal. Get ready!").also {
TribalTotemTeleport(player, npc)
end()
}
1000 -> end()
}
return true
}
override fun newInstance(player: Player?): DialoguePlugin {
return CrompertyDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(844,NPCs.WIZARD_CROMPERTY_2328)
}
fun TribalTotemTeleport(player : Player, npc: NPC) {
val LOCATIONS = arrayOf(Location.create(2649, 3272, 0),Location.create(2642, 3321, 0))
npc.animate(Animation(437))
npc.faceTemporary(player, 1)
npc.graphics(Graphics(108))
player.lock()
player.audioManager.send(125)
Projectile.create(npc, player, 109).send()
npc.sendChat("Dipsolum sententa sententi!")
GameWorld.Pulser.submit(object : Pulse(1) {
var counter = 0
var delivered = player.questRepository.getStage("Tribal Totem") >= 25
override fun pulse(): Boolean {
when(counter++){
2 -> {
if(delivered) {
player.questRepository.getQuest("Tribal Totem").setStage(player,30)
player.properties.teleportLocation = LOCATIONS[1]
}
else player.properties.teleportLocation = LOCATIONS[0]
}
3 ->{
player.graphics(Graphics(110))
player.unlock()
return true
}
}
return false
}
})
}
}
@@ -0,0 +1,41 @@
package rs09.game.content.quest.members.tribaltotem
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.NPCs
@Initializable
class GPDTEmployeeDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any?): Boolean {
npcl(FacialExpression.HAPPY,"Welcome to G.P.D.T.!")
stage = if(player.questRepository.getStage("Tribal Totem") == 20){
5
}else 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> playerl(FacialExpression.HAPPY,"Thank you very much.").also { stage = 1000 }
5 -> playerl(FacialExpression.ASKING,"So, when are you going to deliver this crate?").also { stage++ }
6 -> npcl(FacialExpression.THINKING,"Well... I guess we could do it now...").also {
player.questRepository.getQuest("Tribal Totem").setStage(player,25)
stage = 1000
}
1000 -> end()
}
return true
}
override fun newInstance(player: Player?): DialoguePlugin {
return GPDTEmployeeDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.RPDT_EMPLOYEE_843)
}
}
@@ -0,0 +1,58 @@
package rs09.game.content.quest.members.tribaltotem
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.plugin.Initializable
@Initializable
class HoracioDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any?): Boolean {
if(player.questRepository.hasStarted("Tribal Totem")){
npcl(FacialExpression.HAPPY,"It's a fine day to be out in a garden, isn't it? ")
stage = 5
}
else{
npcl(FacialExpression.HAPPY,"It's a fine day to be out in a garden, isn't it? ")
stage = 0
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> playerl(FacialExpression.HAPPY,"Yes it's very nice.").also { stage++ }
1 -> npcl(FacialExpression.HAPPY,"Days like these make me glad to be alive!").also { stage = 1000 }
5 -> playerl(FacialExpression.ASKING,"So... who are you?").also { stage++ }
6 -> npcl(FacialExpression.HAPPY,"My name is Horacio Dobson. I'm a gardener to Lord Handlemort.").also { stage++ }
7 -> npcl(FacialExpression.HAPPY,"Take a look around this beautiful garden, all of this is my handiwork.").also { stage++ }
8 -> options("So... do you garden round the back too?","Do you need any help?").also { stage++ }
9 -> when(buttonId){
1 -> playerl(FacialExpression.THINKING,"So... do you garden round the back, too?").also { stage = 10 }
2 -> playerl(FacialExpression.ASKING,"Do you need any help?").also { stage = 20 }
}
10 -> npcl(FacialExpression.HAPPY,"That I do!").also { stage++ }
11 -> playerl(FacialExpression.ASKING,"Doesn't all of the security around the house get in your way then?").also { stage++ }
12 -> npcl(FacialExpression.HAPPY,"Ah. I'm used to all that. I have my keys, the guard dogs know me, and I know the combination to the door lock.").also { stage++ }
13 -> npcl(FacialExpression.HAPPY,"It's rather easy, it's his middle name.").also { stage++ }
14 -> playerl(FacialExpression.ASKING,"Whose middle name?").also { stage++ }
15 -> npcl(FacialExpression.ANNOYED,"Hum. I probably shouldn't have said that. Forget I mentioned it.").also { stage = 1000 }
20 -> npcl(FacialExpression.ANNOYED,"Trying to muscle in on my job, eh? I'm more than happy to do this all by myself!").also { stage = 1000 }
1000 -> end()
}
return true
}
override fun newInstance(player: Player?): DialoguePlugin {
return HoracioDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(845)
}
}
@@ -0,0 +1,82 @@
package rs09.game.content.quest.members.tribaltotem
import api.removeItem
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.Items
@Initializable
class KangaiMauDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any?): Boolean {
if(!player.questRepository.hasStarted("Tribal Totem")){
npcl(FacialExpression.HAPPY,"Hello. I'm Kangai Mau of the Rantuki Tribe.")
stage = 0
}
else if(player.inventory.containsAtLeastOneItem(Items.TOTEM_1857)){
npcl(FacialExpression.ASKING,"Have you got our totem back?")
stage = 35
}
else if(player.questRepository.hasStarted("Tribal Totem")){
npcl(FacialExpression.ASKING,"Have you got our totem back?")
stage = 30
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> options("And what are you doing here in Brimhaven?","I'm in search of adventure!","Who are the Rantuki tribe?").also { stage++ }
1 -> when(buttonId){
1 -> playerl(FacialExpression.ASKING,"And what are you doing here in Brimhaven?").also { stage = 5 }
2 -> playerl(FacialExpression.HAPPY,"I'm in search of adventure!").also { stage = 15 }
3 -> playerl(FacialExpression.ASKING,"Who are the Rantuki Tribe?").also { stage = 10 }
}
5 -> npcl(FacialExpression.HAPPY,"I'm looking for someone brave to go on important mission. Someone skilled in thievery and sneaking about.").also { stage++ }
6 -> npcl(FacialExpression.HAPPY,"I am told I can find such people in Brimhaven.").also { stage++ }
7 -> playerl(FacialExpression.HAPPY,"Yep. I have heard there are many of that type here.").also { stage++ }
8 -> npcl(FacialExpression.THINKING,"Let's hope I find them.").also { stage = 1000 }
10 -> npcl(FacialExpression.HAPPY,"A proud and noble tribe of Karamja.").also { stage++ }
11 -> npcl(FacialExpression.ANGRY,"But now we are few, as men come from across, steal our land, and settle on our hunting grounds").also { stage = 1000 }
15 -> npcl(FacialExpression.HAPPY,"Adventure is something I may be able to give. I need someone to go on a mission to the city of Ardougne.").also { stage++ }
16 -> npcl(FacialExpression.HAPPY,"There you will find the house of Lord Handlemort. In his house he has our tribal totem. We need it back.").also { stage++ }
17 -> playerl(FacialExpression.ASKING,"Why does he have it?").also { stage++ }
18 -> npcl(FacialExpression.ANGRY,"Lord Handlemort is an Ardougnese explorer which means he think he have the right to come to my tribal home,").also { stage++ }
19 -> npcl(FacialExpression.ANGRY,"steal our stuff and put in his private museum.").also { stage++ }
20 -> playerl(FacialExpression.THINKING,"How can I find Handlemoret's house? Ardougne IS a big place...").also { stage++ }
21 -> npcl(FacialExpression.ANNOYED,"I don't know Ardougne. You tell me.").also { stage++ }
22 -> playerl(FacialExpression.HAPPY,"Ok, I will get it back.").also {
player.questRepository.getQuest("Tribal Totem").start(player)
player.questRepository.getQuest("Tribal Totem").setStage(player, 10)
stage++
}
23 -> npcl(FacialExpression.HAPPY,"Best of luck with that adventurer").also { stage = 1000 }
30 -> playerl(FacialExpression.SAD,"Not yet, sorry.").also { stage = 1000 }
35 -> playerl(FacialExpression.HAPPY,"Yes I have.").also { stage++ }
36 -> npcl(FacialExpression.HAPPY,"You have??? Many thanks brave adventurer! Here, have some freshly cooked Karamjan fish, caught specially by my tribe.").also { stage++ }
37 -> sendDialogue("You hand over the totem").also {
removeItem(player,Items.TOTEM_1857)
player.questRepository.getQuest("Tribal Totem").finish(player)
stage = 1000
}
1000 -> end()
}
return true
}
override fun newInstance(player: Player?): DialoguePlugin {
return KangaiMauDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(846)
}
}
@@ -0,0 +1,207 @@
package rs09.game.content.quest.members.tribaltotem
import api.closeInterface
import api.sendMessage
import api.setInterfaceText
import core.game.world.map.Location
import rs09.game.interaction.InterfaceListener
class TTDoorCodeInterfaceListener : InterfaceListener() {
override fun defineListeners() {
val LETTERONEBACK = 10
val LETTERONEFORWARD = 11
val LETTERTWOBACK = 12
val LETTERTWOFORWARD = 13
val LETTERTHREEBACK = 14
val LETTERTHREEFORWARD = 15
val LETTERFOURBACK = 16
val LETTERFOURFORWARD = 17
val ENTER = 18
val DOORLOCKINTERFACE = 285
val LETTERS = arrayOf(
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z"
)
onOpen(DOORLOCKINTERFACE) { player, component ->
player.setAttribute("tt-letter-one", 0)
player.setAttribute("tt-letter-two", 0)
player.setAttribute("tt-letter-three", 0)
player.setAttribute("tt-letter-four", 0)
return@onOpen true
}
onClose(DOORLOCKINTERFACE) { player, component ->
player.removeAttribute("tt-letter-one")
player.removeAttribute("tt-letter-two")
player.removeAttribute("tt-letter-three")
player.removeAttribute("tt-letter-four")
return@onClose true
}
on(DOORLOCKINTERFACE) { player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
LETTERONEBACK -> {
if (player.getAttribute("tt-letter-one", 0) == 0) {
player.setAttribute("tt-letter-one", 25)
setInterfaceText(player, LETTERS[player.getAttribute("tt-letter-one", 0)], DOORLOCKINTERFACE, 6)
} else {
(player.incrementAttribute("tt-letter-one", -1))
setInterfaceText(player, LETTERS[player.getAttribute("tt-letter-one", 0)], DOORLOCKINTERFACE, 6)
}
}
LETTERONEFORWARD -> {
if (player.getAttribute("tt-letter-one", 0) == 25) {
player.setAttribute("tt-letter-one", 0)
setInterfaceText(player, LETTERS[player.getAttribute("tt-letter-one", 0)], DOORLOCKINTERFACE, 6)
} else {
(player.incrementAttribute("tt-letter-one", 1))
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-one", 0)],
DOORLOCKINTERFACE,
6
)
}
}
LETTERTWOBACK -> {
if (player.getAttribute("tt-letter-two", 0) == 0) {
player.setAttribute("tt-letter-two", 25)
setInterfaceText(player, LETTERS[player.getAttribute("tt-letter-two", 0)], DOORLOCKINTERFACE, 7)
} else {
(player.incrementAttribute("tt-letter-two", -1))
setInterfaceText(player, LETTERS[player.getAttribute("tt-letter-two", 0)], DOORLOCKINTERFACE, 7)
}
}
LETTERTWOFORWARD -> {
if (player.getAttribute("tt-letter-two", 0) == 25) {
player.setAttribute("tt-letter-two", 0)
setInterfaceText(player, LETTERS[player.getAttribute("tt-letter-two", 0)], DOORLOCKINTERFACE, 7)
} else {
(player.incrementAttribute("tt-letter-two", 1))
setInterfaceText(player, LETTERS[player.getAttribute("tt-letter-two", 0)], DOORLOCKINTERFACE, 7)
}
}
LETTERTHREEBACK -> {
if (player.getAttribute("tt-letter-three", 0) == 0) {
player.setAttribute("tt-letter-three", 25)
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-three", 0)],
DOORLOCKINTERFACE,
8
)
} else {
(player.incrementAttribute("tt-letter-three", -1))
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-three", 0)],
DOORLOCKINTERFACE,
8
)
}
}
LETTERTHREEFORWARD -> {
if (player.getAttribute("tt-letter-three", 0) == 25) {
player.setAttribute("tt-letter-three", 0)
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-three", 0)],
DOORLOCKINTERFACE,
8
)
} else {
(player.incrementAttribute("tt-letter-three", 1))
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-three", 0)],
DOORLOCKINTERFACE,
8
)
}
}
LETTERFOURBACK -> {
if (player.getAttribute("tt-letter-four", 0) == 0) {
player.setAttribute("tt-letter-four", 25)
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-four", 0)],
DOORLOCKINTERFACE,
9
)
} else {
(player.incrementAttribute("tt-letter-four", -1))
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-four", 0)],
DOORLOCKINTERFACE,
9
)
}
}
LETTERFOURFORWARD -> {
if (player.getAttribute("tt-letter-four", 0) == 25) {
player.setAttribute("tt-letter-four", 0)
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-four", 0)],
DOORLOCKINTERFACE,
9
)
} else {
(player.incrementAttribute("tt-letter-four", 1))
setInterfaceText(
player,
LETTERS[player.getAttribute("tt-letter-four", 0)],
DOORLOCKINTERFACE,
9
)
}
}
ENTER -> {
val letterOne = LETTERS[player.getAttribute("tt-letter-one", 0)]
val letterTwo = LETTERS[player.getAttribute("tt-letter-two", 0)]
val letterThree = LETTERS[player.getAttribute("tt-letter-three", 0)]
val letterFour = LETTERS[player.getAttribute("tt-letter-four", 0)]
if (letterOne == "K" && letterTwo == "U" && letterThree == "R" && letterFour == "T") {
player.setAttribute("/save:TT:DoorUnlocked",true)
sendMessage(player, "You hear a satisfying click, signifying that the door has been unlocked")
closeInterface(player)
}
else {
sendMessage(player,"You hear a satisfying click, and then a worrying thunk.")
sendMessage(player,"The floor opens up beneath you sending you plummeting down")
sendMessage(player,"to the sewers.")
player.teleport(Location.create(2641, 9721, 0))
closeInterface(player)
}
}
}
return@on true
}
}
}
@@ -0,0 +1,108 @@
package rs09.game.content.quest.members.tribaltotem
import api.*
import core.game.content.global.action.ClimbActionHandler
import core.game.content.global.action.DoorActionHandler
import core.game.node.entity.skill.Skills
import core.game.node.scenery.SceneryBuilder
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import rs09.game.interaction.InteractionListener
class TribalTotemListeners : InteractionListener(){
val frontDoor = 2706
val wizCrate = 2707
val realCrate = 2708
val label = Items.ADDRESS_LABEL_1858
val lockedDoor = 2705
val stairs = 2711
val closedChest = 2709
val openChest = 2710
override fun defineListeners() {
on(frontDoor, SCENERY,"Open"){ player, door ->
if(player.questRepository.getStage("Tribal Totem") >= 35){
DoorActionHandler.handleAutowalkDoor(player,door.asScenery())
}
sendMessage(player,"The door is locked shut.")
return@on true
}
on(realCrate, SCENERY,"Investigate"){ player, node ->
if(player.questRepository.getStage("Tribal Totem") in 1..19 && !player.inventory.containsAtLeastOneItem(Items.ADDRESS_LABEL_1858)){
sendDialogue(player,"There is a label on this crate. It says; To Lord Handelmort, Handelmort Mansion Ardogune.You carefully peel it off and take it.")
addItem(player,Items.ADDRESS_LABEL_1858,1)
}
else if(player.questRepository.getStage("Tribal Totem") in 1..19 && player.inventory.containsAtLeastOneItem(Items.ADDRESS_LABEL_1858)){
sendDialogue(player,"There was a label on this crate, but it's gone now since you took it!")
}
return@on true
}
on(wizCrate, SCENERY,"Investigate"){ player, node ->
sendDialogue(player,"There is a label on this crate: Senior Patents Clerk, Chamber of Invention, The Wizards' Tower, Misthalin. The crate is securely fastened shut and ready for delivery.")
return@on true
}
onUseWith(SCENERY,label,wizCrate){ player, used, with ->
sendDialogue(player,"You carefully place the delivery address label over the existing label, covering it completely.")
removeItem(player,label)
player.questRepository.getQuest("Tribal Totem").setStage(player,20)
return@onUseWith true
}
on(lockedDoor, SCENERY,"Open"){ player, node ->
if(player.getAttribute("TT:DoorUnlocked",false) == true){
DoorActionHandler.handleAutowalkDoor(player,node.asScenery())
}else{
openInterface(player,285)
}
return@on true
}
on(stairs,SCENERY,"Climb-up"){ player, node ->
if(player.getAttribute("TT:StairsChecked",false)){
ClimbActionHandler.climb(player, Animation(828), Location.create(2629, 3324, 1))
}
else{
sendMessage(player,"You set off a trap and the stairs give way under you, dropping you into the sewers.")
player.teleport(Location.create(2641, 9721, 0))
}
return@on true
}
on(stairs, SCENERY,"Investigate"){ player, node ->
if(player.getSkills().getStaticLevel(Skills.THIEVING) >= 21){
sendDialogue(player,"Your trained senses as a thief enable you to see that there is a trap in these stairs. You make a note of its location for future reference when using these stairs")
player.setAttribute("/save:TT:StairsChecked",true)
}else{
sendDialogue(player,"You don't see anything out of place on these stairs.")
}
return@on true
}
on(closedChest, SCENERY,"Open"){ player, node ->
SceneryBuilder.replace(node.asScenery(), node.asScenery().transform(2710))
return@on true
}
on(openChest,SCENERY,"Close"){ player, node ->
SceneryBuilder.replace(node.asScenery(), node.asScenery().transform(2709))
return@on true
}
on(openChest, SCENERY,"Search"){ player, node ->
if(!player.inventory.containsAtLeastOneItem(Items.TOTEM_1857)){
sendDialogue(player,"Inside the chest you find the tribal totem.")
addItem(player,Items.TOTEM_1857)
}
else{
sendDialogue(player,"Inside the chest you don't find anything because you already took the totem!")
}
return@on true
}
}
}
@@ -0,0 +1,79 @@
package rs09.game.content.quest.members.tribaltotem
import api.rewardXP
import core.game.content.quest.fremtrials.FremennikTrials
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.quest.Quest
import core.game.node.entity.skill.Skills
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.plugin.Initializable
import org.rs09.consts.Items
@Initializable
class TribalTotem : Quest("Tribal Totem",26,125,1,200,0,1,5){
class SkillRequirement(val skill: Int?, val level: Int?)
val requirements = arrayListOf<TribalTotem.SkillRequirement>()
override fun drawJournal(player: Player?, stage: Int) {
super.drawJournal(player, stage)
var line = 11
if(stage == 0){
line(player,"I can start this quest by speaking to !!Kangai Mau?? in",line++)
line(player,"!!Shrimp & Parrot?? restaurant in Brimhaven.",line++)
line += 1
line(player,"To complete this quest I need:",line++)
line(player,"!!Level 21 Theiving??",line++, player?.skills?.getStaticLevel(Skills.THIEVING)!! >= 21)
}
else{
if(stage >= 10){
line(player,"I agreed to help !!Kangai Mau?? on Brimhaven recover",line++,stage>15&&stage!=100)
line(player,"the tribal totem stolen from his village by",line++,stage>15&&stage!=100)
line(player,"!!Lord Handelmort??.",line++,stage>10)
}
if(stage >= 20){
line(player,"I found a package due for delivery to !!Lord Handelmort??",line++,stage>25&&stage!=100)
line(player,"at the !!G.P.D.T. Depot??, and swapped the label for the",line++,stage>25&&stage!=100)
line(player,"!!Wizard Cromperty's?? experimental teleport block.",line++,stage>25&&stage!=100)
}
if(stage >= 30){
line(player,"I got the !!G.P.D.T.?? men to deliver the teleport block to",line++,stage>35&&stage!=100)
line(player,"!!Lord Handelmort?? and teleported myself inside.",line++,stage>35&&stage!=100)
}
if(stage == 100){
line(player,"After bypassing the traps and security inside the mansion I was able",line++)
line(player,"to reclaim the totem, and take it back to !!Kangai Mau??, who rewarded",line++)
line(player,"me for all of my help.",line++)
}
}
}
override fun finish(player: Player?) {
super.finish(player)
player ?: return
var ln = 10
player.packetDispatch.sendItemZoomOnInterface(Items.TOTEM_1857,230,277,5)
drawReward(player,"1 Quest point",ln++)
drawReward(player,"1,775 Thieving XP",ln++)
drawReward(player,"5 Swordfish",ln++)
rewardXP(player,Skills.THIEVING,1775.0)
if(!player.inventory.add(Item(Items.SWORDFISH_373,5))){
GroundItemManager.create(Item(Items.SWORDFISH_373,5),player)
}
cleanTTAttributes(player)
}
override fun newInstance(`object`: Any?): Quest {
requirements.add(TribalTotem.SkillRequirement(Skills.THIEVING, 21))
return this
}
private fun cleanTTAttributes(player: Player){
player.removeAttribute("TT:StairsChecked")
player.removeAttribute("TT:DoorUnlocked")
}
}
@@ -0,0 +1,47 @@
package rs09.game.content.tutorial
import api.setAttribute
import api.teleport
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.plugin.Initializable
import org.rs09.consts.NPCs
/**
* Handles Skippy's skip tutorial dialogue
* @author Ceikry
*/
@Initializable
class SkipTutorialDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return SkipTutorialDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npcl(FacialExpression.FRIENDLY, "Hey, would you like to skip to the end? Choose wisely! This is the only time you get this choice.")
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> options("Yes, I'd like to skip the tutorial.", "No thanks.").also { stage++ }
1 -> when(buttonId)
{
1 -> {
end()
setAttribute(player, "/save:tutorial:stage", 71)
TutorialStage.load(player, 71)
teleport(player, Location.create(3141, 3089, 0))
}
2 -> end()
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.SKIPPY_2796)
}
}
@@ -0,0 +1,117 @@
package rs09.game.content.tutorial
import api.addItem
import api.inInventory
import api.setAttribute
import core.game.component.Component
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* Handles the survival expert's dialogue
* @author Ceikry
*/
@Initializable
class SurvivalExpertDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return SurvivalExpertDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
val tutStage = player?.getAttribute("tutorial:stage", 0) ?: 0
when(tutStage)
{
4 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"Hello there, newcomer. My name is Brynna. My job is",
"to teach you a few suvival tips and tricks. First off",
"we're going to start with the most basic skill of",
"all: making a fire."
)
)
11 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"Well done! Next we need to get some food in our",
"bellies. We'd need something to cook. There are shrimp",
"in the pond there. So let's catch and cook some."
)
)
5, 14, 15 -> {
if(!inInventory(player, Items.BRONZE_AXE_1351))
{
player.dialogueInterpreter.sendItemMessage(Items.BRONZE_AXE_1351, "The Survival Expert gives you a spare bronze axe.")
addItem(player, Items.BRONZE_AXE_1351)
}
if(!inInventory(player, Items.TINDERBOX_590))
{
player.dialogueInterpreter.sendItemMessage(Items.TINDERBOX_590, "The Survival Expert gives you a spare tinderbox.")
}
return false
}
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(player?.getAttribute("tutorial:stage", 0))
{
4 -> when(stage)
{
0 -> {
Component.setUnclosable(
player,
interpreter.sendDoubleItemMessage(
Items.TINDERBOX_590,
Items.BRONZE_AXE_1351,
"The Surivival Guide gives you a <col=08088A>tinderbox</col> and a <col=08088A>bronze axe</col>!"
)
)
addItem(player, Items.TINDERBOX_590)
addItem(player, Items.BRONZE_AXE_1351)
stage++
}
1 -> {
end()
setAttribute(player, "tutorial:stage", 5)
TutorialStage.load(player, 5)
}
}
11 -> when(stage){
0 -> {
Component.setUnclosable(
player,
interpreter.sendItemMessage(303, "The Survival Guide gives you a <col=08088A>net</col>!")
)
addItem(player, Items.SMALL_FISHING_NET_303)
stage++
}
1 -> {
end()
setAttribute(player, "tutorial:stage", 12)
TutorialStage.load(player, 12)
}
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.SURVIVAL_EXPERT_943)
}
}
@@ -0,0 +1,94 @@
package rs09.game.content.tutorial
import api.*
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* Handles the combat instructor's dialogue
* @author Ceikry
*/
@Initializable
class TutorialCombatInstructorDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialCombatInstructorDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
when(getAttribute(player, "tutorial:stage", 0))
{
44 -> playerl(FacialExpression.FRIENDLY, "Hi! My name's ${player.username}.")
47 -> npcl(FacialExpression.FRIENDLY, "Very good, but that little butter knife isn't going to protect you much. Here, take these.")
53 -> playerl(FacialExpression.FRIENDLY, "I did it! I killed a giant rat!")
54 -> {
player.dialogueInterpreter.sendDoubleItemMessage(Items.SHORTBOW_841, Items.BRONZE_ARROW_882, "The Combat Guide gives you some bronze arrows and a shortbow!")
if(!inInventory(player, Items.SHORTBOW_841) && !inEquipment(player, Items.SHORTBOW_841))
addItem(player, Items.SHORTBOW_841)
if(!inInventory(player, Items.BRONZE_ARROW_882) && !inEquipment(player, Items.BRONZE_ARROW_882))
addItem(player, Items.BRONZE_ARROW_882, 30)
}
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(getAttribute(player, "tutorial:stage", 0))
{
44 -> when(stage){
0 -> npcl(FacialExpression.ANGRY, "Do I look like I care? To me you're just another newcomer who thinks they're ready to fight.").also { stage++ }
1 -> npcl(FacialExpression.FRIENDLY, "I'm Vannaka, the greatest swordsman alive.").also { stage++ }
2 -> npcl(FacialExpression.FRIENDLY, "Let's get started by teaching you to wield a weapon.").also { stage++ }
3 -> {
end()
setAttribute(player, "tutorial:stage", 45)
TutorialStage.load(player, 45)
}
}
47 -> when(stage){
0 -> {
addItemOrDrop(player, Items.BRONZE_SWORD_1277)
addItemOrDrop(player, Items.WOODEN_SHIELD_1171)
sendDoubleItemDialogue(player, Items.BRONZE_SWORD_1277, Items.WOODEN_SHIELD_1171, "The Combat Guide gives you a bronze sword and a wooden shield!")
stage++
}
1 -> {
end()
setAttribute(player, "tutorial:stage", 48)
TutorialStage.load(player, 48)
}
}
53 -> when(stage){
0 -> npcl(FacialExpression.FRIENDLY, "I saw, ${player.username}. You seem better at this than I thought. Now that you have grasped basic swordplay, let's move on.").also { stage++ }
1 -> npcl(FacialExpression.FRIENDLY, "Let's try some ranged attacking, with this you can kill foes from a distance. Also, foes unable to reach you are as good as dead. You'll be able to attack the rats, without entering the pit.").also { stage++ }
2 -> {
sendDoubleItemDialogue(player, Items.SHORTBOW_841, Items.BRONZE_ARROW_882, "The Combat Guide gives you some bronze arrows and a shortbow!")
if(!inInventory(player, Items.SHORTBOW_841) && !inEquipment(player, Items.SHORTBOW_841))
addItem(player, Items.SHORTBOW_841)
if(!inInventory(player, Items.BRONZE_ARROW_882) && !inEquipment(player, Items.BRONZE_ARROW_882))
addItem(player, Items.BRONZE_ARROW_882, 30)
stage++
}
3 -> {
end()
setAttribute(player, "tutorial:stage", 54)
TutorialStage.load(player, 54)
}
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.COMBAT_INSTRUCTOR_944)
}
}
@@ -0,0 +1,327 @@
package rs09.game.content.tutorial
import api.events.*
import api.getAttribute
import api.setAttribute
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.node.entity.skill.fishing.FishingSpot
import core.game.node.entity.skill.gather.mining.MiningNode
import core.game.node.entity.skill.gather.woodcutting.WoodcuttingNode
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import rs09.game.system.SystemLogger
/**
* Event receivers for tutorial island
* @author Ceikry
*/
object TutorialButtonReceiver : EventHook<ButtonClickedEvent>
{
override fun process(entity: Entity, event: ButtonClickedEvent) {
if(entity !is Player) return
when(getAttribute(entity, "tutorial:stage", 0))
{
//character design interface, confirm button
0 -> if(event.iface == 771 && event.buttonId == 362) {
setAttribute(entity, "/save:tutorial:stage", 1)
TutorialStage.load(entity, 1)
}
//click settings tab SD: 548,24 HD: 746,52
1 -> if((event.iface == 548 && event.buttonId == 24) || (event.iface == 746 && event.buttonId == 52)) {
setAttribute(entity, "/save:tutorial:stage", 2)
TutorialStage.load(entity, 2)
}
//click inventory tab SD: 548,41 HD: 746,44
5 -> if((event.iface == 548 && event.buttonId == 41) || (event.iface == 746 && event.buttonId == 44)) {
setAttribute(entity, "tutorial:stage", 6)
TutorialStage.load(entity, 6)
}
//Click skills tab SD: 548,39 HD: 746,42
10 -> if((event.iface == 548 && event.buttonId == 39) || (event.iface == 746 && event.buttonId == 42)) {
setAttribute(entity, "tutorial:stage", 11)
TutorialStage.load(entity, 11)
}
//Click music tab SD: 548,26 HD: 746,54
21 -> if((event.iface == 548 && event.buttonId == 26) || (event.iface == 746 && event.buttonId == 54)) {
setAttribute(entity, "tutorial:stage", 22)
TutorialStage.load(entity, 22)
}
//Click emote tab SD: 548,25 HD: 746,53
23 -> if((event.iface == 548 && event.buttonId == 25) || (event.iface == 746 && event.buttonId == 53)){
setAttribute(entity, "tutorial:stage", 24)
TutorialStage.load(entity, 24)
}
//Click any emote
24 -> if(event.iface == 464){
setAttribute(entity, "tutorial:stage", 25)
TutorialStage.load(entity, 25)
}
//click run button
25 -> if(event.iface == 261 && event.buttonId == 3){
setAttribute(entity, "tutorial:stage", 26)
TutorialStage.load(entity, 26)
}
//Open quest journal tab SD:548,40 HD:746,43
27 -> if((event.iface == 548 && event.buttonId == 40) || (event.iface == 746 && event.buttonId == 43)){
setAttribute(entity, "tutorial:stage", 28)
TutorialStage.load(entity, 28)
}
//Open equipment tab SD:548,42 HD:746,45
45 -> if((event.iface == 548 && event.buttonId == 42) || (event.iface == 746 && event.buttonId == 45)){
setAttribute(entity, "tutorial:stage", 46)
TutorialStage.load(entity, 46)
}
//Open weapon interface SD:548,38 HD:746,41
49 -> if((event.iface == 548 && event.buttonId == 38) || (event.iface == 746 && event.buttonId == 41)) {
setAttribute(entity, "tutorial:stage", 50)
TutorialStage.load(entity, 50)
}
//Open prayer interface SD:548,43 HD:746,46
61 -> if((event.iface == 548 && event.buttonId == 43) || (event.iface == 746 && event.buttonId == 46)){
setAttribute(entity, "tutorial:stage", 62)
TutorialStage.load(entity, 62)
}
//Open friends tab SD:548,21 HD:746,49
63 -> if((event.iface == 548 && event.buttonId == 21) || (event.iface == 746 && event.buttonId == 49)){
setAttribute(entity, "tutorial:stage", 64)
TutorialStage.load(entity, 64)
}
//Open ignore list tab SD:548,22 HD:746,50
64 -> if((event.iface == 548 && event.buttonId == 22) || (event.iface == 746 && event.buttonId == 50)){
setAttribute(entity, "tutorial:stage", 65)
TutorialStage.load(entity, 65)
}
//Open magic tab SD:548,44 HD:746,47
68 -> if((event.iface == 548 && event.buttonId == 44) || (event.iface == 746 && event.buttonId == 47)){
setAttribute(entity, "tutorial:stage", 69)
TutorialStage.load(entity, 69)
}
}
}
}
object TutorialInteractionReceiver : EventHook<InteractionEvent>
{
override fun process(entity: Entity, event: InteractionEvent) {
if(entity !is Player) return
when(getAttribute(entity, "tutorial:stage", 0))
{
//Click on tree and start chopping
6 -> if((WoodcuttingNode.forId(event.target.id)?.identifier ?: -1) == 1.toByte())
{
setAttribute(entity, "tutorial:stage", 7)
TutorialStage.load(entity, 7)
}
//Click on fishing spot to start fishing
12 -> if(FishingSpot.forId(event.target.id) != null)
{
setAttribute(entity, "tutorial:stage", 13)
TutorialStage.load(entity, 13)
}
//Prospect rock - Tin
31 -> if(MiningNode.forId(event.target.id).identifier == 2.toByte() && event.option == "prospect"){
setAttribute(entity, "tutorial:stage", 32)
TutorialStage.load(entity, 32)
}
//Prospect rock- Copper
33 -> if(MiningNode.forId(event.target.id).identifier == 1.toByte() && event.option == "prospect"){
setAttribute(entity, "tutorial:stage", 34)
TutorialStage.load(entity, 34)
}
//Mine rock - Tin
35 -> if(MiningNode.forId(event.target.id).identifier == 2.toByte() && event.option == "mine"){
setAttribute(entity, "tutorial:stage", 36)
TutorialStage.load(entity, 36)
}
//Equip bronze dagger
46 -> if(event.target.id == Items.BRONZE_DAGGER_1205 && event.option == "equip"){
setAttribute(entity, "tutorial:stage", 47)
TutorialStage.load(entity, 47)
}
//Equip sword and shield
48 -> {
if(event.target.id == Items.BRONZE_SWORD_1277 && event.option == "equip"){
setAttribute(entity, "/save:tutorial:sword", true)
}
else if(event.target.id == Items.WOODEN_SHIELD_1171 && event.option == "equip"){
setAttribute(entity, "/save:tutorial:shield", true)
}
if(getAttribute(entity, "tutorial:shield",false) && getAttribute(entity, "tutorial:sword",false))
{
setAttribute(entity, "tutorial:stage", 49)
TutorialStage.load(entity, 49)
}
}
//Attack rat
51 -> if(event.target.id == NPCs.GIANT_RAT_86 && event.option == "attack") {
setAttribute(entity, "tutorial:stage", 52)
TutorialStage.load(entity, 52)
}
//Open bank
56 -> if(event.target.name.contains("booth", true) && event.option == "use"){
setAttribute(entity, "tutorial:stage", 57)
TutorialStage.load(entity, 57)
}
}
}
}
object TutorialResourceReceiver : EventHook<ResourceGatheredEvent>
{
override fun process(entity: Entity, event: ResourceGatheredEvent) {
if(entity !is Player) return
when(getAttribute(entity, "tutorial:stage", 0))
{
//Gather some logs
7 -> if(event.itemId == Items.LOGS_1511)
{
setAttribute(entity, "tutorial:stage", 8)
TutorialStage.load(entity, 8)
}
//Catch some raw shrimp
13 -> if(event.itemId == Items.RAW_SHRIMPS_317)
{
setAttribute(entity, "tutorial:stage", 14)
TutorialStage.load(entity, 14)
}
//Cook a shrimp
14,15 -> if(event.itemId == Items.BURNT_SHRIMP_7954)
{
setAttribute(entity, "tutorial:stage", 15)
TutorialStage.load(entity, 15)
}
else if(event.itemId == Items.SHRIMPS_315)
{
setAttribute(entity, "tutorial:stage", 16)
TutorialStage.load(entity, 16)
}
//Make some bread dough
19 -> if(event.itemId == Items.BREAD_DOUGH_2307) {
setAttribute(entity, "tutorial:stage", 20)
TutorialStage.load(entity, 20)
}
//Bake some bread
20 -> if(event.itemId == Items.BREAD_2309 || event.itemId == Items.BURNT_BREAD_2311) {
setAttribute(entity, "tutorial:stage", 21)
TutorialStage.load(entity, 21)
}
//Mine some tin ore
36 -> if(event.itemId == Items.TIN_ORE_438){
setAttribute(entity, "tutorial:stage", 37)
TutorialStage.load(entity, 37)
}
//Mine some copper ore
37 -> if(event.itemId == Items.COPPER_ORE_436){
setAttribute(entity, "tutorial:stage", 38)
TutorialStage.load(entity, 38)
}
//Make a bronze bar
38 -> if(event.itemId == Items.BRONZE_BAR_2349){
setAttribute(entity, "tutorial:stage", 40)
TutorialStage.load(entity, 40)
}
//Make a bronze dagger
42 -> if(event.itemId == Items.BRONZE_DAGGER_1205){
setAttribute(entity, "tutorial:stage", 43)
TutorialStage.load(entity, 43)
}
}
}
}
object TutorialFireReceiver : EventHook<LitFireEvent>
{
override fun process(entity: Entity, event: LitFireEvent) {
if(entity !is Player) return
when(getAttribute(entity, "tutorial:stage", 0))
{
9 -> {
setAttribute(entity, "tutorial:stage", 10)
TutorialStage.load(entity, 10)
}
}
}
}
object TutorialUseWithReceiver : EventHook<UsedWithEvent>
{
override fun process(entity: Entity, event: UsedWithEvent) {
if(entity !is Player) return
when(getAttribute(entity, "tutorial:stage", 0))
{
//Start lighting a fire
8 -> if(event.used == Items.TINDERBOX_590 && event.with == Items.LOGS_1511) {
setAttribute(entity, "tutorial:stage", 9)
TutorialStage.load(entity, 9)
}
//Use bar on anvil
41 -> if(event.used == Items.BRONZE_BAR_2349 && event.with == 2783) {
setAttribute(entity, "tutorial:stage", 42)
TutorialStage.load(entity, 42)
}
}
}
}
object TutorialKillReceiver : EventHook<NPCKillEvent>
{
override fun process(entity: Entity, event: NPCKillEvent) {
if(entity !is Player) return
when(getAttribute(entity, "tutorial:stage", 0))
{
52 -> if(event.npc.id == NPCs.GIANT_RAT_86){
setAttribute(entity, "tutorial:stage", 53)
TutorialStage.load(entity, 53)
}
54 -> if(event.npc.id == NPCs.GIANT_RAT_86){
setAttribute(entity, "tutorial:stage", 55)
TutorialStage.load(entity, 55)
}
70 -> if(event.npc.id == NPCs.CHICKEN_41){
setAttribute(entity, "tutorial:stage", 71)
TutorialStage.load(entity, 71)
}
}
}
}
@@ -0,0 +1,59 @@
package rs09.game.content.tutorial
import api.getAttribute
import api.setAttribute
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.NPCs
import rs09.game.world.GameWorld.settings
/**
* Handles the finance tutor's dialogue
* @author Ceikry
*/
@Initializable
class TutorialFinanceAdvisorDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialFinanceAdvisorDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
when(getAttribute(player, "tutorial:stage", 0))
{
58 -> playerl(FacialExpression.FRIENDLY, "Hello, who are you?")
59 -> npcl(FacialExpression.FRIENDLY, "Move along, now.").also { return false }
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(getAttribute(player, "tutorial:stage", 0)){
58 -> when(stage++){
0 -> npcl(FacialExpression.FRIENDLY, "I'm the Financial Advisor. I'm here to tell people how to make money.")
1 -> playerl(FacialExpression.FRIENDLY, "Okay. How can I make money then?")
2 -> npcl(FacialExpression.HALF_THINKING, "How you can make money? Quite.")
3 -> npcl(FacialExpression.FRIENDLY, "Well there are three basic ways of making money here: combat, quests, and trading. I will talk you through each of them very quickly.")
4 -> npcl(FacialExpression.FRIENDLY, "Let's start with combat as it is probably still fresh in your mind. Many enemies, both human and monster will drop items when they die.")
5 -> npcl(FacialExpression.FRIENDLY, "Now, the next way to earn money quickly is by quests. Many people on " + settings!!.name + " have things they need doing, which they will reward you for.")
6 -> npcl(FacialExpression.FRIENDLY, "By getting a high level in skills such as Cooking, Mining, Smithing or Fishing, you can create or catch your own items and sell them for pure profit.")
7 -> npcl(FacialExpression.FRIENDLY, "Lastly, we have jobs you can get from tutors in Lumbridge. These pay very handsomely early on!").also { stage++ }
8 -> npcl(FacialExpression.FRIENDLY, "Well, that about covers it. Move along now.")
9 -> {
end()
setAttribute(player, "tutorial:stage", 59)
TutorialStage.load(player, 59)
}
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.FINANCIAL_ADVISOR_947)
}
}
@@ -0,0 +1,152 @@
package rs09.game.content.tutorial
import api.*
import core.game.content.dialogue.FacialExpression
import core.game.content.global.action.ClimbActionHandler
import core.game.content.global.action.DoorActionHandler
import core.game.node.scenery.Scenery
import core.game.world.map.Location
import org.rs09.consts.NPCs
import rs09.game.interaction.InteractionListener
/**
* Handles tutorial-specific node interactions
* @author Ceikry
*/
class TutorialListeners : InteractionListener() {
val GUIDE_HOUSE_DOOR = 3014
val COOKS_DOOR = 3017
val COOKS_EXIT = 3018
val QUEST_ENTER = 3019
val QUEST_LADDER = 3029
val COMBAT_EXIT = 3030
val BANK_EXIT = 3024
val FINANCE_EXIT = 3025
val CHURCH_EXIT = 3026
val FIRST_GATE = intArrayOf(3015,3016)
val COMBAT_GATES = intArrayOf(3020,3021)
val RAT_GATES = intArrayOf(3022, 3023)
override fun defineListeners() {
on(GUIDE_HOUSE_DOOR, SCENERY, "open"){player, door ->
if(getAttribute(player, "tutorial:stage", 0) != 3)
return@on true
setAttribute(player, "tutorial:stage", 4)
TutorialStage.load(player, 4)
DoorActionHandler.handleAutowalkDoor(player, door as Scenery, Location.create(3098, 3107, 0))
return@on true
}
on(FIRST_GATE, SCENERY, "open"){player, gate ->
if(getAttribute(player, "tutorial:stage", 0) != 16)
return@on true
setAttribute(player, "tutorial:stage", 17)
TutorialStage.load(player, 17)
DoorActionHandler.handleAutowalkDoor(player, gate as Scenery)
return@on true
}
on(COOKS_DOOR, SCENERY, "open"){player, door ->
if(getAttribute(player, "tutorial:stage", 0) != 17)
return@on true
setAttribute(player, "tutorial:stage", 18)
TutorialStage.load(player, 18)
DoorActionHandler.handleAutowalkDoor(player, door as Scenery)
return@on true
}
on(COOKS_EXIT, SCENERY, "open"){player, door ->
if(getAttribute(player, "tutorial:stage", 0) != 22)
return@on true
setAttribute(player, "tutorial:stage", 23)
TutorialStage.load(player, 23)
DoorActionHandler.handleAutowalkDoor(player, door as Scenery)
return@on true
}
on(QUEST_ENTER, SCENERY, "open") {player, door ->
if(getAttribute(player, "tutorial:stage", 0) != 26)
return@on true
setAttribute(player, "tutorial:stage", 27)
TutorialStage.load(player, 27)
DoorActionHandler.handleAutowalkDoor(player, door as Scenery)
return@on true
}
on(QUEST_LADDER, SCENERY, "climb-down") {player, ladder ->
if(getAttribute(player, "tutorial:stage", 0) != 29)
return@on true
setAttribute(player, "tutorial:stage", 30)
TutorialStage.load(player, 30)
ClimbActionHandler.climbLadder(player, ladder.asScenery(), "climb-down")
}
on(COMBAT_GATES, SCENERY, "open"){player, gate ->
if(getAttribute(player, "tutorial:stage", 0) != 43)
return@on true
setAttribute(player, "tutorial:stage", 44)
TutorialStage.load(player, 44)
DoorActionHandler.handleAutowalkDoor(player, gate as Scenery)
}
on(RAT_GATES, SCENERY, "open") {player, gate ->
val stage = getAttribute(player, "tutorial:stage", 0)
if(stage !in 50..53){
player.dialogueInterpreter.sendDialogues(NPCs.COMBAT_INSTRUCTOR_944, FacialExpression.ANGRY, "Oi, get away from there!","Don't enter my rat pen unless I say so!")
return@on true
}
if(stage == 50) {
setAttribute(player, "tutorial:stage", 51)
TutorialStage.load(player, 51)
}
DoorActionHandler.handleAutowalkDoor(player, gate as Scenery)
return@on true
}
on(COMBAT_EXIT, SCENERY, "climb-up") {player, ladder ->
if(getAttribute(player, "tutorial:stage", 0) != 55)
return@on true
setAttribute(player, "tutorial:stage", 56)
TutorialStage.load(player, 56)
ClimbActionHandler.climbLadder(player, ladder.asScenery(), "climb-up")
}
on(BANK_EXIT, SCENERY, "open") {player, door ->
if(getAttribute(player, "tutorial:stage", 0) != 57)
return@on true
setAttribute(player, "tutorial:stage", 58)
TutorialStage.load(player, 58)
DoorActionHandler.handleAutowalkDoor(player, door as Scenery)
}
on(FINANCE_EXIT, SCENERY, "open") {player,door ->
if(getAttribute(player, "tutorial:stage", 0) != 59)
return@on true
setAttribute(player, "tutorial:stage", 60)
TutorialStage.load(player, 60)
DoorActionHandler.handleAutowalkDoor(player, door as Scenery)
}
on(CHURCH_EXIT, SCENERY, "open") {player, door ->
if(getAttribute(player, "tutorial:stage", 0) != 66)
return@on true
setAttribute(player, "tutorial:stage", 67)
TutorialStage.load(player, 67)
DoorActionHandler.handleAutowalkDoor(player, door as Scenery)
}
}
}
@@ -0,0 +1,28 @@
package rs09.game.content.tutorial
import api.*
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import rs09.game.world.GameWorld
/**
* Login listener that checks for tutorial completion and loads the current tutorial stage
* @author Ceikry
*/
class TutorialLoginCheck : LoginListener {
override fun login(player: Player) {
if(!getAttribute(player, "tutorial:complete", false)) {
//Disable need to do tutorial for anyone who has already started their account (gained levels or using it as a mule)
if(getAttribute(player, "tutorial:stage", 0) == 0 && (player.skills.totalLevel > 33 || player.bank.itemCount() > 0 || player.inventory.itemCount() > 0)){
setAttribute(player, "/save:tutorial:complete", true)
return
}
GameWorld.Pulser.submit(object : Pulse() {
override fun pulse(): Boolean {
TutorialStage.load(player, getAttribute(player, "tutorial:stage", 0), true)
return true
}
})
}
}
}
@@ -0,0 +1,177 @@
package rs09.game.content.tutorial
import api.*
import core.game.component.Component
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.InterfaceManager
import core.game.node.entity.player.link.IronmanMode
import core.game.node.entity.player.link.TeleportManager
import core.game.node.item.Item
import core.game.world.map.Location
import core.net.amsc.MSPacketRepository
import core.net.amsc.WorldCommunicator
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import rs09.game.world.GameWorld
import rs09.tools.END_DIALOGUE
/**
* Handles the magic tutor's dialogue
* @author Ceikry
*/
@Initializable
class TutorialMagicTutorDialogue(player: Player? = null) : DialoguePlugin(player) {
private val STARTER_PACK = arrayOf(
Item(1351, 1),
Item(590, 1),
Item(303, 1),
Item(315, 1),
Item(1925, 1),
Item(1931, 1),
Item(2309, 1),
Item(1265, 1),
Item(1205, 1),
Item(1277, 1),
Item(1171, 1),
Item(841, 1),
Item(882, 25),
Item(556, 25),
Item(558, 15),
Item(555, 6),
Item(557, 4),
Item(559, 2)
)
private val STARTER_BANK = arrayOf(Item(995, 25))
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialMagicTutorDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
when(getAttribute(player, "tutorial:stage", 0))
{
67 -> playerl(FacialExpression.FRIENDLY, "Hello.")
69 -> npcl(FacialExpression.FRIENDLY, "Good. This is a list of your spells. Currently you can only cast one offensive spell called Wind Strike. Let's try it out on one of those chickens.")
70 -> if(!inInventory(player, Items.AIR_RUNE_556) && !inInventory(player, Items.MIND_RUNE_558))
{
player.dialogueInterpreter.sendDoubleItemMessage(Items.AIR_RUNE_556, Items.MIND_RUNE_558, "You receive some spare runes.")
addItem(player, Items.AIR_RUNE_556, 15)
addItem(player, Items.MIND_RUNE_558, 15)
return false
}
71 -> npcl(FacialExpression.FRIENDLY, "Alright, last thing. Are you interested in being an ironman or changing your experience rate?")
else -> return false
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(getAttribute(player, "tutorial:stage", 0))
{
67 -> when(stage++){
0 -> npcl(FacialExpression.FRIENDLY, "Good day, newcomer. My name is Terrova. I'm here to tell you about Magic. Let's start by opening your spell list.")
1 -> {
end()
setAttribute(player, "tutorial:stage", 68)
TutorialStage.load(player, 68)
}
}
69 -> when(stage++){
0 -> {
sendDoubleItemDialogue(player, Items.AIR_RUNE_556, Items.MIND_RUNE_558, "Terrova gives you 15 air runes and 15 mind runes!")
addItemOrDrop(player, Items.AIR_RUNE_556, 5)
addItemOrDrop(player, Items.MIND_RUNE_558, 5)
}
1 -> {
end()
setAttribute(player, "tutorial:stage", 70)
TutorialStage.load(player, 70)
}
}
71 -> when(stage){
0 -> options("Set Ironman Mode (current: ${player.ironmanManager.mode.name})", "Change XP Rate (current: ${player.skills.experienceMutiplier}x)", "I'm ready now.").also { stage++ }
1 -> when(buttonId){
1 -> options("None","Standard","Hardcore (Permadeath!)","Ultimate","Nevermind.").also { stage = 10 }
2 -> options("1.0x","2.5x","5.0x","10x","20x").also { stage = 20 }
3 -> npcl(FacialExpression.FRIENDLY, "Well, you're all finished here now. I'll give you a reasonable number of starting items when you leave.").also { stage = 30 }
}
10 -> {
val mode = IronmanMode.values()[buttonId - 1]
player.dialogueInterpreter.sendDialogue("You set your ironman mode to: ${mode.name}.")
player.ironmanManager.mode = mode
stage = 0
}
20 -> {
val rates = arrayOf(1.0,2.5,5.0,10.0,20.0)
val rate = rates[buttonId - 1]
player.dialogueInterpreter.sendDialogue("You set your XP rate to: ${rate}x.")
player.skills.experienceMutiplier = rate
stage = 0
}
30 -> player.dialogueInterpreter.sendOptions("Leave Tutorial Island?", "Yes, I'm ready.", "No, not yet.").also { stage++ }
31 -> when(buttonId)
{
1 -> playerl(FacialExpression.FRIENDLY, "I'm ready to go now, thank you.").also { stage = 40 }
2 -> playerl(FacialExpression.FRIENDLY, "I'm not quite ready to go yet, thank you.").also { stage = END_DIALOGUE }
}
40 -> {
setAttribute(player, "/save:tutorial:complete", true)
setVarbit(player, 1021, 0, 0)
teleport(player, Location.create(3233, 3230), TeleportManager.TeleportType.NORMAL)
closeOverlay(player)
player.inventory.clear()
player.bank.clear()
player.equipment.clear()
player.interfaceManager.restoreTabs()
player.interfaceManager.setViewedTab(3)
player.inventory.add(*STARTER_PACK)
player.bank.add(*STARTER_BANK)
//This overwrites the stuck dialogue after teleporting to Lumbridge for some reason
//Dialogue from 2007 or thereabouts
//Original is five lines, but if the same is done here it will break. Need to find another way of showing all this information.
interpreter.sendDialogue(
"Welcome to Lumbridge! To get more help, simply click on the",
"Lumbridge Guide or one of the Tutors - these can be found by looking",
"for the question mark icon on your mini-map. If you find you are lost",
"at any time, look for a signpost or use the Lumbridge Home Port Spell."
)
stage = 12
player.unlock()
if(WorldCommunicator.isEnabled())
MSPacketRepository.sendInfoUpdate(player)
TutorialStage.removeHintIcon(player)
player.unhook(TutorialKillReceiver)
player.unhook(TutorialFireReceiver)
player.unhook(TutorialResourceReceiver)
player.unhook(TutorialUseWithReceiver)
player.unhook(TutorialInteractionReceiver)
player.unhook(TutorialButtonReceiver)
}
12 -> {
player.setAttribute("close_c_", true)
end()
sendMessage(player, "Welcome to ${GameWorld.settings!!.name}.")
}
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.MAGIC_INSTRUCTOR_946)
}
}
@@ -0,0 +1,120 @@
package rs09.game.content.tutorial
import api.*
import core.game.component.Component
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* Handles the cooking tutor's dialogue
* @author Ceikry
*/
@Initializable
class TutorialMasterChefDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialMasterChefDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
when(getAttribute(player, "tutorial:stage", 0))
{
18 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"Ahh! Welcome, newcomer. I am the Master Chef, Lev. It",
"is here I will teach you how to cook food truly fit for a",
"king."
)
)
19,20 -> {
if(!inInventory(player, Items.BREAD_DOUGH_2307))
{
if(!inInventory(player, Items.BUCKET_OF_WATER_1929))
{
sendItemDialogue(player, Items.BUCKET_OF_WATER_1929, "The Master Chef gives you another bucket of water.")
addItem(player, Items.BUCKET_OF_WATER_1929)
return false
}
if(!inInventory(player, Items.POT_OF_FLOUR_1933))
{
sendItemDialogue(player, Items.POT_OF_FLOUR_1933, "The Master Chef gives you another pot of flour.")
addItem(player, Items.POT_OF_FLOUR_1933)
return false
}
}
return false
}
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(getAttribute(player, "tutorial:stage", 0))
{
18 -> when(stage)
{
0 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
player,
FacialExpression.HALF_GUILTY,
"I already know how to cook. Brynna taught me just",
"now."
)
).also { stage++ }
1 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.LAUGH,
"Hahahahahaha! You call THAT cooking? Some shrimp",
"on an open log fire? Oh, no, no no. I am going to",
"teach you the fine art of cooking bread."
)
).also { stage++ }
2 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"And no fine meal is complete without good music, so",
"we'll cover that while you're here too."
)
).also { stage++ }
3 -> {
Component.setUnclosable(
player,
interpreter.sendDoubleItemMessage(
Items.BUCKET_OF_WATER_1929,
Items.POT_OF_FLOUR_1933,
"The Cooking Guide gives you a <col=08088A>bucket of water<col> and a <col=08088A>pot of flour</col>."
)
)
addItem(player, Items.BUCKET_OF_WATER_1929)
addItem(player, Items.POT_OF_FLOUR_1933)
stage++
}
4 -> {
end()
setAttribute(player, "tutorial:stage", 19)
TutorialStage.load(player, 19)
}
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.MASTER_CHEF_942)
}
}
@@ -0,0 +1,106 @@
package rs09.game.content.tutorial
import api.addItem
import api.getAttribute
import api.inInventory
import api.setAttribute
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* Handles the mining tutor's dialogue
* @author Ceikry
*/
@Initializable
class TutorialMiningInstructorDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialMiningInstructorDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
when(getAttribute(player, "tutorial:stage", 0)) {
30 -> npcl(FacialExpression.FRIENDLY, "Hi there. You must be new around here. So what do I call you? 'Newcomer' seems so impersonal, and if we're going to be working together, I'd rather call you by name.")
34 -> playerl(FacialExpression.FRIENDLY, "I prospected both types of rock! One set contains tin and the other has copper ore inside.")
35 -> {
if(!inInventory(player, Items.BRONZE_PICKAXE_1265)) {
addItem(player, Items.BRONZE_PICKAXE_1265)
player.dialogueInterpreter.sendItemMessage(Items.BRONZE_PICKAXE_1265, "Dezzick gives you a bronze pickaxe!")
stage = 3
}
else {
TutorialStage.load(player, 35)
}
}
40 -> playerl(FacialExpression.ASKING, "How do I make a weapon out of this?")
41 -> {
if(!inInventory(player, Items.HAMMER_2347)) {
addItem(player, Items.HAMMER_2347)
player.dialogueInterpreter.sendItemMessage(Items.HAMMER_2347, "Dezzick gives you a hammer!")
stage = 3
}
else
{
end()
TutorialStage.load(player, 41)
}
}
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(getAttribute(player, "tutorial:stage", 0)) {
30 -> when(stage) {
0 -> playerl(FacialExpression.FRIENDLY, "You can call me ${player.username}.").also { stage++ }
1 -> npcl(FacialExpression.FRIENDLY, "Ok then, ${player.username}. My name is Dezzick and I'm a miner by Trade. Let's prospect some of these rocks.").also { stage++ }
2 -> {
end()
setAttribute(player, "tutorial:stage", 31)
TutorialStage.load(player, 31)
}
}
34 -> when(stage) {
0 -> npcl(FacialExpression.FRIENDLY, "Absolutely right, ${player.username}. These two ore types can be smelted together to make bronze.").also { stage++ }
1 -> npcl(FacialExpression.FRIENDLY, "So now you know what ore is in the rocks over there, why don't you have a go at mining some tin and copper? Here, you'll need this to start with.").also { stage++ }
2 -> {
addItem(player, Items.BRONZE_PICKAXE_1265)
player.dialogueInterpreter.sendItemMessage(Items.BRONZE_PICKAXE_1265, "Dezzick gives you a bronze pickaxe!")
stage++
}
3 -> {
end()
setAttribute(player, "tutorial:stage", 35)
TutorialStage.load(player, 35)
}
}
40 -> when(stage){
0 -> npcl(FacialExpression.FRIENDLY, "Okay, I'll show you how to make a dagger out of it. You'll be needing this..").also { stage++ }
1 -> {
addItem(player, Items.HAMMER_2347)
player.dialogueInterpreter.sendItemMessage(Items.HAMMER_2347, "Drezzick gives you a hammer!")
stage++
}
2 -> {
end()
setAttribute(player, "tutorial:stage", 41)
TutorialStage.load(player, 41)
}
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.MINING_INSTRUCTOR_948)
}
}
@@ -0,0 +1,68 @@
package rs09.game.content.tutorial
import api.getAttribute
import api.setAttribute
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.NPCs
/**
* Handles the prayer guide's dialogue
* @author Ceikry
*/
@Initializable
class TutorialPrayerDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialPrayerDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
when(getAttribute(player, "tutorial:stage", 0))
{
60 -> npcl(FacialExpression.FRIENDLY, "Greetings! I'd just like to briefly go over two topics with you: prayer, and friends.")
62 -> npcl(FacialExpression.FRIENDLY, "Prayers have all sorts of wonderful benefits! From boosting defence and damage, to protecting you from outside damage, to saving items on death!")
65 -> npcl(FacialExpression.FRIENDLY, "For your friend and ignore lists, it's quite simple really! Use your friend list to keep track of players who you like, and ignore those you don't!")
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(getAttribute(player, "tutorial:stage", 0))
{
60 -> when(stage++){
0 -> playerl(FacialExpression.FRIENDLY, "Alright, sounds fun!")
1 -> npcl(FacialExpression.FRIENDLY, "Right, so first thing: prayer. Prayer is trained by offering bones to the gods, and can grant you many boons!")
2 -> {
end()
setAttribute(player, "tutorial:stage", 61)
TutorialStage.load(player, 61)
}
}
62 -> when(stage++){
0 -> playerl(FacialExpression.AMAZED, "Very cool!")
1 -> npcl(FacialExpression.FRIENDLY, "Next up, let's talk about friends.")
2 -> {
end()
setAttribute(player, "tutorial:stage", 63)
TutorialStage.load(player, 63)
}
}
65 -> {
end()
setAttribute(player, "tutorial:stage", 66)
TutorialStage.load(player, 66)
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.BROTHER_BRACE_954)
}
}
@@ -0,0 +1,121 @@
package rs09.game.content.tutorial
import api.getAttribute
import api.setAttribute
import api.setVarbit
import core.game.component.Component
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.Components
import org.rs09.consts.NPCs
/**
* Handles the quest guide's dialogue
* @author Ceikry
*/
@Initializable
class TutorialQuestGuideDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialQuestGuideDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
when(getAttribute(player, "tutorial:stage", 0))
{
27 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"Ah. Welcome adventurer. I'm here to tell you all about",
"quests. Lets start by opening the Quest list."
)
)
28 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"Now you have the journal open. I'll tell you a bit about",
"it At the moment all the quests are shown in red. Which",
"means you have not started them yet."
)
)
else -> return false
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(getAttribute(player, "tutorial:stage", 0))
{
27 -> {
Component.setUnclosable(
player,
interpreter.sendPlaneMessageWithBlueTitle(
"Open the Quest Journal.",
"",
"Click on the flashing icon next to your inventory.",
"",
""
)
)
setVarbit(player, 1021, 0, 3)
player.interfaceManager.openTab(Component(Components.QUESTJOURNAL_V2_274))
}
28 -> when(stage)
{
0 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"When you start a quest it will change colour to yellow,",
"and to green when you've finished. This is so you can",
"easily see what's complete, what's started and what's left",
"to begin."
)
).also { stage++ }
1 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"The start of quests are easy to find. Look out for the",
"star icons on the minimap, just like the one you should",
"see marking my house."
)
).also { stage++ }
2 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"There's not a lot more I can tell you about questing.",
"You have to experience the thrill of it yourself to fully",
"understand. You may find some adevnture in the caves",
"under my house."
)
).also { stage++ }
3 -> {
end()
setAttribute(player, "tutorial:stage", 29)
TutorialStage.load(player, 29)
}
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.QUEST_GUIDE_949)
}
}
@@ -0,0 +1,134 @@
package rs09.game.content.tutorial
import api.setAttribute
import core.game.component.Component
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.NPCs
/**
* Handles the RuneSccape guide's dialogue
* @author Ceikry
*/
@Initializable
class TutorialRSGuideDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return TutorialRSGuideDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
npc = args[0] as NPC
val tutStage = player?.getAttribute("tutorial:stage", 0) ?: 0
if(tutStage < 2) {
Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.HALF_GUILTY,
"Greetings! Please follow the onscreen",
"instructions!"
)
)
return false
}
if(tutStage == 2)
{
Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.HALF_GUILTY,
"Greetings! I see you are a new arrival to this land. My",
"job is to welcome all new visitors. So welcome!"
)
)
stage = 0
return true
}
else
{
Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.HALF_GUILTY,
"Please follow the onscreen instructions!"
)
)
return false
}
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage)
{
0 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"You have already learned the first thing needed to",
"succeed in this world: talking to other people!"
)
).also { stage++ }
1 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"You will find many inhabitants of this world have useful",
"things to say to you. By clicking on them with your",
"mouse you can talk to them."
)
).also { stage++ }
2 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"I would also suggest reading through some of the",
"supporting information on the website. There you can",
"find the starter guides, which contain all the",
"additional information you're ever likely to need. they also"
)
).also { stage++ }
3 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"contain helpful tips to help you on your",
"journey."
)
).also { stage++ }
4 -> Component.setUnclosable(
player,
interpreter.sendDialogues(
npc,
FacialExpression.FRIENDLY,
"To continue the tutorial go through that door over",
"there and speak to your first instructor!"
)
).also { stage++ }
5 -> {
end()
setAttribute(player, "tutorial:stage", 3)
TutorialStage.load(player, 3)
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.RUNESCAPE_GUIDE_945)
}
}
File diff suppressed because it is too large Load Diff
@@ -56,6 +56,8 @@ object GrandExchange : CallBack {
for(offer in buyOffers)
processOffer(offer)
stmt.close()
Thread.sleep(15_000) //sleep for 15 seconds
}
}.start()
@@ -102,6 +104,7 @@ object GrandExchange : CallBack {
SystemLogger.logGE("Purchased FROM BOT ${offer.amountLeft - before}x ${getItemName(offer.itemID)}")
}
}
sellStmt.close()
}
}
@@ -142,6 +145,7 @@ object GrandExchange : CallBack {
bestPrice = o.offeredValue
}
stmt.close()
stmt = conn.createStatement()
val bot_offers = stmt.executeQuery("SELECT * from bot_offers where item_id = $itemID")
if(bot_offers.next())
@@ -174,6 +178,7 @@ object GrandExchange : CallBack {
sb.append("</col>Highest Offer: <col=FFFFFF>$bestPrice</col>")
}
stmt.close()
return sb.toString()
}
@@ -269,6 +274,7 @@ object GrandExchange : CallBack {
val o = GrandExchangeOffer.fromQuery(results)
offers.add(o)
}
stmt.close()
return offers
}
@@ -284,6 +290,7 @@ object GrandExchange : CallBack {
val o = GrandExchangeOffer.fromBotQuery(results)
offers.add(o)
}
stmt.close()
return offers
}
@@ -102,6 +102,7 @@ class GrandExchangeOffer() {
stmt.setInt(1, amountLeft)
stmt.setInt(2, itemID)
stmt.executeUpdate()
stmt.close()
}
else
{
@@ -113,6 +114,7 @@ class GrandExchangeOffer() {
stmt.setInt(5, index)
stmt.setLong(6, uid)
stmt.executeUpdate()
stmt.close()
}
}
@@ -134,6 +136,7 @@ class GrandExchangeOffer() {
}
else
stmt.executeUpdate("INSERT INTO bot_offers(item_id,amount) values($itemID,$amount)")
stmt.close()
}
else
{
@@ -143,6 +146,7 @@ class GrandExchangeOffer() {
val nowuid = stmt.executeQuery("SELECT last_insert_rowid()")
uid = nowuid.getLong(1)
visualize(player)
stmt.close()
}
}
@@ -83,7 +83,7 @@ class GrandExchangeRecords(private val player: Player) {
}
}
}
SystemLogger.logInfo(sb.toString())
stmt.close()
}
fun getOffer(index: Int) : GrandExchangeOffer?
@@ -102,8 +102,10 @@ class GrandExchangeRecords(private val player: Player) {
{
val offer = GrandExchangeOffer.fromQuery(offer_raw)
offer.index = record.slot
stmt.close()
return offer
}
stmt.close()
return null
}
@@ -152,6 +154,7 @@ class GrandExchangeRecords(private val player: Player) {
else
offerRecords[offer.index] = OfferRecord(offer.uid, offer.index)
}
stmt.close()
if (needsIndex.isNotEmpty()) {
for ((index, offer) in offerRecords.withIndex()) {
@@ -1,6 +1,7 @@
package rs09.game.interaction
import api.events.InteractionEvent
import api.events.UsedWithEvent
import core.game.interaction.DestinationFlag
import core.game.interaction.MovementPulse
import core.game.interaction.Option
@@ -148,6 +149,7 @@ object InteractionListeners {
@JvmStatic
fun run(id: Int, player: Player, node: Node, isEquip: Boolean): Boolean{
player.dispatch(InteractionEvent(node, if(isEquip) "equip" else "unequip"))
if(isEquip){
return equipListeners["equip:$id"]?.invoke(player,node) ?: true
} else {
@@ -168,6 +170,7 @@ object InteractionListeners {
var flipped = false
val method = get(used.id,with.id,type) ?: get(with.id,used.id,type).also { flipped = true } ?: return false
val destOverride = if(flipped) {
getOverride(type, used.id, "use") ?: getOverride(type, with.id) ?: getOverride(type, "use")
} else {
@@ -183,12 +186,16 @@ object InteractionListeners {
return true
}
player.faceLocation(with.location)
if(flipped) player.dispatch(UsedWithEvent(with.id, used.id))
else player.dispatch(UsedWithEvent(used.id, with.id))
if(flipped) method.invoke(player,with,used)
else method.invoke(player,used,with)
return true
}
})
} else {
if(flipped) player.dispatch(UsedWithEvent(with.id, used.id))
else player.dispatch(UsedWithEvent(used.id, with.id))
if(flipped) method.invoke(player,with,used)
else method.invoke(player,used,with)
}
@@ -211,20 +218,27 @@ object InteractionListeners {
player.setAttribute("interact:option", option)
if(option.toLowerCase() == "attack") //Attack needs special handling >.>
{
player.dispatch(InteractionEvent(node, option.toLowerCase()))
method.invoke(player, node)
return true
}
if(type != 0) {
if(player.locks.isMovementLocked) return false
player.pulseManager.run(object : MovementPulse(player, node, flag, destOverride) {
override fun pulse(): Boolean {
if(player.zoneMonitor.interact(node, Option(option, 0))) return true
player.faceLocation(node.location)
player.dispatch(InteractionEvent(node, option))
player.dispatch(InteractionEvent(node, option.toLowerCase()))
method.invoke(player,node)
return true
}
})
} else {
method.invoke(player,node)
player.dispatch(InteractionEvent(node, option))
player.dispatch(InteractionEvent(node, option.toLowerCase()))
}
return true
}
@@ -3,7 +3,6 @@ package rs09.game.interaction.inter
import api.*
import core.game.component.CloseEvent
import core.game.component.Component
import core.game.content.quest.tutorials.tutorialisland.TutorialSession
import core.game.node.entity.combat.equipment.WeaponInterface
import core.game.node.entity.combat.equipment.WeaponInterface.WeaponInterfaces
import core.game.node.entity.player.Player
@@ -59,13 +58,11 @@ class MainGameInterface : InterfaceListener() {
)
}
38 -> {
if (TutorialSession.getExtension(player).stage > TutorialSession.MAX_STAGE) {
if (player.getExtension<Any>(WeaponInterface::class.java) === WeaponInterfaces.STAFF) {
val c = Component(WeaponInterfaces.STAFF.interfaceId)
player.interfaceManager.openTab(0, c)
val inter = player.getExtension<WeaponInterface>(WeaponInterface::class.java)
inter.updateInterface()
}
if (player.getExtension<Any>(WeaponInterface::class.java) === WeaponInterfaces.STAFF) {
val c = Component(WeaponInterfaces.STAFF.interfaceId)
player.interfaceManager.openTab(0, c)
val inter = player.getExtension<WeaponInterface>(WeaponInterface::class.java)
inter.updateInterface()
}
}
40 -> player.questRepository.syncronizeTab(player)
@@ -116,7 +116,7 @@ class CanoeInterfaceListeners : InterfaceListener() {
}
2 -> {
PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 2))
player.interfaceManager.hideTabs(0, 1, 2, 3, 4, 5, 6, 11, 12)
player.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 11, 12)
}
travelAnimDur+1 -> {
player.properties.teleportLocation = dest
@@ -1,9 +1,5 @@
package rs09.game.node.entity.combat.handlers
import core.game.container.Container
import core.game.container.impl.EquipmentContainer
import core.game.content.quest.tutorials.tutorialisland.TutorialSession
import core.game.content.quest.tutorials.tutorialisland.TutorialStage
import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState
import core.game.node.entity.combat.CombatStyle
@@ -130,17 +126,6 @@ open class MagicSwingHandler
}
override fun visualizeImpact(entity: Entity?, victim: Entity?, state: BattleState?) {
if (entity is Player) {
if (TutorialSession.getExtension(entity as Player?).stage == 51) {
TutorialStage.load(entity as Player?, 52, false)
}
if (TutorialSession.getExtension(entity as Player?).stage == 52) {
TutorialStage.load(entity as Player?, 53, false)
}
if (TutorialSession.getExtension(entity as Player?).stage == 54) {
TutorialStage.load(entity as Player?, 55, false)
}
}
if (state!!.targets == null) {
if (state.spell != null) {
state.spell.visualizeImpact(entity, victim, state)
@@ -3,8 +3,6 @@ package rs09.game.node.entity.combat.handlers
import api.*
import api.EquipmentSlot
import core.game.container.impl.EquipmentContainer
import core.game.content.quest.tutorials.tutorialisland.TutorialSession
import core.game.content.quest.tutorials.tutorialisland.TutorialStage
import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState
import core.game.node.entity.combat.CombatStyle
@@ -107,14 +105,6 @@ open class MeleeSwingHandler
}
override fun visualizeImpact(entity: Entity?, victim: Entity?, state: BattleState?) {
if (entity is Player) {
if (TutorialSession.getExtension(entity as Player?).stage == 51) {
TutorialStage.load(entity as Player?, 52, false)
}
if (TutorialSession.getExtension(entity as Player?).stage == 54) {
TutorialStage.load(entity as Player?, 55, false)
}
}
victim!!.animate(victim.properties.defenceAnimation)
}
@@ -1,10 +1,6 @@
package rs09.game.node.entity.combat.handlers
import api.EquipmentSlot
import core.game.container.Container
import core.game.container.impl.EquipmentContainer
import core.game.content.quest.tutorials.tutorialisland.TutorialSession
import core.game.content.quest.tutorials.tutorialisland.TutorialStage
import core.game.node.entity.Entity
import core.game.node.entity.combat.BattleState
import core.game.node.entity.combat.CombatStyle
@@ -46,11 +42,6 @@ open class RangeSwingHandler
if (!isProjectileClipped(entity, victim, false)) {
return InteractionType.NO_INTERACT
}
if (entity.getAttribute("tut-island", false)) {
if (TutorialSession.getExtension(entity as Player).stage == 70) {
return InteractionType.NO_INTERACT
}
}
var distance = 7
if (entity is Player && (entity.getExtension<Any>(WeaponInterface::class.java) as WeaponInterface).weaponInterface.interfaceId == 91) {
distance -= 2
@@ -177,14 +168,6 @@ open class RangeSwingHandler
state.ammunition.effect.impact(state)
}
val hit = state.estimatedHit
if (entity is Player) {
if (TutorialSession.getExtension(entity as Player?).stage == 51) {
TutorialStage.load(entity as Player?, 52, false)
}
if (TutorialSession.getExtension(entity as Player?).stage == 52) {
TutorialStage.load(entity as Player?, 53, false)
}
}
victim!!.impactHandler.handleImpact(entity, hit, CombatStyle.RANGE, state)
if (state.secondaryHit > -1) {
val hitt = state.secondaryHit
@@ -0,0 +1,22 @@
package rs09.game.node.entity.skill
import core.game.node.entity.combat.CombatStyle
import rs09.game.interaction.InteractionListener
class AttackListener : InteractionListener() {
override fun defineListeners() {
on(NPC, "attack"){player, npc ->
//Makes sure player uses correct attack styles for lumbridge dummies
if (npc.id == 4474 && player.getSwingHandler(false).type != CombatStyle.MAGIC) {
player.sendMessage("You can only attack this with magic.")
return@on true
}
if (npc.id == 7891 && player.getSwingHandler(false).type != CombatStyle.MELEE) {
player.sendMessage("You must use the training sword to attack this.")
return@on true
}
player.attack(npc)
return@on true
}
}
}
@@ -0,0 +1,42 @@
package rs09.game.node.entity.skill.cooking
import api.*
import api.events.ResourceGatheredEvent
import core.game.node.item.Item
import org.rs09.consts.Items
import rs09.game.content.dialogue.DialogueFile
import rs09.game.interaction.InteractionListener
class DoughMakingListener : InteractionListener() {
val sourceReturnMap = hashMapOf(
Items.BUCKET_OF_WATER_1929 to Items.BUCKET_1925,
Items.BOWL_OF_WATER_1921 to Items.BOWL_1923,
Items.JUG_OF_WATER_1937 to Items.JUG_1935
)
override fun defineListeners() {
onUseWith(ITEM, sourceReturnMap.keys.toIntArray(), Items.POT_OF_FLOUR_1933){player, used, with ->
openDialogue(player, DoughMakeDialogue(used.asItem(), with.asItem()))
return@onUseWith true
}
}
private class DoughMakeDialogue(val used: Item, val with: Item) : DialogueFile()
{
val products = intArrayOf(Items.BREAD_DOUGH_2307, Items.PASTRY_DOUGH_1953, Items.PIZZA_BASE_2283, Items.PITTA_DOUGH_1863)
override fun handle(componentID: Int, buttonID: Int) {
when(stage)
{
0 -> player!!.dialogueInterpreter.sendOptions("What do you wish to make?", "Bread dough.", "Pastry dough.", "Pizza dough.", "Pitta dough.").also { stage++ }
1 -> runTask(player!!, 1){
end()
if(removeItem(player!!, used) && removeItem(player!!, with)){
addItem(player!!, products[buttonID - 1])
player!!.dispatch(ResourceGatheredEvent(products[buttonID - 1], 1, player!!))
sendMessage(player!!, "You mix the flower and the water to make some ${getItemName(products[buttonID - 1]).toLowerCase()}.")
}
}
}
}
}
}
@@ -2,12 +2,8 @@ package rs09.game.node.entity.skill.gather.fishing
import api.events.ResourceGatheredEvent
import core.game.content.global.SkillingPets
import core.game.content.quest.tutorials.tutorialisland.TutorialSession
import core.game.content.quest.tutorials.tutorialisland.TutorialStage
import core.game.container.Container
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.player.link.skillertasks.SkillTasks
import core.game.node.entity.skill.SkillPulse
import core.game.node.entity.skill.Skills
@@ -44,9 +40,6 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption?
private val location: Location = npc.location
override fun start() {
if (TutorialSession.getExtension(player).stage == 12) {
TutorialStage.load(player, 13, false)
}
if (player.familiarManager.hasFamiliar() && player.familiarManager.familiar is Forager) {
val forager = player.familiarManager.familiar as Forager
val dest = player.location.transform(player.direction)
@@ -132,11 +125,6 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption?
player.setAttribute("/save:$STATS_BASE:$STATS_FISH", ++fishCaught)
player.skills.addExperience(Skills.FISHING, fish!!.experience, true)
message(2)
if (TutorialSession.getExtension(player).stage == 13) {
TutorialStage.load(player, 14, false)
stop()
return true
}
}
}
return player.inventory.freeSlots() == 0
@@ -6,8 +6,6 @@ import core.cache.def.impl.ItemDefinition
import core.game.container.impl.EquipmentContainer
import core.game.content.dialogue.FacialExpression
import core.game.content.global.SkillingPets
import core.game.content.quest.tutorials.tutorialisland.TutorialSession
import core.game.content.quest.tutorials.tutorialisland.TutorialStage
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
@@ -21,7 +19,6 @@ import core.game.node.entity.skill.gather.mining.MiningNode
import core.game.node.item.ChanceItem
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.tools.RandomFunction
import core.tools.StringUtils
@@ -76,9 +73,6 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul
if (resource!!.identifier == MiningNode.GEM_ROCK_0.identifier) {
isMiningGems = true
}
if (TutorialSession.getExtension(player).stage == 35) {
TutorialStage.load(player, 36, false)
}
if (checkRequirements()) {
super.start()
message(0)
@@ -0,0 +1,52 @@
package rs09.game.interaction.`object`
import api.*
import core.game.node.entity.skill.gather.SkillingResource
import core.game.node.entity.skill.gather.mining.MiningNode
import core.game.system.task.Pulse
import rs09.game.interaction.InteractionListener
/**
* @author: bushtail
*/
class ProspectListener : InteractionListener() {
override fun defineListeners() {
on(SCENERY, "prospect") { player, node ->
/** Check if the rock contains gems */
if(MiningNode.forId(node.id).identifier == 13.toByte()) {
val rock = SkillingResource.forId(node.asScenery().id)
if(rock == null) {
sendMessage(player, "There is no ore currently available in this rock.")
return@on true
}
sendMessage(player,"You examine the rock for ores...")
/** Send a simple text string saying it's a gem rock */
player.pulseManager.run(object : Pulse(3) {
override fun pulse(): Boolean {
sendMessage(player, "This rock contains gems.")
return true
}
})
}
/** If it doesn't contain gems */
else {
val rock = SkillingResource.forId(node.id)
if(rock == null) {
sendMessage(player, "There is no ore currently available in this rock.")
return@on true
}
sendMessage(player,"You examine the rock for ores...")
/** Get the name of the rock's reward and sends a message to the player */
player.pulseManager.run(object : Pulse(3) {
override fun pulse(): Boolean {
sendMessage(player, "This rock contains ${itemDefinition(rock.reward).name.toLowerCase()}.")
return true
}
})
}
return@on true
}
}
}
@@ -38,50 +38,23 @@ class UpdateSequence
playersList = renderablePlayers
npcList = Repository.renderableNpcs
lobbyList!!.map{ PacketRepository.send(ClearMinimapFlag::class.java, PlayerContext(it)) }
playersList!!.map{player ->
try {
player.tick()
} catch (e: Exception) {
e.printStackTrace()
}
}
npcList!!.map{npc ->
try {
npc.tick()
} catch (e: Exception) {
e.printStackTrace()
}
}
playersList!!.forEach(Player::tick)
npcList!!.forEach(NPC::tick)
}
/**
* Runs the updating part of the sequence.
*/
fun run() {
val latch = CountDownLatch(renderablePlayers.size)
playersList!!.forEach(Consumer { player: Player ->
GlobalScope.launch {
try {
player.update()
} catch (t: Throwable) {
t.printStackTrace()
}
latch.countDown()
}
})
try {
latch.await(1000L, TimeUnit.MILLISECONDS)
} catch (e: InterruptedException) {
e.printStackTrace()
}
renderablePlayers.forEach(Player::update)
}
/**
* Ends the sequence, calls the [Entity.reset] method..
*/
fun end() {
playersList!!.forEach(Consumer { obj: Player -> obj.reset() })
npcList!!.forEach(Consumer { obj: NPC -> obj.reset() })
playersList!!.forEach(Player::reset)
npcList!!.forEach(NPC::reset)
renderablePlayers.sync()
RegionManager.pulse()
GroundItemManager.pulse()
@@ -1,5 +1,6 @@
package rs09.plugin
import api.LoginListener
import core.game.content.activity.ActivityManager
import core.game.content.activity.ActivityPlugin
import core.game.content.dialogue.DialoguePlugin
@@ -16,6 +17,7 @@ import rs09.game.interaction.InterfaceListener
import rs09.game.node.entity.skill.magic.SpellListener
import rs09.game.system.SystemLogger
import rs09.game.system.command.Command
import rs09.game.world.GameWorld
import java.util.*
import java.util.function.Consumer
@@ -73,6 +75,10 @@ object PluginManager {
definePlugin(it.loadClass().newInstance() as Plugin<Command>).also { System.out.println("Initializing $it") }
} catch (e: Exception) {e.printStackTrace()}
}
result.getClassesImplementing("api.LoginListener").forEach {
val clazz = it.loadClass().newInstance() as LoginListener
GameWorld.loginListeners.add(clazz)
}
result.getSubclasses("rs09.game.interaction.InteractionListener").forEach {
val clazz = it.loadClass().newInstance() as InteractionListener
clazz.defineListeners()
@@ -6,6 +6,7 @@ import core.game.system.SystemState
import core.game.system.task.Pulse
import core.plugin.CorePluginTypes.Managers
import gui.GuiEvent
import gui.ServerMonitor
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -44,53 +45,54 @@ class MajorUpdateWorker {
val list = ArrayList(GameWorld.Pulser.TASKS)
Server.heartbeat()
//run our pulses
for(pulse in list) {
val b = System.currentTimeMillis()
if (pulse == null || pulse.update()) rmlist.add(pulse)
GlobalScope.launch {
//run our pulses
for (pulse in list) {
val b = System.currentTimeMillis()
if (pulse == null || pulse.update()) rmlist.add(pulse)
val time = System.currentTimeMillis() - b
val time = System.currentTimeMillis() - b
if(time >= 100){
if(pulse is GeneralBotCreator.BotScriptPulse){
SystemLogger.logWarn("CRITICALLY Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("CRITICALLY long running pulse: ${pulse.javaClass.name} - $time ms")
if (time >= 100) {
if (pulse is GeneralBotCreator.BotScriptPulse) {
SystemLogger.logWarn("CRITICALLY Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("CRITICALLY long running pulse: ${pulse.javaClass.name} - $time ms")
}
} else if (time >= 30) {
if (pulse is GeneralBotCreator.BotScriptPulse) {
SystemLogger.logWarn("Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("Long Running Pulse: ${pulse.javaClass.name} - $time ms")
}
}
}
else if(time >= 30){
if(pulse is GeneralBotCreator.BotScriptPulse){
SystemLogger.logWarn("Long Botscript Tick: ${pulse.botScript.javaClass.name} - $time ms")
} else {
SystemLogger.logWarn("Long Running Pulse: ${pulse.javaClass.name} - $time ms")
//remove all null or finished pulses from the list
rmlist.forEach {
if (GameWorld.Pulser.TASKS.contains(it)) GameWorld.Pulser.TASKS.remove(it)
}
rmlist.clear()
//perform our update sequence where we write masks, etc
try {
sequence.start()
sequence.run()
sequence.end()
GlobalScope.launch {
PacketWriteQueue.flush()
}
} catch (e: Exception) {
e.printStackTrace()
}
//increment global ticks variable
GameWorld.pulse()
//disconnect all players waiting to be disconnected
Repository.disconnectionQueue.update()
//tick all manager plugins
Managers.tick()
}
//remove all null or finished pulses from the list
rmlist.forEach {
if(GameWorld.Pulser.TASKS.contains(it)) GameWorld.Pulser.TASKS.remove(it)
}
rmlist.clear()
//perform our update sequence where we write masks, etc
try {
sequence.start()
sequence.run()
sequence.end()
GlobalScope.launch {
PacketWriteQueue.flush()
}
} catch (e: Exception){
e.printStackTrace()
}
//increment global ticks variable
GameWorld.pulse()
//disconnect all players waiting to be disconnected
Repository.disconnectionQueue.update()
//tick all manager plugins
Managers.tick()
//Handle daily restart if enabled
if(sdf.format(Date()).toInt() == 0){
@@ -117,6 +119,8 @@ class MajorUpdateWorker {
}
val end = System.currentTimeMillis()
ServerMonitor.eventQueue.add(GuiEvent.UpdateTickTime(end - start))
ServerMonitor.eventQueue.add(GuiEvent.UpdatePulseCount(GameWorld.Pulser.TASKS.size))
Thread.sleep(max(600 - (end - start), 0))
}
}