Rewrote Pyramid Plunder Minigame, features improved authenticity amongst other improvements

This commit is contained in:
Ceikry
2022-04-05 03:12:28 +00:00
committed by Ryan
parent 24b28d84fd
commit 1f68dbaed0
44 changed files with 1303 additions and 1657 deletions
+1 -1
View File
@@ -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
}
}
+2 -2
View File
@@ -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
}
/**
+13 -26
View File
@@ -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]
}
}
@@ -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
}
}
@@ -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
@@ -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)
}
}
@@ -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()
}