Rewrote Pyramid Plunder Minigame, features improved authenticity amongst other improvements
This commit is contained in:
@@ -261,7 +261,7 @@ abstract class Cutscene(val player: Player) {
|
||||
clearNPCs()
|
||||
player.unhook(CUTSCENE_DEATH_HOOK)
|
||||
player.logoutListeners.remove("cutscene")
|
||||
RandomEventManager.getInstance(player)!!.enabled = false
|
||||
RandomEventManager.getInstance(player)!!.enabled = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +439,7 @@ fun getAudio(id: Int, volume: Int = 10, delay: Int = 1): Audio {
|
||||
* @param type the type of hit splat to use, ImpactHandler.HitsplatType is an enum containing these options.
|
||||
*/
|
||||
|
||||
fun impact(entity: Entity, amount: Int, type: ImpactHandler.HitsplatType) {
|
||||
fun impact(entity: Entity, amount: Int, type: ImpactHandler.HitsplatType = ImpactHandler.HitsplatType.NORMAL) {
|
||||
entity.impactHandler.manualHit(entity, amount, type)
|
||||
}
|
||||
|
||||
@@ -855,7 +855,7 @@ fun getVarpValue(player: Player, varpIndex: Int): Int{
|
||||
*/
|
||||
|
||||
fun getVarbitValue(player: Player, varpIndex: Int, offset: Int): Int {
|
||||
return player.varpManager.get(varpIndex).getVarbitValue(offset)
|
||||
return player.varpManager.get(varpIndex).getVarbitValue(offset) ?: 0
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,37 +7,28 @@ import core.game.node.entity.player.Player
|
||||
* @author Ceikry
|
||||
*/
|
||||
class Varp(val index: Int) {
|
||||
val varbits = ArrayList<Varbit>()
|
||||
val varbits = HashMap<Int, Int>()
|
||||
var save = false
|
||||
|
||||
fun setVarbit(offset: Int, value: Int): Varp{
|
||||
for(vb in varbits){
|
||||
if (vb.offset == offset){
|
||||
varbits.remove(vb)
|
||||
break
|
||||
}
|
||||
}
|
||||
varbits.add(Varbit(value,offset))
|
||||
varbits[offset] = value
|
||||
return this
|
||||
}
|
||||
|
||||
fun getValue(): Int{
|
||||
var config = 0
|
||||
for(varbit in varbits){
|
||||
config = config or (varbit.value shl varbit.offset)
|
||||
for((index,value) in varbits.entries){
|
||||
config = config or (value shl index)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
fun getVarbit(offset: Int): Varbit?{
|
||||
for(varbit in varbits){
|
||||
if(varbit.offset == offset) return varbit
|
||||
}
|
||||
return null
|
||||
fun getVarbit(offset: Int): Int?{
|
||||
return getVarbitValue(offset)
|
||||
}
|
||||
|
||||
fun getVarbitValue(offset: Int): Int{
|
||||
return getVarbit(offset)?.value ?: 0
|
||||
fun getVarbitValue(offset: Int): Int {
|
||||
return varbits[offset] ?: 0
|
||||
}
|
||||
|
||||
fun send(player: Player){
|
||||
@@ -50,19 +41,15 @@ class Varp(val index: Int) {
|
||||
}
|
||||
|
||||
fun clearBitRange(first : Int, last : Int){
|
||||
for(varbit in varbits){
|
||||
if(varbit.offset in first..last){
|
||||
varbit.value = 0
|
||||
}
|
||||
}
|
||||
for(i in first..last) varbits.remove(i)
|
||||
}
|
||||
|
||||
fun getBitRangeValue(first: Int, last: Int): Int{
|
||||
var product = 0
|
||||
for(varbit in varbits){
|
||||
if(varbit.offset in first..last){
|
||||
product = product or (varbit.value shl varbit.offset)
|
||||
}
|
||||
for (i in first..last)
|
||||
{
|
||||
val value = varbits[i] ?: 0
|
||||
product = product or (value shl i)
|
||||
}
|
||||
return product
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class VarpManager(val player: Player) {
|
||||
|
||||
fun set(index: Int, value: Int){
|
||||
get(index).varbits.clear()
|
||||
get(index).varbits.add(Varbit(value,0))
|
||||
get(index).varbits[0] = value
|
||||
get(index).send(player)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,14 @@ class VarpManager(val player: Player) {
|
||||
}
|
||||
|
||||
fun setVarbit(varbitIndex: Int, value: Int){
|
||||
PacketRepository.send(core.net.packet.out.Varbit::class.java, VarbitContext(player, varbitIndex, value))
|
||||
val def = VarbitDefinition.forId(varbitIndex)
|
||||
get(def.configId).setVarbit(def.bitShift, value)
|
||||
get(def.configId).send(player)
|
||||
}
|
||||
|
||||
fun getVarbit(varbitIndex: Int){
|
||||
val def = VarbitDefinition.forId(varbitIndex)
|
||||
get(def.configId).getVarbit(def.bitShift)
|
||||
}
|
||||
|
||||
fun flagSave(index: Int){
|
||||
@@ -70,7 +77,7 @@ class VarpManager(val player: Player) {
|
||||
val bitArray = JSONArray()
|
||||
for(varbit in varp.varbits){
|
||||
val varbitobj = JSONObject()
|
||||
varbitobj.put("offset",varbit.offset.toString())
|
||||
varbitobj.put("offset",varbit.key.toString())
|
||||
varbitobj.put("value",varbit.value.toString())
|
||||
bitArray.add(varbitobj)
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ enum class AFUBeacon(val title: String, val fmLevel: Int, val varpId: Int, val o
|
||||
}
|
||||
|
||||
fun getState(player: Player): BeaconState{
|
||||
return BeaconState.values()[player.varpManager.get(varpId).getVarbit(offset)?.value ?: 0]
|
||||
return BeaconState.values()[player.varpManager.get(varpId).getVarbit(offset) ?: 0]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ class AFURepairClimbHandler : InteractionListener() {
|
||||
}
|
||||
|
||||
fun isRepaired(player: Player): Boolean{
|
||||
return player.varpManager.get(varp).getVarbit(offset)?.value == 1
|
||||
return player.varpManager.get(varp).getVarbit(offset) == 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ class BlastFurnaceInterfaceListener : InterfaceListener() {
|
||||
on(Components.BLAST_FURNACE_BAR_STOCK_28){ player, _, _, buttonID, _, _ ->
|
||||
val bar = BFBars.forId(buttonID) ?: return@on false
|
||||
val isAll = buttonID == bar.allButtonId
|
||||
val playerAmt = player.varpManager.get(bar.varpIndex).getVarbitValue(bar.offset)
|
||||
val playerAmt = player.varpManager.get(bar.varpIndex).getVarbitValue(bar.offset) ?: 0
|
||||
if(playerAmt == 0) return@on true
|
||||
|
||||
var amtToWithdraw = if(isAll) playerAmt else 1
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package rs09.game.content.activity.pyramidplunder
|
||||
|
||||
import api.setAttribute
|
||||
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
|
||||
import rs09.tools.END_DIALOGUE
|
||||
|
||||
@Initializable
|
||||
class GuardianMummyDialogue(player: Player? = null) : DialoguePlugin(player) {
|
||||
override fun open(vararg args: Any?): Boolean {
|
||||
npcl(FacialExpression.OLD_NOT_INTERESTED, "*sigh* Not another one.")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
|
||||
when(stage){
|
||||
0 -> playerl(FacialExpression.HALF_ASKING, "Another what?").also { stage++ }
|
||||
1 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Another 'archaeologist'. I'm not going to let you plunder my master's tomb you know.").also { stage++ }
|
||||
2 -> playerl(FacialExpression.NEUTRAL, "That's a shame. Have you got anything else I could do while I'm here?").also { stage++ }
|
||||
3 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "If it will keep you out of mischief I suppose I could set something up for you... I have a few rooms full of some things you humans might consider valuable, do you want to give it a go?").also { stage++ }
|
||||
4 -> player.dialogueInterpreter.sendOptions("Play Pyramid Plunder?", "That sounds like fun; what do I do?", "Not right now.", "I know what I'm doing, so let's get on with it.").also { stage++ }
|
||||
5 -> when(buttonId)
|
||||
{
|
||||
1 -> playerl(FacialExpression.FRIENDLY, "That sounds like fun; what do I do?").also { stage = 10 }
|
||||
2 -> playerl(FacialExpression.NEUTRAL, "Not right now.").also { stage = END_DIALOGUE }
|
||||
3 -> playerl(FacialExpression.ANNOYED, "I know what I'm doing, so let's get on with it.").also { stage = 100 }
|
||||
}
|
||||
|
||||
10 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "You have five minutes to explore the treasure rooms and collect as many artefacts as you can. The artefacts are in the urns, chests and sarcophagi found in each room.").also { stage++ }
|
||||
11 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "There are eight treasure rooms, each subsequent room requires higher thieving skills to both enter the room and thieve from the urns and other containers.").also { stage++ }
|
||||
12 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "The rewards also become more lucrative the further into the tomb you go. You will also have to deactivate a trap in order to enter the main part of each room.").also { stage++ }
|
||||
13 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "When you want to move onto the next room you need to find the correct door first.").also { stage++ }
|
||||
14 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "There are four possible exits... you must open the door before finding out whether it is the exit or not. Opening the doors require picking their locks. Having a lockpick will make this easier.").also { stage++ }
|
||||
15 -> player.dialogueInterpreter.sendOptions("Do you have any more questions?", "How do I leave the game?", "How do I get the artefacts?", "What do I do with the artefacts I collect?", "I'm ready to give it a go now.").also { stage++ }
|
||||
16 -> when(buttonId)
|
||||
{
|
||||
1 -> playerl(FacialExpression.FRIENDLY, "How do I leave the game?").also { stage = 20 }
|
||||
2 -> playerl(FacialExpression.FRIENDLY, "How do I get the artefacts?").also { stage = 30 }
|
||||
3 -> playerl(FacialExpression.FRIENDLY, "What do I do with the artefacts?").also { stage = 40 }
|
||||
4 -> playerl(FacialExpression.FRIENDLY, "I'm ready to give it a go now.").also { stage = 100 }
|
||||
}
|
||||
|
||||
20 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "If at any point you decide you need to leave just use a glowing door. The game will end and you will be taken out of the pyramid").also { stage = 15 }
|
||||
|
||||
30 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "The artefacts are in the urns, chests and sarcophagi. Urns contain snakes that guard them. The sarcophagi take some strength to open. They take a while to open.").also { stage++ }
|
||||
31 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Of course, Mummies have been known to take a nap in the sarcophagi, so beware. The golden chests generally contain better artefacts, but are also trapped with scarabs!").also { stage = 15 }
|
||||
|
||||
40 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "There are a number of different artefacts, of three main types. The least valuable are the pottery statuettes and scarabs, and the ivory combs.").also { stage++ }
|
||||
41 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Next are the stone scarabs, statuettes and seals, and finally the gold versions of those artefacts. They are not old, but are well made.").also { stage++ }
|
||||
42 -> playerl(FacialExpression.HALF_ASKING, "What do I do with artefacts once I've collected them?").also { stage++ }
|
||||
43 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "That Simon Simpleton, I mean Templeton, will probably give you some money for them. He couldn't spot a real artefact if it came up to him and bit him in the face.").also { stage++ }
|
||||
44 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "He usually slinks about near the pyramid north-east of Sophanem. I expect he's trying to get some poor fools to steal things from that pyramid as well.").also { stage = 15 }
|
||||
|
||||
100 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Alright, fine.").also { stage++ }
|
||||
101 -> {
|
||||
end()
|
||||
PyramidPlunderMinigame.join(player)
|
||||
setAttribute(player, "/save:pp:mummy-spoken-to", true)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getIds(): IntArray {
|
||||
return intArrayOf(NPCs.GUARDIAN_MUMMY_4476)
|
||||
}
|
||||
|
||||
override fun newInstance(player: Player?): DialoguePlugin {
|
||||
return GuardianMummyDialogue(player)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package rs09.game.content.activity.pyramidplunder
|
||||
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import org.rs09.consts.Items
|
||||
|
||||
/**
|
||||
* An object that simply contains Pyramid Plunder data.
|
||||
*/
|
||||
object PlunderData {
|
||||
val playerLocations = HashMap<Player, PlunderRoom>()
|
||||
val players = ArrayList<Player>()
|
||||
val doorVarbits = arrayOf(2366, 2367, 2368, 2369)
|
||||
val doors = Array(8){doorVarbits[0]}
|
||||
val timeLeft = HashMap<Player, Int>()
|
||||
|
||||
val pyramidEntranceVarbits = arrayOf(2371,2372,2373,2374)
|
||||
var currentEntrance = pyramidEntranceVarbits.random()
|
||||
var nextEntranceSwitch = 0L
|
||||
val mummy = NPC(4476, Location.create(1968, 4428, 2)).also { it.isNeverWalks = true; it.init() }
|
||||
|
||||
val artifacts = arrayOf(
|
||||
arrayOf(Items.IVORY_COMB_9026, Items.POTTERY_SCARAB_9032, Items.POTTERY_STATUETTE_9036),
|
||||
arrayOf(Items.STONE_SCARAB_9030, Items.STONE_STATUETTE_9038, Items.STONE_SEAL_9042),
|
||||
arrayOf(Items.GOLDEN_SCARAB_9028, Items.GOLDEN_STATUETTE_9034, Items.GOLD_SEAL_9040)
|
||||
)
|
||||
|
||||
val rooms = arrayOf(
|
||||
PlunderRoom(1, Location.create(1927, 4477, 0), Location.create(1929, 4469, 0), Direction.SOUTH),
|
||||
PlunderRoom(2, Location.create(1954, 4477, 0), Location.create(1955, 4467, 0), Direction.SOUTH),
|
||||
PlunderRoom(3, Location.create(1977, 4471, 0), Location.create(1975, 4458, 0), Direction.SOUTH),
|
||||
PlunderRoom(4, Location.create(1927, 4453, 0), Location.create(1937, 4454, 0), Direction.EAST),
|
||||
PlunderRoom(5, Location.create(1965, 4444, 0), Location.create(1955, 4449, 0), Direction.WEST),
|
||||
PlunderRoom(6, Location.create(1927, 4424, 0), Location.create(1925, 4433, 0), Direction.NORTH),
|
||||
PlunderRoom(7, Location.create(1943, 4421, 0), Location.create(1950, 4427, 0), Direction.NORTH),
|
||||
PlunderRoom(8, Location.create(1974, 4420, 0), Location.create(1971, 4431, 0), Direction.NORTH)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple way to represent a pyramid plunder room.
|
||||
*/
|
||||
data class PlunderRoom(val room: Int, val entrance: Location, val mummyLoc: Location, val spearDirection: Direction)
|
||||
@@ -1,89 +0,0 @@
|
||||
package rs09.game.content.activity.pyramidplunder
|
||||
|
||||
import core.game.component.Component
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Location
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Components
|
||||
import rs09.game.world.GameWorld
|
||||
|
||||
class PlunderSession(val player: Player) {
|
||||
var door1Open: Boolean = false
|
||||
var door2Open: Boolean = false
|
||||
var door3Open: Boolean = false
|
||||
var door4Open: Boolean = false
|
||||
var chestHidden: Boolean = false
|
||||
var chestOpen: Boolean = false
|
||||
var coffinHidden: Boolean = false
|
||||
var coffinOpen: Boolean = false
|
||||
var timeCounter: Int = 1
|
||||
var correctDoorIndex: Int = RandomFunction.random(1000) % 4
|
||||
var isActive = false
|
||||
|
||||
|
||||
fun init(){
|
||||
player.setAttribute("plunder-session",this)
|
||||
GameWorld.Pulser.submit(PlunderPulse(player))
|
||||
player.interfaceManager.openOverlay(Component(Components.NTK_OVERLAY_428))
|
||||
isActive = true
|
||||
}
|
||||
|
||||
fun updateOverlay(){
|
||||
player.configManager.set(821,getConfig())
|
||||
}
|
||||
|
||||
fun resetVars(){
|
||||
chestOpen = false
|
||||
chestHidden = false
|
||||
coffinHidden = false
|
||||
coffinOpen = false
|
||||
door1Open = false
|
||||
door2Open = false
|
||||
door3Open = false
|
||||
door4Open = false
|
||||
correctDoorIndex = RandomFunction.random(1000) % 4
|
||||
}
|
||||
|
||||
fun getConfig(): Int{
|
||||
var config = 0
|
||||
if(coffinOpen) config = 1
|
||||
if(coffinHidden) config = (config or (1 shl 1))
|
||||
if(chestOpen) config = (config or (1 shl 2))
|
||||
if(chestHidden) config = (config or (1 shl 3))
|
||||
if(door1Open) config = (config or (1 shl 9))
|
||||
if(door2Open) config = (config or (1 shl 10))
|
||||
if(door3Open) config = (config or (1 shl 11))
|
||||
if(door4Open) config = (config or (1 shl 12))
|
||||
return (config or (timeCounter shl 25))
|
||||
}
|
||||
|
||||
fun setDoorOpen(index: Int){
|
||||
when(index){
|
||||
0 -> door1Open = true
|
||||
1 -> door2Open = true
|
||||
2 -> door3Open = true
|
||||
3 -> door4Open = true
|
||||
}
|
||||
}
|
||||
|
||||
class PlunderPulse(val player: Player) : Pulse(){
|
||||
var ticks = 0
|
||||
var overlayConfig = 0
|
||||
val session: PlunderSession? = player.getAttribute("plunder-session",null)
|
||||
override fun pulse(): Boolean {
|
||||
session ?: return false
|
||||
if(ticks++ % 8 == 0){
|
||||
session.timeCounter++
|
||||
session.updateOverlay()
|
||||
}
|
||||
if(session.timeCounter > 63){
|
||||
player.properties.teleportLocation = Location.create(3286, 2803, 0)
|
||||
player.dialogueInterpreter.sendDialogue("You ran out of time and the mummy kicked you","out.")
|
||||
player.configManager.set(822,0)
|
||||
player.configManager.set(821,0)
|
||||
}
|
||||
return session.timeCounter > 63 || !session.isActive
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
package rs09.game.content.activity.pyramidplunder
|
||||
|
||||
import api.*
|
||||
import core.game.component.Component
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Components
|
||||
import org.rs09.consts.Items
|
||||
|
||||
/**
|
||||
* A collection of methods needed for Pyramid Plunder.
|
||||
*/
|
||||
object PlunderUtils {
|
||||
fun hasPlayer(player: Player): Boolean
|
||||
{
|
||||
return PlunderData.playerLocations[player] != null
|
||||
}
|
||||
|
||||
fun registerPlayer(player: Player)
|
||||
{
|
||||
PlunderData.players.add(player)
|
||||
PlunderData.timeLeft[player] = 500 //5 minutes
|
||||
}
|
||||
|
||||
fun unregisterPlayer(player: Player)
|
||||
{
|
||||
PlunderData.players.remove(player)
|
||||
PlunderData.playerLocations.remove(player)
|
||||
PlunderData.timeLeft.remove(player)
|
||||
}
|
||||
|
||||
fun expel(player: Player, summonMummy: Boolean)
|
||||
{
|
||||
teleport(player, Location.create(3288, 2802, 0))
|
||||
unregisterPlayer(player)
|
||||
resetOverlay(player)
|
||||
resetObjectVarbits(player)
|
||||
|
||||
if(!summonMummy)
|
||||
{
|
||||
sendDialogue(player, "You've run out of time and the guardian mummy has thrown you out.")
|
||||
}
|
||||
else
|
||||
{
|
||||
sendDialogue(player, "You've been expelled by the guardian mummy.")
|
||||
}
|
||||
}
|
||||
|
||||
fun decrementTimeRemaining() : ArrayList<Player>
|
||||
{
|
||||
val timesUp = ArrayList<Player>()
|
||||
PlunderData.timeLeft.forEach { player, left ->
|
||||
if(left <= 0) timesUp.add(player)
|
||||
PlunderData.timeLeft[player] = left - 1
|
||||
updateOverlay(player)
|
||||
}
|
||||
return timesUp
|
||||
}
|
||||
|
||||
fun loadNextRoom(player: Player)
|
||||
{
|
||||
val current = PlunderData.playerLocations[player]
|
||||
|
||||
val next: PlunderRoom = if(current == null)
|
||||
getRoom(1)
|
||||
else
|
||||
getRoom(current.room + 1)
|
||||
|
||||
if(PlunderData.playerLocations.filter { it.value == next }.isEmpty()) //if no one is in the next room
|
||||
{
|
||||
PlunderData.doors[next.room - 1] = PlunderData.doorVarbits.random() //reshuffle the next room's exit door
|
||||
}
|
||||
|
||||
teleport(player, next.entrance)
|
||||
PlunderData.playerLocations[player] = next
|
||||
}
|
||||
|
||||
fun getRoom(number: Int) : PlunderRoom
|
||||
{
|
||||
return PlunderData.rooms[number - 1]
|
||||
}
|
||||
|
||||
fun getRoom(player: Player): PlunderRoom?
|
||||
{
|
||||
return PlunderData.playerLocations[player]
|
||||
}
|
||||
|
||||
fun getRoomLevel(player: Player): Int
|
||||
{
|
||||
return 11 + (10 * getRoom(player)!!.room)
|
||||
}
|
||||
|
||||
fun getSpearDestination(player: Player): Location
|
||||
{
|
||||
val room = getRoom(player)!!
|
||||
return when(room.spearDirection)
|
||||
{
|
||||
Direction.NORTH -> player.location.transform(0, 3, 0)
|
||||
Direction.SOUTH -> player.location.transform(0, -3, 0)
|
||||
Direction.WEST -> player.location.transform(-3, 0, 0)
|
||||
Direction.EAST -> player.location.transform(3, 0, 0)
|
||||
else -> player.location
|
||||
}
|
||||
}
|
||||
|
||||
fun getUrnXp(player: Player, check: Boolean): Double
|
||||
{
|
||||
val room = getRoom(player)!!.room
|
||||
return if(check)
|
||||
{
|
||||
when(room)
|
||||
{
|
||||
1 -> 20.0
|
||||
2 -> 30.0
|
||||
3 -> 50.0
|
||||
4 -> 70.0
|
||||
5 -> 100.0
|
||||
6 -> 150.0
|
||||
7 -> 225.0
|
||||
8 -> 275.0
|
||||
else -> 0.0
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
when(room)
|
||||
{
|
||||
1 -> 60.0
|
||||
2 -> 90.0
|
||||
3 -> 150.0
|
||||
4 -> 215.0
|
||||
5 -> 300.0
|
||||
6 -> 450.0
|
||||
7 -> 675.0
|
||||
8 -> 825.0
|
||||
else -> 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resetObjectVarbits(player: Player)
|
||||
{
|
||||
var varp = player.varpManager.get(821)
|
||||
varp.clear()
|
||||
varp.send(player)
|
||||
varp = player.varpManager.get(820)
|
||||
varp.clear()
|
||||
varp.send(player)
|
||||
PlunderData.doorVarbits.forEach { player.varpManager.setVarbit(it, 0) }
|
||||
}
|
||||
|
||||
fun openOverlay(player: Player)
|
||||
{
|
||||
player.interfaceManager.openOverlay(Component(Components.NTK_OVERLAY_428))
|
||||
updateOverlay(player)
|
||||
}
|
||||
|
||||
fun updateOverlay(player: Player)
|
||||
{
|
||||
player.varpManager.setVarbit(2375, 500 - (PlunderData.timeLeft[player] ?: 0))
|
||||
player.varpManager.setVarbit(2376, 11 + (getRoom(player)!!.room * 10))
|
||||
player.varpManager.setVarbit(2377, getRoom(player)!!.room)
|
||||
}
|
||||
|
||||
fun resetOverlay(player: Player)
|
||||
{
|
||||
player.varpManager.setVarbit(2375, 0)
|
||||
player.packetDispatch.resetInterface(Components.NTK_OVERLAY_428)
|
||||
player.interfaceManager.closeOverlay()
|
||||
}
|
||||
|
||||
fun getDoor(player: Player) : Int
|
||||
{
|
||||
val room = getRoom(player)!!.room
|
||||
return PlunderData.doors[room - 1]
|
||||
}
|
||||
|
||||
fun rollSceptre(player: Player): Boolean
|
||||
{
|
||||
val room = getRoom(player)!!.room
|
||||
val chance = when(room)
|
||||
{
|
||||
1 -> 1500
|
||||
2 -> 1350
|
||||
3 -> 1250
|
||||
4 -> 1150
|
||||
else -> 1000
|
||||
}
|
||||
|
||||
if(RandomFunction.roll(chance))
|
||||
{
|
||||
expel(player, true)
|
||||
runTask(player, 2)
|
||||
{
|
||||
addItemOrDrop(player, Items.PHARAOHS_SCEPTRE_9050)
|
||||
sendNews("${player.username} has received a Pharaoh's Sceptre while doing Pyramid Plunder!")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun getSarcophagusXp(player: Player) : Double
|
||||
{
|
||||
val room = getRoom(player)!!.room
|
||||
return when(room)
|
||||
{
|
||||
1 -> 20.0
|
||||
2 -> 30.0
|
||||
3 -> 50.0
|
||||
4 -> 70.0
|
||||
5 -> 100.0
|
||||
6 -> 150.0
|
||||
7 -> 225.0
|
||||
8 -> 275.0
|
||||
else -> 0.0
|
||||
}
|
||||
}
|
||||
|
||||
fun getChestXp(player: Player): Double
|
||||
{
|
||||
val room = getRoom(player)!!.room
|
||||
return when(room)
|
||||
{
|
||||
1 -> 60.0
|
||||
2 -> 90.0
|
||||
3 -> 150.0
|
||||
4 -> 215.0
|
||||
5 -> 300.0
|
||||
6 -> 450.0
|
||||
7 -> 675.0
|
||||
8 -> 825.0
|
||||
else -> 0.0
|
||||
} * 0.66
|
||||
}
|
||||
|
||||
fun getDoorXp(player: Player, lockpick: Boolean) : Double
|
||||
{
|
||||
val room = getRoom(player)!!.room
|
||||
var reward = when(room)
|
||||
{
|
||||
1 -> 60.0
|
||||
2 -> 90.0
|
||||
3 -> 150.0
|
||||
4 -> 215.0
|
||||
5 -> 300.0
|
||||
6 -> 450.0
|
||||
7 -> 675.0
|
||||
8 -> 825.0
|
||||
else -> 0.0
|
||||
} * 0.66
|
||||
|
||||
if(lockpick)
|
||||
reward /= 2.0
|
||||
|
||||
return reward
|
||||
}
|
||||
|
||||
fun rollArtifact(player: Player, tier: Int) : Int
|
||||
{
|
||||
//tier 1 -> urn
|
||||
//tier 2 -> sarcophagus
|
||||
//tier 3 -> chest
|
||||
val room = getRoom(player)!!.room
|
||||
val divisor = (room * 2) * (tier * 35)
|
||||
val goldRate = divisor / 650
|
||||
val stoneRate = divisor / 250
|
||||
|
||||
val roll = RandomFunction.RANDOM.nextDouble()
|
||||
if(goldRate > roll)
|
||||
return PlunderData.artifacts[2].random()
|
||||
if(stoneRate > roll)
|
||||
return PlunderData.artifacts[1].random()
|
||||
return PlunderData.artifacts[0].random()
|
||||
}
|
||||
|
||||
fun checkEntranceSwitch()
|
||||
{
|
||||
if(System.currentTimeMillis() > PlunderData.nextEntranceSwitch)
|
||||
{
|
||||
PlunderData.currentEntrance = PlunderData.pyramidEntranceVarbits.random()
|
||||
PlunderData.nextEntranceSwitch = System.currentTimeMillis() + (60000 * 15)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun checkEntrance(door: Node): Boolean
|
||||
{
|
||||
return door.asScenery().definition.varbitID == PlunderData.currentEntrance
|
||||
}
|
||||
|
||||
fun rollUrnSuccess(player: Player, charmed: Boolean = false): Boolean
|
||||
{
|
||||
val level = getDynLevel(player, Skills.THIEVING)
|
||||
val room = getRoom(player)!!.room
|
||||
return RandomFunction.random(level) > (room * if(charmed) 2 else 4)
|
||||
}
|
||||
}
|
||||
+385
@@ -0,0 +1,385 @@
|
||||
package rs09.game.content.activity.pyramidplunder
|
||||
|
||||
import api.*
|
||||
import core.game.content.activity.pyramidplunder.PyramidPlunderMummyNPC
|
||||
import core.game.content.activity.pyramidplunder.PyramidPlunderSwarmNPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.entity.state.EntityState
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Scenery
|
||||
import rs09.game.content.dialogue.DialogueFile
|
||||
import rs09.game.interaction.InteractionListener
|
||||
|
||||
/**
|
||||
* The "controller" class for pyramid plunder. Handles per-tick updates, logout hooks, and defines interaction listeners for the minigame.
|
||||
* @author Ceikry
|
||||
*/
|
||||
class PyramidPlunderMinigame : InteractionListener(), TickListener, LogoutListener {
|
||||
override fun tick() {
|
||||
val playersToExpel = PlunderUtils.decrementTimeRemaining()
|
||||
playersToExpel.forEach {player -> PlunderUtils.expel(player, false) }
|
||||
PlunderUtils.checkEntranceSwitch()
|
||||
}
|
||||
|
||||
override fun logout(player: Player) {
|
||||
if(PlunderUtils.hasPlayer(player))
|
||||
{
|
||||
player.location = Location.create(3288, 2802, 0)
|
||||
PlunderUtils.unregisterPlayer(player)
|
||||
}
|
||||
}
|
||||
|
||||
override fun defineListeners() {
|
||||
val CHECK_ANIM = 3572
|
||||
val URN_CHECK = 4340
|
||||
val URN_BIT = 4341
|
||||
val URN_SUCCESS = 4342
|
||||
val PUSH_LID_START = 4343
|
||||
val PUSH_LID_LOOP = 4344
|
||||
val PUSH_LID_FINISH = 4345
|
||||
val CHARM_ANIM = 1877
|
||||
val OPEN_CHEST_ANIM = 536
|
||||
|
||||
val SPEAR_OBJ_ANIM = 459
|
||||
val SNAKE_URN_ANIM = 4335
|
||||
|
||||
val SEALED_URNS = intArrayOf(Scenery.URN_16501, Scenery.URN_16502, Scenery.URN_16503)
|
||||
val OPEN_URNS = intArrayOf(Scenery.URN_16505, Scenery.URN_16506, Scenery.URN_16507)
|
||||
val SNAKE_URNS = intArrayOf(Scenery.URN_16509, Scenery.URN_16510, Scenery.URN_16511)
|
||||
val CHARMED_SNAKES = intArrayOf(Scenery.URN_16513, Scenery.URN_16514, Scenery.URN_16515)
|
||||
val ENTRANCES = intArrayOf(16484, 16487, 16490, 16493) //All Scenery.AN_ANONYMOUS_LOOKING_DOOR_16484/etc
|
||||
val SARCOPHAGUS = Scenery.SARCOPHAGUS_16495
|
||||
|
||||
on(Scenery.SPEARTRAP_16517, SCENERY, "pass"){player, node ->
|
||||
val anim = Animation(CHECK_ANIM)
|
||||
val duration = animationDuration(anim)
|
||||
|
||||
if(player.skills.getStaticLevel(Skills.THIEVING) < PlunderUtils.getRoomLevel(player))
|
||||
{
|
||||
sendDialogue(player, "You need a Thieving level of ${PlunderUtils.getRoomLevel(player)} to do that.")
|
||||
return@on true
|
||||
}
|
||||
|
||||
val spearDir = PlunderUtils.getRoom(player)!!.spearDirection
|
||||
|
||||
val pastSpears = (spearDir == Direction.NORTH && player.location.y > node.location.y)
|
||||
|| (spearDir == Direction.SOUTH && player.location.y < node.location.y)
|
||||
|| (spearDir == Direction.EAST && player.location.x > node.location.x)
|
||||
|| (spearDir == Direction.WEST && player.location.x < node.location.x)
|
||||
|
||||
if(pastSpears)
|
||||
{
|
||||
sendDialogue(player, "I have no reason to do that.")
|
||||
return@on true
|
||||
}
|
||||
|
||||
animate(player, anim)
|
||||
sendMessage(player, "You carefully try to temporarily disable the trap.")
|
||||
player.pulseManager.run(object : Pulse(duration) {
|
||||
override fun pulse(): Boolean {
|
||||
if(RandomFunction.roll(5))
|
||||
{
|
||||
val dest = PlunderUtils.getSpearDestination(player)
|
||||
player.walkingQueue.reset()
|
||||
player.walkingQueue.addPath(dest.x,dest.y)
|
||||
rewardXP(player, Skills.THIEVING, 10.0)
|
||||
return true
|
||||
}
|
||||
if(RandomFunction.roll(20))
|
||||
{
|
||||
animateScenery(node.asScenery(), SPEAR_OBJ_ANIM)
|
||||
impact(player, RandomFunction.random(1,5))
|
||||
sendChat(player, "Ouch!")
|
||||
sendMessage(player, "You fail to disable the trap.")
|
||||
return true
|
||||
}
|
||||
animate(player, anim)
|
||||
return false
|
||||
}
|
||||
})
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(intArrayOf(*SEALED_URNS, *SNAKE_URNS), SCENERY, "search") { player, node ->
|
||||
animate(player, URN_CHECK)
|
||||
player.faceLocation(node.location)
|
||||
player.lock()
|
||||
runTask(player, 1) {
|
||||
player.unlock()
|
||||
if(!PlunderUtils.rollUrnSuccess(player))
|
||||
{
|
||||
animate(player, URN_BIT)
|
||||
sendMessage(player, "You've been bitten by something moving around in the urn.")
|
||||
impact(player, RandomFunction.random(1,5))
|
||||
player.stateManager.register(EntityState.POISONED, true, 20, player)
|
||||
}
|
||||
else {
|
||||
animate(player, URN_SUCCESS)
|
||||
sendMessage(player, "You successfully loot the urn.")
|
||||
rewardXP(player, Skills.THIEVING, PlunderUtils.getUrnXp(player, false))
|
||||
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 1))
|
||||
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
|
||||
}
|
||||
player.unlock()
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(SEALED_URNS, SCENERY, "check for snakes") { player, node ->
|
||||
val urn = node.asScenery()
|
||||
animate(player, URN_CHECK)
|
||||
player.faceLocation(node.location)
|
||||
player.lock()
|
||||
runTask(player, 1){
|
||||
player.unlock()
|
||||
animate(player, URN_BIT)
|
||||
player.varpManager.setVarbit(urn.definition.varbitID, 2)
|
||||
animateScenery(urn, SNAKE_URN_ANIM)
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(SNAKE_URNS, SCENERY, "charm snake") { player, node ->
|
||||
if(!inInventory(player, Items.SNAKE_CHARM_4605))
|
||||
{
|
||||
sendMessage(player, "You need a snake charm to charm a snake.")
|
||||
return@on true
|
||||
}
|
||||
lock(player, 2)
|
||||
animate(player, CHARM_ANIM)
|
||||
runTask(player, 1)
|
||||
{
|
||||
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 3)
|
||||
sendMessage(player, "You charm the snake with your music.")
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(CHARMED_SNAKES, SCENERY, "search") { player, node ->
|
||||
animate(player, URN_CHECK)
|
||||
player.faceLocation(node.location)
|
||||
player.lock()
|
||||
runTask(player, 1) {
|
||||
player.unlock()
|
||||
if(!PlunderUtils.rollUrnSuccess(player, true))
|
||||
{
|
||||
animate(player, URN_BIT)
|
||||
sendMessage(player, "You've been bitten by something moving around in the urn.")
|
||||
impact(player, RandomFunction.random(1,5))
|
||||
player.stateManager.register(EntityState.POISONED, true, 20, player)
|
||||
}
|
||||
else {
|
||||
animate(player, URN_SUCCESS)
|
||||
sendMessage(player, "You successfully loot the urn.")
|
||||
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 1))
|
||||
rewardXP(player, Skills.THIEVING, PlunderUtils.getUrnXp(player, false) * 0.66)
|
||||
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
|
||||
}
|
||||
player.unlock()
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(OPEN_URNS, SCENERY, "search") { player, _ ->
|
||||
sendMessage(player, "You've already looted this urn.")
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(SARCOPHAGUS, SCENERY, "open") { player, node ->
|
||||
sendMessage(player, "You attempt to push open the massive lid.")
|
||||
val strength = getDynLevel(player, Skills.STRENGTH)
|
||||
animate(player, PUSH_LID_START)
|
||||
player.pulseManager.run(object : Pulse(2)
|
||||
{
|
||||
override fun pulse(): Boolean {
|
||||
animate(player, PUSH_LID_LOOP)
|
||||
if(RandomFunction.random(125) > strength)
|
||||
return false
|
||||
animate(player, PUSH_LID_FINISH)
|
||||
runTask(player, 3){
|
||||
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
|
||||
rewardXP(player, Skills.STRENGTH, PlunderUtils.getSarcophagusXp(player))
|
||||
if(RandomFunction.roll(25))
|
||||
{
|
||||
val mummy = PyramidPlunderMummyNPC(player.location, player)
|
||||
mummy.isRespawn = false
|
||||
mummy.init()
|
||||
mummy.attack(player)
|
||||
}
|
||||
else if(!PlunderUtils.rollSceptre(player))
|
||||
{
|
||||
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 2))
|
||||
}
|
||||
player.unlock()
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.GRAND_GOLD_CHEST_16473, SCENERY, "search") { player, node ->
|
||||
animate(player, OPEN_CHEST_ANIM)
|
||||
runTask(player){
|
||||
if(RandomFunction.roll(25))
|
||||
{
|
||||
val swarm = PyramidPlunderSwarmNPC(player.location, player)
|
||||
swarm.isRespawn = false
|
||||
swarm.init()
|
||||
swarm.attack(player)
|
||||
impact(player, RandomFunction.random(1,5))
|
||||
}
|
||||
else
|
||||
{
|
||||
rewardXP(player, Skills.THIEVING, PlunderUtils.getChestXp(player))
|
||||
if(!PlunderUtils.rollSceptre(player))
|
||||
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 3))
|
||||
}
|
||||
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.TOMB_DOOR_16475, SCENERY, "pick-lock") { player, node ->
|
||||
val anim = Animation(CHECK_ANIM)
|
||||
val duration = animationDuration(anim)
|
||||
|
||||
if(PlunderUtils.getRoom(player)!!.room == 8)
|
||||
{
|
||||
sendMessage(player, "This is the final room. I should probably just leave instead.")
|
||||
return@on true
|
||||
}
|
||||
|
||||
animate(player, anim)
|
||||
player.lock()
|
||||
val rate =
|
||||
if(inInventory(player, Items.LOCKPICK_1523))
|
||||
{
|
||||
sendMessage(player, "You attempt to open the door.")
|
||||
2
|
||||
}
|
||||
else
|
||||
{
|
||||
sendMessage(player, "You attempt to open the door. Lockpicks would make it easier...")
|
||||
3
|
||||
}
|
||||
runTask(player, duration){
|
||||
player.unlock()
|
||||
if(RandomFunction.roll(rate))
|
||||
{
|
||||
val varbitId = node.asScenery().definition.varbitID
|
||||
rewardXP(player, Skills.THIEVING, PlunderUtils.getDoorXp(player, rate == 3))
|
||||
if(PlunderUtils.getDoor(player) == varbitId) {
|
||||
PlunderUtils.loadNextRoom(player)
|
||||
PlunderUtils.resetObjectVarbits(player)
|
||||
} else {
|
||||
sendMessage(player, "The door leads to a dead end.")
|
||||
player.varpManager.setVarbit(varbitId, 1)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sendMessage(player, "Your attempt fails.")
|
||||
}
|
||||
}
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.TOMB_DOOR_16458, SCENERY, "leave tomb") { player, _ ->
|
||||
openDialogue(player, object : DialogueFile()
|
||||
{
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
when(stage)
|
||||
{
|
||||
0 -> options("Yes, I'm sure I want to leave.", "No, never mind.").also { stage++ }
|
||||
1 -> when(buttonID)
|
||||
{
|
||||
1 -> {
|
||||
end()
|
||||
teleport(player, Location.create(3288, 2802, 0))
|
||||
PlunderUtils.unregisterPlayer(player)
|
||||
PlunderUtils.resetOverlay(player)
|
||||
PlunderUtils.resetObjectVarbits(player)
|
||||
}
|
||||
2 -> end()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(ENTRANCES, SCENERY, "search") { player, door ->
|
||||
if(!getAttribute(player, "tarik-spoken-to", false))
|
||||
{
|
||||
sendDialogue(player, "I should probably try to find out more about this place before I try to break in.")
|
||||
return@on true
|
||||
}
|
||||
val anim = Animation(CHECK_ANIM)
|
||||
val duration = animationDuration(anim)
|
||||
|
||||
animate(player, anim)
|
||||
sendMessage(player, "You use your thieving skills to search the stone panel.")
|
||||
player.pulseManager.run(object : Pulse(duration){
|
||||
override fun pulse(): Boolean {
|
||||
if(RandomFunction.roll(3))
|
||||
{
|
||||
setAttribute(player, "pyramid-entrance", player.location.transform(0,0,0))
|
||||
sendMessage(player, "You find a door! You open it.")
|
||||
if(PlunderUtils.checkEntrance(door)) {
|
||||
teleport(player, GUARDIAN_ROOM)
|
||||
rewardXP(player, Skills.THIEVING, 20.0)
|
||||
}
|
||||
else
|
||||
teleport(player, EMPTY_ROOM)
|
||||
|
||||
return true
|
||||
}
|
||||
animate(player, anim)
|
||||
return false
|
||||
}
|
||||
})
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(Scenery.TOMB_DOOR_16459, SCENERY, "leave tomb") { player, _ ->
|
||||
teleport(player, getAttribute(player, "pyramid-entrance", Location.create(3288, 2802, 0)))
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(NPCs.GUARDIAN_MUMMY_4476, NPC, "start-minigame") { player, _ ->
|
||||
if(!getAttribute(player, "pp:mummy-spoken-to", false))
|
||||
{
|
||||
openDialogue(player, NPCs.GUARDIAN_MUMMY_4476)
|
||||
return@on true
|
||||
}
|
||||
|
||||
join(player)
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic val GUARDIAN_ROOM = Location.create(1968, 4420, 2)
|
||||
@JvmStatic val EMPTY_ROOM = Location.create(1934, 4450, 2)
|
||||
|
||||
@JvmStatic fun join(player: Player)
|
||||
{
|
||||
if(PlunderUtils.hasPlayer(player))
|
||||
{
|
||||
sendMessage(player, "[PLUNDER] You should never see this message. Please report this.")
|
||||
return
|
||||
}
|
||||
PlunderUtils.registerPlayer(player)
|
||||
PlunderUtils.loadNextRoom(player)
|
||||
PlunderUtils.openOverlay(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
|
||||
player.hook(Event.Tick, instance)
|
||||
setAttribute(player, "random-manager", instance)
|
||||
instance.rollNextSpawn()
|
||||
instance.enabled = true
|
||||
SystemLogger.logRE("Initialized REManager for ${player.username}.")
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ object DrillDemonUtils {
|
||||
}
|
||||
|
||||
fun getMatTask(id: Int, player: Player): Int{
|
||||
return player.varpManager.get(DD_SIGN_VARP).getVarbitValue(getOffsetForID(id))
|
||||
return player.varpManager.get(DD_SIGN_VARP).getVarbitValue(getOffsetForID(id)) ?: 0
|
||||
}
|
||||
|
||||
fun cleanup(player: Player){
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package rs09.game.content.dialogue.region.sophanem
|
||||
|
||||
import api.setAttribute
|
||||
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
|
||||
import rs09.tools.END_DIALOGUE
|
||||
|
||||
@Initializable
|
||||
class TarikDialogue(player: Player? = null) : DialoguePlugin(player) {
|
||||
override fun open(vararg args: Any?): Boolean {
|
||||
npcl(FacialExpression.WORRIED, "Ouch!")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
|
||||
when(stage)
|
||||
{
|
||||
0 -> playerl(FacialExpression.HALF_WORRIED, "Are you alright?").also { stage++ }
|
||||
1 -> npcl(FacialExpression.FRIENDLY, "I'm fine, I'm fine. Just a scratch.").also { stage++ }
|
||||
2 -> options("Who are you then?","How did you injure yourself?","Do you know anything about this pyramid?").also { stage++ }
|
||||
3 -> when(buttonId) {
|
||||
1 -> playerl(FacialExpression.FRIENDLY, "Who are you then?").also { stage = 10 }
|
||||
2 -> playerl(FacialExpression.HALF_WORRIED, "How did you injure yourself?").also { stage = 20 }
|
||||
3 -> playerl(FacialExpression.HALF_ASKING, "So what's in the pyramid?").also { stage = 30 }
|
||||
}
|
||||
|
||||
//Who are you
|
||||
10 -> npcl(FacialExpression.FRIENDLY, "Me? I'm Tarik.").also { stage++ }
|
||||
11 -> playerl(FacialExpression.HALF_ASKING, "That hat you're wearing doesn't look like it comes from around here?").also { stage++ }
|
||||
12 -> npcl(FacialExpression.FRIENDLY, "It was a present, my employer thought it would suit me. I'm not sure what it does, though it does keep the sun off very well.").also { stage++ }
|
||||
13 -> playerl(FacialExpression.FRIENDLY, "Who is your employer then?").also { stage++ }
|
||||
14 -> npcl(FacialExpression.FRIENDLY, "Simon Templeton, though I haven't seen him since the town gates were closed off.").also { stage++ }
|
||||
15 -> playerl(FacialExpression.HALF_THINKING, "Simon Templeton ... that name seems familiar?").also { stage++ }
|
||||
16 -> npcl(FacialExpression.FRIENDLY, "He's an archaeologist, I worked as an assistant for him. Though I work for myself now.").also { stage++ }
|
||||
17 -> playerl(FacialExpression.FRIENDLY, "So what have you been up to?").also { stage++ }
|
||||
18 -> npcl(FacialExpression.FRIENDLY, "Simon suggested that there might be riches to be found in that pyramid over there.").also { stage = 30 }
|
||||
|
||||
//How did you injure yourself
|
||||
20 -> npcl(FacialExpression.NEUTRAL, "I've been investigating that pyramid over there.").also { stage = 30 }
|
||||
|
||||
//Do you know anything about this pyramid?
|
||||
30 -> npcl(FacialExpression.HALF_THINKING, "Well, I'm not sure. First of all there's something odd about the doors on the place. There's four of them - but three of them lead to an empty tomb. The other one is guarded by something.").also { stage++ }
|
||||
31 -> npcl(FacialExpression.THINKING, "If I make it through the door there's a Mummy waiting. But which door the right one is seems to change, it's all quite confusing.").also { stage++ }
|
||||
32 -> playerl(FacialExpression.HALF_ASKING, "What about this Mummy?").also { stage++ }
|
||||
33 -> npcl(FacialExpression.FRIENDLY, "I don't think he likes people. However he does allow you to enter some of the rooms in the tomb. They are dangerous though.").also { stage++ }
|
||||
34 -> playerl(FacialExpression.HAPPY, "Bah, I laugh in the face of danger!").also { stage++ }
|
||||
35 -> npcl(FacialExpression.FRIENDLY, "Well, if you go into that pyramid then you'll be laughing a lot then. It's full of poisonous snakes and scarabs, and rather nasty Mummies as well. You could die in there.").also { stage++ }
|
||||
36 -> npcl(FacialExpression.FRIENDLY, "I managed to get into one room, but the next room was harder. My lockpicking skills weren't good enough, maybe I should have brought a lockpick.").also { stage++ }
|
||||
37 -> api.sendDialogue(player, "The first room in the pyramid requires a thieving level of 21. Each subsequent room requires an extra 10 levels to enter.").also { stage++ }
|
||||
38 -> npcl(FacialExpression.NEUTRAL, "There are also lots of poisonous snakes in the urns. They'll bite you if they can. You might be able to charm them if you know how. I'd bring some antipoison anyway if I were you.").also { stage++ }
|
||||
39 -> playerl(FacialExpression.FRIENDLY, "It all sounds like fun to me. So is there anything valuable in there?").also { stage++ }
|
||||
40 -> npcl(FacialExpression.NEUTRAL, "There are lots of artefacts, you should be able to sell them on the black market, I mean, to a legitimate trader, for some money.").also { stage++ }
|
||||
41 -> playerl(FacialExpression.NEUTRAL, "You mean Simon Templeton?").also { stage++ }
|
||||
42 -> npcl(FacialExpression.NEUTRAL, "Well, he's a 'legitimate' as you can get, if you can get out of this city and get to him.").also { stage++ }
|
||||
43 -> playerl(FacialExpression.FRIENDLY, "I'll find a way. Is there anything else of value in there?").also { stage++ }
|
||||
44 -> npcl(FacialExpression.SUSPICIOUS, "I have heard a rumour that there is a valuable magic sceptre in there as well.").also { stage++ }
|
||||
45 -> playerl(FacialExpression.HALF_THINKING, "Ah, now you have piqued my interest. What do you know about this sceptre?").also { stage++ }
|
||||
46 -> npcl(FacialExpression.SUSPICIOUS, "Not a lot. It is apparently made of gold and covered in jewels, and used to be owned by one of Tumeken's sons.").also { stage++ }
|
||||
47 -> playerl(FacialExpression.HALF_ASKING, "Tumeken?").also { setAttribute(player, "/save:tarik-spoken-to", true); stage++ }
|
||||
48 -> npcl(FacialExpression.NEUTRAL, "Tumeken, the sun god and head of the gods. His sons were the rulers, chosen by him to rule in his name.").also { stage++ }
|
||||
49 -> playerl(FacialExpression.HALF_THINKING, "So these sons were rich and powerful then? This sceptre should be pretty good then.").also { stage++ }
|
||||
50 -> npcl(FacialExpression.NEUTRAL, "Hmmm. Well it is supposed to have some magical powers.").also { stage++ }
|
||||
51 -> playerl(FacialExpression.HALF_ASKING, "Magical powers? This sounds good. What are they?").also { stage++ }
|
||||
52 -> npcl(FacialExpression.LAUGH, "I'll let you know when I find it!").also { stage++ }
|
||||
53 -> playerl(FacialExpression.ANNOYED, "Not if I find it first!").also { stage++ }
|
||||
54 -> npcl(FacialExpression.FRIENDLY, "Hey! If you find it I deserve a share of the profits! You wouldn't have known it existed without my help.").also { stage++ }
|
||||
55 -> playerl(FacialExpression.NEUTRAL, "I'll think about it... Right, I think I'd better investigate this place.").also { stage = END_DIALOGUE }
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getIds(): IntArray {
|
||||
return intArrayOf(NPCs.TARIK_4478)
|
||||
}
|
||||
|
||||
override fun newInstance(player: Player?): DialoguePlugin {
|
||||
return TarikDialogue(player)
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ class PlayerSaveParser(val player: Player) {
|
||||
}
|
||||
}
|
||||
|
||||
fun parse() = GlobalScope.launch {
|
||||
fun parse() {
|
||||
if (read) {
|
||||
parseCore()
|
||||
parseAttributes()
|
||||
|
||||
@@ -88,7 +88,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
|
||||
}
|
||||
|
||||
fun getCurrentState(): Int{
|
||||
return player.varpManager.get(patch.varpIndex).getVarbitValue(patch.varpOffset)
|
||||
return player.varpManager.get(patch.varpIndex).getVarbitValue(patch.varpOffset) ?: 0
|
||||
}
|
||||
|
||||
fun setCurrentState(state: Int){
|
||||
|
||||
@@ -188,7 +188,7 @@ class VisualCommand : CommandPlugin() {
|
||||
player!!.debug("syntax error: x y id")
|
||||
return true
|
||||
}
|
||||
location = if (args.size > 2) Location.create(args[1]!!.toInt(), args[2]!!.toInt(), 3) else player!!.location
|
||||
location = if (args.size > 2) Location.create(args[1]!!.toInt(), args[2]!!.toInt(), player!!.location.z) else player!!.location
|
||||
`object` = RegionManager.getObject(location)
|
||||
if (`object` == null) {
|
||||
player!!.debug("error: object not found in region cache.")
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
package rs09.game.system.command.sets
|
||||
|
||||
import api.sendMessage
|
||||
import core.cache.Cache
|
||||
import core.cache.def.impl.NPCDefinition
|
||||
import core.cache.def.impl.VarbitDefinition
|
||||
import core.game.node.entity.combat.ImpactHandler.HitsplatType
|
||||
import core.game.node.entity.npc.drop.NPCDropTables
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.link.SpellBookManager
|
||||
import core.game.node.item.Item
|
||||
import core.net.packet.context.PlayerContext
|
||||
import core.net.packet.out.ResetInterface
|
||||
import core.net.packet.out.Varbit
|
||||
import core.plugin.Initializable
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rs09.consts.Items
|
||||
import rs09.game.content.global.NPCDropTable
|
||||
import rs09.game.system.command.Command
|
||||
import rs09.game.system.command.Privilege
|
||||
import rs09.net.packet.PacketWriteQueue
|
||||
|
||||
@Initializable
|
||||
class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
|
||||
@@ -57,5 +66,28 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
|
||||
|
||||
container.open(player)
|
||||
}
|
||||
|
||||
define("varbits") { player, args ->
|
||||
if(args.size < 2)
|
||||
reject(player, "Usage: ::list_varbits varpIndex")
|
||||
|
||||
val varp = args[1].toIntOrNull() ?: reject(player, "Please use a valid int for the varpIndex.")
|
||||
GlobalScope.launch {
|
||||
sendMessage(player, "========== Found Varbits for Varp $varp ==========")
|
||||
for(id in 0 until 10000)
|
||||
{
|
||||
val def = VarbitDefinition.forId(id)
|
||||
if(def.configId == varp)
|
||||
{
|
||||
sendMessage(player, "${def.id} -> [offset: ${def.bitShift}, upperBound: ${def.bitSize}]")
|
||||
}
|
||||
}
|
||||
sendMessage(player, "=========================================")
|
||||
}
|
||||
}
|
||||
|
||||
define("testpacket") { player, _ ->
|
||||
PacketWriteQueue.write(ResetInterface(), PlayerContext(player))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import rs09.game.content.ame.RandomEvents
|
||||
import rs09.game.ge.GrandExchange
|
||||
import rs09.game.node.entity.state.newsys.states.FarmingState
|
||||
import rs09.game.system.SystemLogger
|
||||
import rs09.game.system.command.Command
|
||||
import rs09.game.system.command.CommandMapping
|
||||
import rs09.game.system.command.Privilege
|
||||
import rs09.game.world.repository.Repository
|
||||
@@ -342,10 +341,10 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
||||
reject(player, "Syntax: ::define_varbit varbitId")
|
||||
}
|
||||
val varbitID = args[1].toInt()
|
||||
notify(player, "${varbitID}: ${VarbitDefinition.forId(varbitID, 0)}")
|
||||
notify(player, "${varbitID}: ${VarbitDefinition.forId(varbitID)}")
|
||||
}
|
||||
define("togglexp", Privilege.STANDARD){ player, args ->
|
||||
val enabled = player.varpManager.get(2501).getVarbit(0)?.value == 1
|
||||
val enabled = player.varpManager.get(2501).getVarbit(0) == 1
|
||||
player.varpManager.get(2501).setVarbit(0,if(enabled) 0 else 1).send(player)
|
||||
notify(player, "XP drops are now " + colorize("%R" + if(!enabled) "ON." else "OFF."))
|
||||
player.varpManager.flagSave(2501)
|
||||
@@ -406,7 +405,7 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
||||
}
|
||||
|
||||
define("toggleslayer", Privilege.STANDARD){ player, _ ->
|
||||
val disabled = player.varpManager.get(2502).getVarbit(0)?.value == 1
|
||||
val disabled = player.varpManager.get(2502).getVarbit(0) == 1
|
||||
player.varpManager.get(2502).setVarbit(0,if(disabled) 0 else 1).send(player)
|
||||
if(!disabled){
|
||||
player.varpManager.flagSave(2502)
|
||||
@@ -418,19 +417,35 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
||||
|
||||
define("setvarbit", Privilege.ADMIN){
|
||||
player,args ->
|
||||
if(args.size != 3){
|
||||
reject(player,"Usage: ::setvarbit varbit value")
|
||||
}
|
||||
val index = args[1].toIntOrNull()
|
||||
val value = args[3].toIntOrNull()
|
||||
|
||||
if(index == null || value == null){
|
||||
reject(player,"Usage ::setvarbit index offset value")
|
||||
}
|
||||
|
||||
player.varpManager.setVarbit(index!!, value!!)
|
||||
}
|
||||
|
||||
define("setvarp", Privilege.ADMIN){
|
||||
player,args ->
|
||||
if(args.size < 4){
|
||||
reject(player,"Usage: ::setvarbit index offset value")
|
||||
reject(player,"Usage: ::setvarp index offset value")
|
||||
}
|
||||
val index = args[1].toIntOrNull()
|
||||
val offset = args[2].toIntOrNull()
|
||||
val value = args[3].toIntOrNull()
|
||||
|
||||
if(index == null || offset == null || value == null){
|
||||
reject(player,"Usage ::setvarbit index offset value")
|
||||
reject(player,"Usage ::setvarp index offset value")
|
||||
}
|
||||
|
||||
player.varpManager.get(index!!).setVarbit(offset!!, value!!).send(player)
|
||||
}
|
||||
|
||||
define("setvarc", Privilege.ADMIN) { player, args ->
|
||||
if(args.size < 3){
|
||||
reject(player,"Usage: ::setvarc index value")
|
||||
|
||||
@@ -1,49 +1,88 @@
|
||||
package rs09.net.packet
|
||||
|
||||
import api.TickListener
|
||||
import core.net.packet.OutgoingPacket
|
||||
import core.net.packet.out.*
|
||||
import gui.GuiEvent
|
||||
import rs09.game.system.SystemLogger
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
object PacketWriteQueue {
|
||||
private val PacketsToWrite: Queue<QueuedPacket<*>> = LinkedList<QueuedPacket<*>>()
|
||||
|
||||
@JvmStatic
|
||||
fun <T> handle(packet: OutgoingPacket<T>, context: T){
|
||||
when(packet){
|
||||
//Dynamic packets need to be sent immediately
|
||||
is UpdateSceneGraph,
|
||||
is BuildDynamicScene,
|
||||
is InstancedLocationUpdate,
|
||||
is ClearRegionChunk -> packet.send(context)
|
||||
//Rest get queued up and sent at the end of the tick (authentic)
|
||||
else -> queue(packet,context)
|
||||
}
|
||||
class PacketWriteQueue : TickListener {
|
||||
override fun tick() {
|
||||
flush()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <T> queue(packet: OutgoingPacket<T>, context: T){
|
||||
PacketsToWrite.add(QueuedPacket(packet,context))
|
||||
}
|
||||
companion object {
|
||||
private val queueLock = ReentrantLock()
|
||||
private val packetsToQueue = ArrayList<QueuedPacket<*>>(1000)
|
||||
private val packetsToWrite = LinkedList<QueuedPacket<*>>()
|
||||
|
||||
@JvmStatic
|
||||
fun flush(){
|
||||
while(!PacketsToWrite.isEmpty()){
|
||||
val p = PacketsToWrite.poll() ?: continue
|
||||
write(p.out,p.context)
|
||||
@JvmStatic
|
||||
fun <T> handle(packet: OutgoingPacket<T>, context: T) {
|
||||
when (packet) {
|
||||
//Dynamic packets need to be sent immediately
|
||||
is UpdateSceneGraph,
|
||||
is BuildDynamicScene,
|
||||
is InstancedLocationUpdate,
|
||||
is ClearRegionChunk -> packet.send(context)
|
||||
//Rest get queued up and sent at the end of the tick (authentic)
|
||||
else -> push(packet, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> write(out: OutgoingPacket<*>, context: T){
|
||||
val pack = out as? OutgoingPacket<T>
|
||||
val ctx = context as? T
|
||||
if(pack == null || ctx == null){
|
||||
SystemLogger.logWarn("Failed packet casting")
|
||||
return
|
||||
@JvmStatic
|
||||
fun <T> push(packet: OutgoingPacket<T>, context: T) {
|
||||
if (queueLock.isLocked)
|
||||
packetsToQueue.add(QueuedPacket(packet, context))
|
||||
else
|
||||
packetsToWrite.add(QueuedPacket(packet, context))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun pop(): QueuedPacket<*>? {
|
||||
return try {
|
||||
packetsToWrite.pop()
|
||||
} catch (e: NoSuchElementException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun flush() {
|
||||
queueLock.lock()
|
||||
var packet: QueuedPacket<*>?
|
||||
while (pop().also { packet = it } != null)
|
||||
write(packet?.out ?: break, packet?.context ?: break)
|
||||
if (packetsToWrite.isNotEmpty()) {
|
||||
SystemLogger.logWarn("Packet queue was NOT empty! Remaining packets: ${packetsToWrite.size}")
|
||||
try {
|
||||
for (pkt in packetsToWrite) SystemLogger.logWarn("${pkt.out.javaClass.simpleName} <- ${pkt.context}")
|
||||
} catch (e: Exception)
|
||||
{
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
packetsToWrite.clear()
|
||||
}
|
||||
}
|
||||
val queueIter = packetsToQueue.iterator()
|
||||
while (queueIter.hasNext()) {
|
||||
packetsToWrite.add(queueIter.next())
|
||||
queueIter.remove()
|
||||
}
|
||||
queueLock.unlock()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> write(out: OutgoingPacket<*>, context: T) {
|
||||
val pack = out as? OutgoingPacket<T>
|
||||
val ctx = context as? T
|
||||
if (pack == null || ctx == null) {
|
||||
SystemLogger.logWarn("Failed packet casting")
|
||||
return
|
||||
}
|
||||
pack.send(ctx)
|
||||
}
|
||||
pack.send(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import rs09.game.node.entity.player.info.login.PlayerSaveParser
|
||||
import rs09.game.node.entity.player.info.login.PlayerSaver
|
||||
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
|
||||
|
||||
@@ -79,9 +79,6 @@ class MajorUpdateWorker {
|
||||
sequence.start()
|
||||
sequence.run()
|
||||
sequence.end()
|
||||
GlobalScope.launch {
|
||||
PacketWriteQueue.flush()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user