Random event manager rewrite
Time until next random event now persists across logins Events will no longer spawn while the player has an interface like the bank open Replaced the slurry of random event commands with a singular ::revent admin command Random events now support being associated with multiple skills Random event selection is now more robust Players will no longer get skill-based random events if more than 2.5 minutes have passed since training the skill
This commit is contained in:
@@ -1,94 +0,0 @@
|
|||||||
package content.global.ame
|
|
||||||
|
|
||||||
import core.api.*
|
|
||||||
import core.game.event.EventHook
|
|
||||||
import core.game.event.TickEvent
|
|
||||||
import core.game.node.entity.Entity
|
|
||||||
import core.game.node.entity.player.Player
|
|
||||||
import core.game.world.map.zone.ZoneRestriction
|
|
||||||
import core.tools.RandomFunction
|
|
||||||
import core.tools.SystemLogger
|
|
||||||
import core.game.system.command.Privilege
|
|
||||||
import core.game.world.GameWorld
|
|
||||||
import core.game.world.repository.Repository
|
|
||||||
import core.tools.Log
|
|
||||||
import kotlin.random.Random
|
|
||||||
import content.global.ame.RandomEvents
|
|
||||||
|
|
||||||
class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<TickEvent>, Commands {
|
|
||||||
var event: content.global.ame.RandomEventNPC? = null
|
|
||||||
var enabled: Boolean = false
|
|
||||||
var nextSpawn = 0
|
|
||||||
val skills = arrayOf("WoodcuttingSkillPulse","FishingPulse","MiningSkillPulse","BoneBuryingOptionPlugin")
|
|
||||||
|
|
||||||
override fun login(player: Player) {
|
|
||||||
if(player.isArtificial) return
|
|
||||||
val instance = RandomEventManager(player)
|
|
||||||
player.hook(Event.Tick, instance)
|
|
||||||
setAttribute(player, "random-manager", instance)
|
|
||||||
instance.rollNextSpawn()
|
|
||||||
instance.enabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun process(entity: Entity, event: TickEvent) {
|
|
||||||
if (GameWorld.ticks > nextSpawn && getAttribute(player!!, "tutorial:complete", false)) fireEvent()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fireEvent() {
|
|
||||||
if(!enabled){
|
|
||||||
rollNextSpawn()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (player!!.zoneMonitor.isRestricted(ZoneRestriction.RANDOM_EVENTS)) {
|
|
||||||
rollNextSpawn()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (getAttribute<content.global.ame.RandomEventNPC?>(player, "re-npc", null) != null) return
|
|
||||||
val currentAction = player.pulseManager.current?.toString() ?: "None"
|
|
||||||
|
|
||||||
//Give us a decent pool of events to pick from randomly, with the skill-based random event mixed in if applicable.
|
|
||||||
//This is just to provide a bit more randomization (you don't want to get the skill-based randoms EVERY TIME when training woodcutting, for example.)
|
|
||||||
val ame = listOf (
|
|
||||||
RandomEvents.getSkillBasedRandomEvent (player.skills.lastTrainedSkill),
|
|
||||||
RandomEvents.getNonSkillRandom(),
|
|
||||||
RandomEvents.getNonSkillRandom()
|
|
||||||
).filter{ it != null }.random() ?: RandomEvents.getNonSkillRandom() //Absolute cosmic bit-flip tier safety fallback
|
|
||||||
|
|
||||||
event = ame.npc.create(player,ame.loot,ame.type)
|
|
||||||
if (event!!.spawnLocation == null) {
|
|
||||||
nextSpawn = GameWorld.ticks + 3000
|
|
||||||
log(this::class.java, Log.WARN, "Tried to spawn random event for ${player.username} but spawn location was null!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
event!!.init()
|
|
||||||
rollNextSpawn()
|
|
||||||
log(this::class.java, Log.FINE, "Fired ${event!!.name} for ${player.username}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun rollNextSpawn() {
|
|
||||||
nextSpawn = GameWorld.ticks + RandomFunction.random(MIN_DELAY_TICKS, MAX_DELAY_TICKS)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun defineCommands() {
|
|
||||||
define("targeted-ame", Privilege.ADMIN, "targeted-ame username", "Summons a random for the given user") {player, args ->
|
|
||||||
val username = args[1]
|
|
||||||
val target = Repository.getPlayerByName(username)
|
|
||||||
|
|
||||||
if (target == null)
|
|
||||||
reject(player, "Unable to find player $username!")
|
|
||||||
|
|
||||||
getInstance(target!!)?.fireEvent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
var AVG_DELAY_TICKS = 6000 // 60 minutes
|
|
||||||
var MIN_DELAY_TICKS = AVG_DELAY_TICKS / 2
|
|
||||||
var MAX_DELAY_TICKS = MIN_DELAY_TICKS + AVG_DELAY_TICKS // window of 60 min centered on 60 min (30 to 90 min)
|
|
||||||
|
|
||||||
@JvmStatic fun getInstance(player: Player): RandomEventManager?
|
|
||||||
{
|
|
||||||
return getAttribute(player, "random-manager", null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -39,7 +39,6 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
|
|||||||
open fun terminate() {
|
open fun terminate() {
|
||||||
finalized = true
|
finalized = true
|
||||||
pulseManager.clear(PulseType.STANDARD)
|
pulseManager.clear(PulseType.STANDARD)
|
||||||
content.global.ame.RandomEventManager.getInstance(player)?.event = null
|
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
poofClear(this)
|
poofClear(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import core.api.utils.WeightBasedTable
|
|||||||
import core.api.utils.WeightedItem
|
import core.api.utils.WeightedItem
|
||||||
import core.game.node.entity.skill.Skills
|
import core.game.node.entity.skill.Skills
|
||||||
|
|
||||||
enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = null, val skillId: Int = -1, val type: String = "") {
|
enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = null, val skillIds: IntArray = intArrayOf(), val type: String = "") {
|
||||||
SANDWICH_LADY(npc = SandwichLadyRENPC()),
|
SANDWICH_LADY(npc = SandwichLadyRENPC()),
|
||||||
GENIE(npc = GenieNPC()),
|
GENIE(npc = GenieNPC()),
|
||||||
CERTER(npc = CerterNPC(), loot = WeightBasedTable.create(
|
CERTER(npc = CerterNPC(), loot = WeightBasedTable.create(
|
||||||
@@ -41,14 +41,14 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
|
|||||||
)),
|
)),
|
||||||
DRILL_DEMON(npc = SeargentDamienNPC()),
|
DRILL_DEMON(npc = SeargentDamienNPC()),
|
||||||
EVIL_CHICKEN(npc = EvilChickenNPC()),
|
EVIL_CHICKEN(npc = EvilChickenNPC()),
|
||||||
EVIL_BOB(npc = EvilBobNPC(), skillId = Skills.FISHING),
|
EVIL_BOB(npc = EvilBobNPC(), skillIds = intArrayOf(Skills.FISHING, Skills.MAGIC)),
|
||||||
SURPRISE_EXAM(npc = MysteriousOldManNPC(), type = "sexam"),
|
SURPRISE_EXAM(npc = MysteriousOldManNPC(), type = "sexam"),
|
||||||
FREAKY_FORESTER(npc = FreakyForesterNPC(), skillId = Skills.WOODCUTTING),
|
FREAKY_FORESTER(npc = FreakyForesterNPC(), skillIds = intArrayOf(Skills.WOODCUTTING)),
|
||||||
TREE_SPIRIT(npc = TreeSpiritRENPC(), skillId = Skills.WOODCUTTING),
|
TREE_SPIRIT(npc = TreeSpiritRENPC(), skillIds = intArrayOf(Skills.WOODCUTTING)),
|
||||||
RIVER_TROLL(RiverTrollRENPC(), skillId = Skills.FISHING),
|
RIVER_TROLL(RiverTrollRENPC(), skillIds = intArrayOf(Skills.FISHING)),
|
||||||
ROCK_GOLEM(RockGolemRENPC(), skillId = Skills.MINING),
|
ROCK_GOLEM(RockGolemRENPC(), skillIds = intArrayOf(Skills.MINING)),
|
||||||
SHADE(ShadeRENPC(), skillId = Skills.PRAYER),
|
SHADE(ShadeRENPC(), skillIds = intArrayOf(Skills.PRAYER)),
|
||||||
ZOMBIE(ZombieRENPC(), skillId = Skills.PRAYER);
|
ZOMBIE(ZombieRENPC(), skillIds = intArrayOf(Skills.PRAYER));
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -68,11 +68,12 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
|
|||||||
|
|
||||||
private fun populateMappings() {
|
private fun populateMappings() {
|
||||||
for (event in values()) {
|
for (event in values()) {
|
||||||
if (event.skillId != -1) {
|
for (id in event.skillIds) {
|
||||||
val list = skillMap[event.skillId] ?: ArrayList<RandomEvents>().also { skillMap[event.skillId] = it }
|
val list = skillMap[id] ?: ArrayList<RandomEvents>().also { skillMap[id] = it }
|
||||||
list.add (event)
|
list.add (event)
|
||||||
}
|
}
|
||||||
else nonSkillList.add (event)
|
if (event.skillIds.isEmpty())
|
||||||
|
nonSkillList.add (event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package content.global.ame.events
|
|||||||
import core.game.node.entity.player.Player
|
import core.game.node.entity.player.Player
|
||||||
import content.global.ame.events.supriseexam.SurpriseExamUtils
|
import content.global.ame.events.supriseexam.SurpriseExamUtils
|
||||||
import core.game.dialogue.DialogueFile
|
import core.game.dialogue.DialogueFile
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
|
|
||||||
class MysteriousOldManDialogue(val type: String) : DialogueFile() {
|
class MysteriousOldManDialogue(val type: String) : DialogueFile() {
|
||||||
|
|
||||||
@@ -22,11 +23,11 @@ class MysteriousOldManDialogue(val type: String) : DialogueFile() {
|
|||||||
1 -> {
|
1 -> {
|
||||||
end()
|
end()
|
||||||
teleport(player!!,type)
|
teleport(player!!,type)
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)?.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
end()
|
end()
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)?.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import core.game.component.Component
|
|||||||
import core.game.node.entity.impl.PulseType
|
import core.game.node.entity.impl.PulseType
|
||||||
import core.game.node.entity.player.link.emote.Emotes
|
import core.game.node.entity.player.link.emote.Emotes
|
||||||
import core.game.dialogue.DialogueFile
|
import core.game.dialogue.DialogueFile
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import core.tools.END_DIALOGUE
|
import core.tools.END_DIALOGUE
|
||||||
|
|
||||||
class CerterDialogue(val initial: Boolean) : DialogueFile() {
|
class CerterDialogue(val initial: Boolean) : DialogueFile() {
|
||||||
@@ -30,13 +31,13 @@ class CerterDialogue(val initial: Boolean) : DialogueFile() {
|
|||||||
npc("Sorry, I don't think so.").also {
|
npc("Sorry, I don't think so.").also {
|
||||||
player!!.setAttribute("certer:reward", true)
|
player!!.setAttribute("certer:reward", true)
|
||||||
stage = END_DIALOGUE
|
stage = END_DIALOGUE
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)?.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
npc("Thank you, I hope you like your present. I must be", "leaving now though.").also {
|
npc("Thank you, I hope you like your present. I must be", "leaving now though.").also {
|
||||||
player!!.setAttribute("certer:reward", true)
|
player!!.setAttribute("certer:reward", true)
|
||||||
stage = END_DIALOGUE
|
stage = END_DIALOGUE
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)!!.event!!.loot!!.roll().forEach { addItemOrDrop(player!!, it.id, it.amount) }
|
AntiMacro.rollEventLoot(player!!).forEach { addItemOrDrop(player!!, it.id, it.amount) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +52,7 @@ class CerterDialogue(val initial: Boolean) : DialogueFile() {
|
|||||||
// Wave goodbye
|
// Wave goodbye
|
||||||
npc!!.animate(Emotes.WAVE.animation)
|
npc!!.animate(Emotes.WAVE.animation)
|
||||||
// Terminate the event
|
// Terminate the event
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)?.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
} else {
|
} else {
|
||||||
player!!.setAttribute("random:pause", false)
|
player!!.setAttribute("random:pause", false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package content.global.ame.events.certer
|
package content.global.ame.events.certer
|
||||||
|
|
||||||
import content.global.ame.RandomEventManager
|
|
||||||
import core.game.node.entity.player.Player
|
import core.game.node.entity.player.Player
|
||||||
import core.game.node.item.Item
|
import core.game.node.item.Item
|
||||||
import org.rs09.consts.Items
|
import org.rs09.consts.Items
|
||||||
import core.game.interaction.InterfaceListener
|
import core.game.interaction.InterfaceListener
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
|
|
||||||
class CerterEventInterface : InterfaceListener {
|
class CerterEventInterface : InterfaceListener {
|
||||||
val CERTER_INTERFACE = 184
|
val CERTER_INTERFACE = 184
|
||||||
@@ -37,7 +37,7 @@ class CerterEventInterface : InterfaceListener {
|
|||||||
val correctAnswer = player.getAttribute("certer:correctIndex", 0)
|
val correctAnswer = player.getAttribute("certer:correctIndex", 0)
|
||||||
player.setAttribute("certer:correct", correctAnswer == answer)
|
player.setAttribute("certer:correct", correctAnswer == answer)
|
||||||
player.interfaceManager.close()
|
player.interfaceManager.close()
|
||||||
player.dialogueInterpreter.open(CerterDialogue(false), RandomEventManager.getInstance(player)!!.event?.asNpc())
|
player.dialogueInterpreter.open(CerterDialogue(false), AntiMacro.getEventNpc(player))
|
||||||
return@on true
|
return@on true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package content.global.ame.events.drilldemon
|
package content.global.ame.events.drilldemon
|
||||||
|
|
||||||
import core.game.dialogue.FacialExpression
|
|
||||||
import core.game.system.task.Pulse
|
import core.game.system.task.Pulse
|
||||||
import core.game.dialogue.DialogueFile
|
import core.game.dialogue.DialogueFile
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import core.tools.END_DIALOGUE
|
import core.tools.END_DIALOGUE
|
||||||
import core.tools.START_DIALOGUE
|
import core.tools.START_DIALOGUE
|
||||||
|
|
||||||
class SeargentDamienDialogue(val isCorrect: Boolean = false) : DialogueFile() {
|
class SeargentDamienDialogue(val isCorrect: Boolean = false) : DialogueFile() {
|
||||||
override fun handle(componentID: Int, buttonID: Int) {
|
override fun handle(componentID: Int, buttonID: Int) {
|
||||||
var correctAmt = player!!.getAttribute(DrillDemonUtils.DD_CORRECT_COUNTER,0)
|
var correctAmt = player!!.getAttribute(DrillDemonUtils.DD_CORRECT_COUNTER,0)
|
||||||
if(correctAmt == 4 && content.global.ame.RandomEventManager.getInstance(player!!)!!.event == null) {
|
if(correctAmt == 4 && AntiMacro.getEventNpc(player!!) == null) {
|
||||||
when(stage){
|
when(stage){
|
||||||
0 -> npc(core.game.dialogue.FacialExpression.OLD_NORMAL,"My god you actually did it, you limp","wristed worm-bodied MAGGOT! Take this","and get out of my sight.").also { stage++ }
|
0 -> npc(core.game.dialogue.FacialExpression.OLD_NORMAL,"My god you actually did it, you limp","wristed worm-bodied MAGGOT! Take this","and get out of my sight.").also { stage++ }
|
||||||
1 -> {
|
1 -> {
|
||||||
@@ -24,7 +24,7 @@ class SeargentDamienDialogue(val isCorrect: Boolean = false) : DialogueFile() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(content.global.ame.RandomEventManager.getInstance(player!!)!!.event == null){
|
} else if(AntiMacro.getEventNpc(player!!) == null){
|
||||||
when(stage){
|
when(stage){
|
||||||
START_DIALOGUE -> if(isCorrect) npc(core.game.dialogue.FacialExpression.OLD_NORMAL,"Good! Now...").also { stage++ } else npc(core.game.dialogue.FacialExpression.OLD_ANGRY1,"WRONG, MAGGOT!").also { stage++ }
|
START_DIALOGUE -> if(isCorrect) npc(core.game.dialogue.FacialExpression.OLD_NORMAL,"Good! Now...").also { stage++ } else npc(core.game.dialogue.FacialExpression.OLD_ANGRY1,"WRONG, MAGGOT!").also { stage++ }
|
||||||
1 -> {
|
1 -> {
|
||||||
@@ -40,12 +40,12 @@ class SeargentDamienDialogue(val isCorrect: Boolean = false) : DialogueFile() {
|
|||||||
1 -> {
|
1 -> {
|
||||||
end()
|
end()
|
||||||
DrillDemonUtils.teleport(player!!)
|
DrillDemonUtils.teleport(player!!)
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)!!.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
stage = END_DIALOGUE
|
stage = END_DIALOGUE
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
end()
|
end()
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)!!.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
stage = END_DIALOGUE
|
stage = END_DIALOGUE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import content.global.ame.RandomEventNPC
|
|||||||
import core.api.*
|
import core.api.*
|
||||||
import core.api.utils.WeightBasedTable
|
import core.api.utils.WeightBasedTable
|
||||||
import core.game.node.entity.npc.NPC
|
import core.game.node.entity.npc.NPC
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import org.rs09.consts.NPCs
|
import org.rs09.consts.NPCs
|
||||||
import org.rs09.consts.Sounds
|
import org.rs09.consts.Sounds
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ class EvilBobNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(N
|
|||||||
EvilBobUtils.teleport(player)
|
EvilBobUtils.teleport(player)
|
||||||
resetAnimator(player)
|
resetAnimator(player)
|
||||||
openDialogue(player, EvilBobDialogue(), NPCs.EVIL_BOB_2479)
|
openDialogue(player, EvilBobDialogue(), NPCs.EVIL_BOB_2479)
|
||||||
content.global.ame.RandomEventManager.getInstance(player)?.event?.terminate()
|
AntiMacro.terminateEventNpc(player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package content.global.ame.events.freakyforester
|
package content.global.ame.events.freakyforester
|
||||||
|
|
||||||
import content.global.ame.RandomEventManager
|
|
||||||
import content.global.ame.RandomEventNPC
|
import content.global.ame.RandomEventNPC
|
||||||
import core.api.*
|
import core.api.*
|
||||||
import org.rs09.consts.NPCs
|
import org.rs09.consts.NPCs
|
||||||
import core.api.utils.WeightBasedTable
|
import core.api.utils.WeightBasedTable
|
||||||
import core.game.node.entity.npc.NPC
|
import core.game.node.entity.npc.NPC
|
||||||
import core.game.system.task.Pulse
|
import core.game.system.task.Pulse
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import core.game.world.update.flag.context.Graphics
|
import core.game.world.update.flag.context.Graphics
|
||||||
import org.rs09.consts.Sounds
|
import org.rs09.consts.Sounds
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ class FreakyForesterNPC(override var loot: WeightBasedTable? = null) : RandomEve
|
|||||||
7 -> {
|
7 -> {
|
||||||
FreakUtils.teleport(player)
|
FreakUtils.teleport(player)
|
||||||
FreakUtils.giveFreakTask(player)
|
FreakUtils.giveFreakTask(player)
|
||||||
RandomEventManager.getInstance(player)!!.event?.terminate()
|
AntiMacro.terminateEventNpc(player)
|
||||||
openDialogue(player, FreakyForesterDialogue(), FreakUtils.freakNpc)
|
openDialogue(player, FreakyForesterDialogue(), FreakUtils.freakNpc)
|
||||||
resetAnimator(player)
|
resetAnimator(player)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package content.global.ame.events.genie
|
|||||||
import core.api.*
|
import core.api.*
|
||||||
import core.game.dialogue.FacialExpression
|
import core.game.dialogue.FacialExpression
|
||||||
import core.game.dialogue.DialogueFile
|
import core.game.dialogue.DialogueFile
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import core.tools.END_DIALOGUE
|
import core.tools.END_DIALOGUE
|
||||||
|
|
||||||
class GenieDialogue : DialogueFile() {
|
class GenieDialogue : DialogueFile() {
|
||||||
@@ -10,7 +11,7 @@ class GenieDialogue : DialogueFile() {
|
|||||||
val assigned = player!!.getAttribute("genie:item",0)
|
val assigned = player!!.getAttribute("genie:item",0)
|
||||||
npcl(core.game.dialogue.FacialExpression.NEUTRAL, "Ah, so you are there, ${player!!.name.capitalize()}. I'm so glad you summoned me. Please take this lamp and make your wish.")
|
npcl(core.game.dialogue.FacialExpression.NEUTRAL, "Ah, so you are there, ${player!!.name.capitalize()}. I'm so glad you summoned me. Please take this lamp and make your wish.")
|
||||||
addItemOrDrop(player!!, assigned)
|
addItemOrDrop(player!!, assigned)
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)!!.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
stage = END_DIALOGUE
|
stage = END_DIALOGUE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import core.game.node.entity.combat.ImpactHandler
|
|||||||
import core.game.node.item.GroundItemManager
|
import core.game.node.item.GroundItemManager
|
||||||
import core.game.node.item.Item
|
import core.game.node.item.Item
|
||||||
import core.game.dialogue.DialogueFile
|
import core.game.dialogue.DialogueFile
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import core.tools.END_DIALOGUE
|
import core.tools.END_DIALOGUE
|
||||||
|
|
||||||
class SandwichLadyDialogue(val isChoice: Boolean) : DialogueFile() {
|
class SandwichLadyDialogue(val isChoice: Boolean) : DialogueFile() {
|
||||||
@@ -26,13 +27,13 @@ class SandwichLadyDialogue(val isChoice: Boolean) : DialogueFile() {
|
|||||||
0 -> if(choice != assigned){
|
0 -> if(choice != assigned){
|
||||||
npc!!.sendChat("That's not what I said you could have!")
|
npc!!.sendChat("That's not what I said you could have!")
|
||||||
player!!.impactHandler.manualHit(npc,3,ImpactHandler.HitsplatType.NORMAL)
|
player!!.impactHandler.manualHit(npc,3,ImpactHandler.HitsplatType.NORMAL)
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)!!.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
} else {
|
} else {
|
||||||
npc("Here you are, dear. I hope you enjoy it!")
|
npc("Here you are, dear. I hope you enjoy it!")
|
||||||
if(!player!!.inventory.add(Item(assigned))){
|
if(!player!!.inventory.add(Item(assigned))){
|
||||||
GroundItemManager.create(Item(assigned),player)
|
GroundItemManager.create(Item(assigned),player)
|
||||||
}
|
}
|
||||||
content.global.ame.RandomEventManager.getInstance(player!!)!!.event?.terminate()
|
AntiMacro.terminateEventNpc(player!!)
|
||||||
stage = END_DIALOGUE
|
stage = END_DIALOGUE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package content.global.ame.events.sandwichlady
|
|||||||
import core.game.node.item.Item
|
import core.game.node.item.Item
|
||||||
import org.rs09.consts.Items
|
import org.rs09.consts.Items
|
||||||
import core.game.interaction.InterfaceListener
|
import core.game.interaction.InterfaceListener
|
||||||
import content.global.ame.RandomEventManager
|
import core.game.system.timer.impl.AntiMacro
|
||||||
|
|
||||||
class SandwichLadyInterface : InterfaceListener {
|
class SandwichLadyInterface : InterfaceListener {
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ class SandwichLadyInterface : InterfaceListener {
|
|||||||
|
|
||||||
override fun defineInterfaceListeners() {
|
override fun defineInterfaceListeners() {
|
||||||
on(SANDWICH_INTERFACE){player, _, _, buttonID, _, _ ->
|
on(SANDWICH_INTERFACE){player, _, _, buttonID, _, _ ->
|
||||||
val event = RandomEventManager.getInstance(player)!!.event
|
val event = AntiMacro.getEventNpc(player)
|
||||||
if (event == null) {
|
if (event == null) {
|
||||||
player.interfaceManager.close()
|
player.interfaceManager.close()
|
||||||
return@on true
|
return@on true
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import content.global.ame.RandomEvents
|
|||||||
import content.minigame.gnomecooking.*
|
import content.minigame.gnomecooking.*
|
||||||
import core.game.interaction.InteractionListener
|
import core.game.interaction.InteractionListener
|
||||||
import core.game.interaction.IntType
|
import core.game.interaction.IntType
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the NPC talk-to option.
|
* Handles the NPC talk-to option.
|
||||||
@@ -31,10 +32,10 @@ class NPCTalkListener : InteractionListener {
|
|||||||
on(IntType.NPC,"talk-to","talk","talk to"){ player, node ->
|
on(IntType.NPC,"talk-to","talk","talk to"){ player, node ->
|
||||||
val npc = node.asNpc()
|
val npc = node.asNpc()
|
||||||
if(RandomEvents.randomIDs.contains(node.id)){
|
if(RandomEvents.randomIDs.contains(node.id)){
|
||||||
if(content.global.ame.RandomEventManager.getInstance(player)!!.event == null || content.global.ame.RandomEventManager.getInstance(player)!!.event!! != node.asNpc()){
|
if(AntiMacro.getEventNpc(player) == null || AntiMacro.getEventNpc(player) != node.asNpc()){
|
||||||
player.sendMessage("They aren't interested in talking to you.")
|
player.sendMessage("They aren't interested in talking to you.")
|
||||||
} else {
|
} else {
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.event!!.talkTo(node.asNpc())
|
AntiMacro.getEventNpc(player)?.talkTo(node.asNpc())
|
||||||
}
|
}
|
||||||
return@on true
|
return@on true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.rs09.consts.Components
|
|||||||
import core.ServerConstants
|
import core.ServerConstants
|
||||||
import core.api.Event
|
import core.api.Event
|
||||||
import core.api.utils.PlayerCamera
|
import core.api.utils.PlayerCamera
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import core.tools.SystemLogger
|
import core.tools.SystemLogger
|
||||||
import core.game.world.GameWorld
|
import core.game.world.GameWorld
|
||||||
import core.tools.Log
|
import core.tools.Log
|
||||||
@@ -238,7 +239,7 @@ abstract class Cutscene(val player: Player) {
|
|||||||
player.lock()
|
player.lock()
|
||||||
player.hook(Event.SelfDeath, CUTSCENE_DEATH_HOOK)
|
player.hook(Event.SelfDeath, CUTSCENE_DEATH_HOOK)
|
||||||
player.logoutListeners["cutscene"] = {player -> player.location = exitLocation; player.getCutscene()?.end() }
|
player.logoutListeners["cutscene"] = {player -> player.location = exitLocation; player.getCutscene()?.end() }
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.enabled = false
|
AntiMacro.pause(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -275,7 +276,7 @@ abstract class Cutscene(val player: Player) {
|
|||||||
clearNPCs()
|
clearNPCs()
|
||||||
player.unhook(CUTSCENE_DEATH_HOOK)
|
player.unhook(CUTSCENE_DEATH_HOOK)
|
||||||
player.logoutListeners.remove("cutscene")
|
player.logoutListeners.remove("cutscene")
|
||||||
content.global.ame.RandomEventManager.getInstance(player)?.enabled = true
|
AntiMacro.unpause(player)
|
||||||
PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 0))
|
PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 0))
|
||||||
try {
|
try {
|
||||||
endActions?.invoke()
|
endActions?.invoke()
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public abstract class Entity extends Node {
|
|||||||
* The reward locks.
|
* The reward locks.
|
||||||
*/
|
*/
|
||||||
private final ActionLocks locks = new ActionLocks();
|
private final ActionLocks locks = new ActionLocks();
|
||||||
public final ScriptProcessor scripts = new ScriptProcessor(this);
|
public ScriptProcessor scripts = new ScriptProcessor(this);
|
||||||
public final int[] clocks = new int[10];
|
public final int[] clocks = new int[10];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ public class Player extends Entity {
|
|||||||
/**
|
/**
|
||||||
* The quest repository.
|
* The quest repository.
|
||||||
*/
|
*/
|
||||||
private QuestRepository questRepository = new QuestRepository(this);
|
public QuestRepository questRepository = new QuestRepository(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The prayer manager.
|
* The prayer manager.
|
||||||
@@ -239,7 +239,7 @@ public class Player extends Entity {
|
|||||||
/**
|
/**
|
||||||
* The saved data.
|
* The saved data.
|
||||||
*/
|
*/
|
||||||
private SavedData savedData = new SavedData(this);
|
public SavedData savedData = new SavedData(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The request manager.
|
* The request manager.
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class PlayerSaveParser(val player: Player) {
|
|||||||
var saveFile: JSONObject? = null
|
var saveFile: JSONObject? = null
|
||||||
var read = true
|
var read = true
|
||||||
|
|
||||||
init {
|
fun parse() {
|
||||||
val JSON = File(ServerConstants.PLAYER_SAVE_PATH + player.name + ".json")
|
val JSON = File(ServerConstants.PLAYER_SAVE_PATH + player.name + ".json")
|
||||||
if(JSON.exists())
|
if(JSON.exists())
|
||||||
{
|
{
|
||||||
@@ -49,36 +49,38 @@ class PlayerSaveParser(val player: Player) {
|
|||||||
if (read) {
|
if (read) {
|
||||||
saveFile = parser.parse(reader) as JSONObject
|
saveFile = parser.parse(reader) as JSONObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (read) {
|
||||||
|
parseData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parse() {
|
fun parseData() {
|
||||||
if (read) {
|
parseCore()
|
||||||
parseCore()
|
parseAttributes()
|
||||||
parseAttributes()
|
parseSkills()
|
||||||
parseSkills()
|
parseSettings()
|
||||||
parseSettings()
|
parseQuests()
|
||||||
parseQuests()
|
parseAppearance()
|
||||||
parseAppearance()
|
parseGrave()
|
||||||
parseGrave()
|
parseVarps()
|
||||||
parseVarps()
|
parseStates()
|
||||||
parseStates()
|
parseSpellbook()
|
||||||
parseSpellbook()
|
parseSavedData()
|
||||||
parseSavedData()
|
parseAutocastSpell()
|
||||||
parseAutocastSpell()
|
parseFarming()
|
||||||
parseFarming()
|
parseConfigs()
|
||||||
parseConfigs()
|
parseMonitor()
|
||||||
parseMonitor()
|
parseMusic()
|
||||||
parseMusic()
|
parseFamiliars()
|
||||||
parseFamiliars()
|
parseBankPin()
|
||||||
parseBankPin()
|
parseHouse()
|
||||||
parseHouse()
|
parseIronman()
|
||||||
parseIronman()
|
parseEmoteManager()
|
||||||
parseEmoteManager()
|
parseStatistics()
|
||||||
parseStatistics()
|
parseAchievements()
|
||||||
parseAchievements()
|
parsePouches()
|
||||||
parsePouches()
|
parsePouches()
|
||||||
parsePouches()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runContentHooks()
|
fun runContentHooks()
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class PlayerSaver (val player: Player){
|
|||||||
companion object {
|
companion object {
|
||||||
val contentHooks = ArrayList<PersistPlayer>()
|
val contentHooks = ArrayList<PersistPlayer>()
|
||||||
}
|
}
|
||||||
private fun populate(): JSONObject {
|
fun populate(): JSONObject {
|
||||||
val saveFile = JSONObject()
|
val saveFile = JSONObject()
|
||||||
saveCoreData(saveFile)
|
saveCoreData(saveFile)
|
||||||
saveSkills(saveFile)
|
saveSkills(saveFile)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.rs09.consts.Items;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static core.api.ContentAPIKt.getWorldTicks;
|
||||||
import static java.lang.Math.floor;
|
import static java.lang.Math.floor;
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
@@ -119,7 +120,8 @@ public final class Skills {
|
|||||||
*/
|
*/
|
||||||
private int skillMilestone;
|
private int skillMilestone;
|
||||||
|
|
||||||
public int lastTrainedSkill = -1;
|
public int lastTrainedSkill = -1;
|
||||||
|
public int lastXpGain = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code Skills} {@code Object}.
|
* Constructs a new {@code Skills} {@code Object}.
|
||||||
@@ -271,7 +273,8 @@ public final class Skills {
|
|||||||
lastUpdateXp = this.experience.clone();
|
lastUpdateXp = this.experience.clone();
|
||||||
lastUpdate = GameWorld.getTicks();
|
lastUpdate = GameWorld.getTicks();
|
||||||
}
|
}
|
||||||
lastTrainedSkill = slot;
|
lastTrainedSkill = slot;
|
||||||
|
lastXpGain = getWorldTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -546,26 +546,6 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
|||||||
define("finishbins", Privilege.ADMIN, "", "Finishes any in-progress compost bins."){ player, _ ->
|
define("finishbins", Privilege.ADMIN, "", "Finishes any in-progress compost bins."){ player, _ ->
|
||||||
}
|
}
|
||||||
|
|
||||||
define("testlady", Privilege.ADMIN){ player, _ ->
|
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.event = RandomEvents.RIVER_TROLL.npc.create(player)
|
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.event!!.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
define("freak", Privilege.ADMIN){ player, _ ->
|
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.event = RandomEvents.FREAKY_FORESTER.npc.create(player)
|
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.event!!.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
define("bob", Privilege.ADMIN){ player, _ ->
|
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.event = RandomEvents.EVIL_BOB.npc.create(player)
|
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.event!!.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
define("revent", Privilege.ADMIN){ player, _ ->
|
|
||||||
println(player.pulseManager.current)
|
|
||||||
content.global.ame.RandomEventManager.getInstance(player)!!.fireEvent()
|
|
||||||
}
|
|
||||||
|
|
||||||
define("addcredits", Privilege.ADMIN){ player, _ ->
|
define("addcredits", Privilege.ADMIN){ player, _ ->
|
||||||
player.details.credits += 100
|
player.details.credits += 100
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,12 @@ class TimerManager (val entity: Entity) {
|
|||||||
timer.save(obj, entity)
|
timer.save(obj, entity)
|
||||||
root [timer.identifier] = obj
|
root [timer.identifier] = obj
|
||||||
}
|
}
|
||||||
|
for (timer in newTimers) {
|
||||||
|
if (timer !is PersistTimer) continue
|
||||||
|
val obj = JSONObject()
|
||||||
|
timer.save(obj, entity)
|
||||||
|
root [timer.identifier] = obj
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseTimers (root: JSONObject) {
|
fun parseTimers (root: JSONObject) {
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ object TimerRegistry {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun addAutoTimers (entity: Entity) {
|
fun addAutoTimers (entity: Entity) {
|
||||||
(entity as? Player)?.debug ("Adding auto timers...")
|
|
||||||
for (timer in autoTimers) {
|
for (timer in autoTimers) {
|
||||||
if (!hasTimerActive (entity, timer.identifier))
|
if (!hasTimerActive (entity, timer.identifier))
|
||||||
registerTimer (entity, timer.retrieveInstance())
|
registerTimer (entity, timer.retrieveInstance())
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package core.game.system.timer.impl
|
||||||
|
|
||||||
|
import content.global.ame.RandomEventNPC
|
||||||
|
import content.global.ame.RandomEvents
|
||||||
|
import core.api.*
|
||||||
|
import core.game.node.entity.Entity
|
||||||
|
import core.game.node.entity.player.Player
|
||||||
|
import core.game.node.item.Item
|
||||||
|
import core.game.system.command.Privilege
|
||||||
|
import core.game.system.timer.PersistTimer
|
||||||
|
import core.game.world.map.zone.ZoneRestriction
|
||||||
|
import core.game.world.repository.Repository
|
||||||
|
import core.tools.RandomFunction
|
||||||
|
import org.json.simple.JSONObject
|
||||||
|
|
||||||
|
class AntiMacro : PersistTimer(0, "antimacro", isAuto = true), Commands {
|
||||||
|
var paused = false
|
||||||
|
var nextRandom: RandomEvents? = null
|
||||||
|
|
||||||
|
override fun run(entity: Entity): Boolean {
|
||||||
|
if (entity !is Player) return false
|
||||||
|
|
||||||
|
setNextExecution()
|
||||||
|
|
||||||
|
if (!canSpawn(entity)) return true
|
||||||
|
val eventSelection = rollEventPool(entity)
|
||||||
|
val eventNpc = eventSelection.npc.create(entity, eventSelection.loot, eventSelection.type)
|
||||||
|
if (eventNpc.spawnLocation == null) {
|
||||||
|
entity.debug("[AntiMacro] Attempted to spawn random, but spawnLoc was null.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
eventNpc.init()
|
||||||
|
setAttribute(entity, EVENT_NPC, eventNpc)
|
||||||
|
entity.debug("[AntiMacro] Fired ${eventSelection.name}.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRegister(entity: Entity) {
|
||||||
|
if (entity !is Player)
|
||||||
|
entity.timers.removeTimer(this)
|
||||||
|
|
||||||
|
if (runInterval == 0)
|
||||||
|
setNextExecution()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun save(root: JSONObject, entity: Entity) {
|
||||||
|
root["ticksRemaining"] = (nextExecution - getWorldTicks()).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun parse(root: JSONObject, entity: Entity) {
|
||||||
|
runInterval = (root["ticksRemaining"]?.toString()?.toIntOrNull() ?: 0)
|
||||||
|
nextExecution = getWorldTicks() + runInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canSpawn(entity: Entity) : Boolean {
|
||||||
|
if (entity.zoneMonitor.isRestricted(ZoneRestriction.RANDOM_EVENTS))
|
||||||
|
return false
|
||||||
|
|
||||||
|
val current = getAttribute<RandomEventNPC?>(entity, EVENT_NPC, null)
|
||||||
|
if (current != null)
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (paused)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setNextExecution() {
|
||||||
|
runInterval = RandomFunction.random(MIN_DELAY_TICKS, MAX_DELAY_TICKS + 1)
|
||||||
|
nextExecution = getWorldTicks() + runInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rollEventPool(entity: Entity) : RandomEvents {
|
||||||
|
if (nextRandom != null) {
|
||||||
|
val result = nextRandom!!
|
||||||
|
nextRandom = null
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
val skillBasedRandom = RandomEvents.getSkillBasedRandomEvent(entity.skills.lastTrainedSkill)
|
||||||
|
val normalRandom = RandomEvents.getNonSkillRandom()
|
||||||
|
val roll = RandomFunction.random(100)
|
||||||
|
|
||||||
|
if (roll >= 65 && skillBasedRandom != null && getWorldTicks() - entity.skills.lastXpGain < 250)
|
||||||
|
return skillBasedRandom
|
||||||
|
return normalRandom
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun defineCommands() {
|
||||||
|
define("revent", Privilege.ADMIN, "::revent [-p] <lt>player name<gt> [-e <lt>event name<gt>]", "Spawns a random event for the target player.<br>Optional -e parameter to pass a specific event.") {player, args ->
|
||||||
|
if (args.size == 1) {
|
||||||
|
val possible = RandomEvents.values()
|
||||||
|
for (event in possible) {
|
||||||
|
notify(player, event.name.lowercase())
|
||||||
|
}
|
||||||
|
return@define
|
||||||
|
}
|
||||||
|
|
||||||
|
val arg = parseCommandArgs(args.joinToString(" "))
|
||||||
|
val target = Repository.getPlayerByName(arg.targetPlayer)
|
||||||
|
if (target == null)
|
||||||
|
reject(player, "Unable to find user ${arg.targetPlayer}.")
|
||||||
|
|
||||||
|
forceEvent(target!!, arg.targetEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class CommandArgs (val targetPlayer: String, val targetEvent: RandomEvents?)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val EVENT_NPC = "re-npc"
|
||||||
|
const val MIN_DELAY_TICKS = 3000
|
||||||
|
const val MAX_DELAY_TICKS = 9000
|
||||||
|
|
||||||
|
fun terminateEventNpc (player: Player) {
|
||||||
|
getEventNpc(player)?.terminate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rollEventLoot (player: Player) : ArrayList<Item> {
|
||||||
|
return getEventNpc(player)?.loot?.roll(player) ?: ArrayList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEventNpc (player: Player) : RandomEventNPC? {
|
||||||
|
return getAttribute<RandomEventNPC?>(player, EVENT_NPC, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pause (player: Player) {
|
||||||
|
val timer = getTimer<AntiMacro>(player) ?: return
|
||||||
|
timer.paused = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unpause (player: Player) {
|
||||||
|
val timer = getTimer<AntiMacro>(player) ?: return
|
||||||
|
timer.paused = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun forceEvent (player: Player, event: RandomEvents? = null) {
|
||||||
|
val timer = getTimer<AntiMacro>(player) ?: return
|
||||||
|
timer.nextExecution = getWorldTicks()
|
||||||
|
timer.nextRandom = event
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseCommandArgs (args: String, commandName: String = "revent") : CommandArgs {
|
||||||
|
val tokens = args.split(" ")
|
||||||
|
val modeTokens = arrayOf("-p", "-e")
|
||||||
|
|
||||||
|
var userString = ""
|
||||||
|
var eventString = ""
|
||||||
|
var lastMode = "-p"
|
||||||
|
|
||||||
|
for (token in tokens) {
|
||||||
|
when (token) {
|
||||||
|
commandName -> continue
|
||||||
|
in modeTokens -> lastMode = token
|
||||||
|
else -> when (lastMode) {
|
||||||
|
"-p" -> userString += "$token "
|
||||||
|
"-e" -> eventString += "$token "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val username = userString.trim().lowercase().replace(" ", "_")
|
||||||
|
val eventName = eventString.trim().uppercase().replace(" ", "_")
|
||||||
|
|
||||||
|
var event: RandomEvents? = null
|
||||||
|
|
||||||
|
try { event = RandomEvents.valueOf(eventName) } catch (_: Exception) {}
|
||||||
|
|
||||||
|
return CommandArgs(username, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
import content.global.ame.RandomEventManager
|
|
||||||
import content.global.skill.farming.timers.CropGrowth
|
import content.global.skill.farming.timers.CropGrowth
|
||||||
|
import core.ServerConstants
|
||||||
|
import core.api.log
|
||||||
import core.cache.Cache
|
import core.cache.Cache
|
||||||
import core.cache.crypto.ISAACCipher
|
import core.cache.crypto.ISAACCipher
|
||||||
import core.cache.crypto.ISAACPair
|
import core.cache.crypto.ISAACPair
|
||||||
import core.game.node.entity.player.Player
|
import core.game.interaction.ScriptProcessor
|
||||||
import core.game.node.entity.player.info.PlayerDetails
|
|
||||||
import core.game.node.entity.player.info.Rights
|
|
||||||
import core.game.node.entity.player.link.IronmanMode
|
|
||||||
import core.game.node.item.Item
|
|
||||||
import core.net.IoSession
|
|
||||||
import core.net.packet.IoBuffer
|
|
||||||
import org.rs09.consts.Items
|
|
||||||
import core.ServerConstants
|
|
||||||
import core.api.log
|
|
||||||
import core.game.node.Node
|
import core.game.node.Node
|
||||||
import core.game.node.entity.combat.equipment.WeaponInterface
|
import core.game.node.entity.combat.equipment.WeaponInterface
|
||||||
import core.game.node.entity.npc.NPC
|
import core.game.node.entity.npc.NPC
|
||||||
import core.game.node.entity.skill.SkillBonus
|
import core.game.node.entity.player.Player
|
||||||
|
import core.game.node.entity.player.VarpManager
|
||||||
|
import core.game.node.entity.player.info.PlayerDetails
|
||||||
|
import core.game.node.entity.player.info.Rights
|
||||||
|
import core.game.node.entity.player.info.login.PlayerSaveParser
|
||||||
|
import core.game.node.entity.player.info.login.PlayerSaver
|
||||||
|
import core.game.node.entity.player.link.IronmanMode
|
||||||
|
import core.game.node.entity.player.link.SavedData
|
||||||
|
import core.game.node.entity.player.link.quest.QuestRepository
|
||||||
|
import core.game.node.entity.skill.Skills
|
||||||
import core.game.node.item.GroundItem
|
import core.game.node.item.GroundItem
|
||||||
|
import core.game.node.item.Item
|
||||||
import core.game.shops.Shop
|
import core.game.shops.Shop
|
||||||
import core.game.shops.ShopItem
|
import core.game.shops.ShopItem
|
||||||
import core.tools.SystemLogger
|
|
||||||
import core.game.system.config.ConfigParser
|
import core.game.system.config.ConfigParser
|
||||||
import core.game.system.config.ServerConfigParser
|
import core.game.system.config.ServerConfigParser
|
||||||
import core.game.system.timer.TimerRegistry
|
import core.game.system.timer.TimerRegistry
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
import core.game.system.timer.impl.Disease
|
import core.game.system.timer.impl.Disease
|
||||||
import core.game.system.timer.impl.Poison
|
import core.game.system.timer.impl.Poison
|
||||||
import core.game.world.GameWorld
|
import core.game.world.GameWorld
|
||||||
@@ -31,10 +33,11 @@ import core.game.world.map.Location
|
|||||||
import core.game.world.map.RegionManager
|
import core.game.world.map.RegionManager
|
||||||
import core.game.world.repository.Repository
|
import core.game.world.repository.Repository
|
||||||
import core.game.world.update.UpdateSequence
|
import core.game.world.update.UpdateSequence
|
||||||
|
import core.net.IoSession
|
||||||
|
import core.net.packet.IoBuffer
|
||||||
import core.net.packet.PacketProcessor
|
import core.net.packet.PacketProcessor
|
||||||
import core.tools.Log
|
import core.tools.Log
|
||||||
import org.rs09.consts.Scenery
|
import org.rs09.consts.Items
|
||||||
import java.io.Closeable
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
@@ -85,6 +88,7 @@ object TestUtils {
|
|||||||
TimerRegistry.registerTimer(Poison())
|
TimerRegistry.registerTimer(Poison())
|
||||||
TimerRegistry.registerTimer(Disease())
|
TimerRegistry.registerTimer(Disease())
|
||||||
TimerRegistry.registerTimer(CropGrowth())
|
TimerRegistry.registerTimer(CropGrowth())
|
||||||
|
TimerRegistry.registerTimer(AntiMacro())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadFile(path: String) : URI? {
|
fun loadFile(path: String) : URI? {
|
||||||
@@ -111,12 +115,17 @@ object TestUtils {
|
|||||||
|
|
||||||
class MockPlayer(name: String) : Player(PlayerDetails(name)), AutoCloseable {
|
class MockPlayer(name: String) : Player(PlayerDetails(name)), AutoCloseable {
|
||||||
var hasInit = false
|
var hasInit = false
|
||||||
init {
|
init { configureBasicProperties(); flagTutComplete(false); init(); flagTutComplete(true) }
|
||||||
|
|
||||||
|
fun configureBasicProperties() {
|
||||||
this.details.session = MockSession()
|
this.details.session = MockSession()
|
||||||
this.location = ServerConstants.HOME_LOCATION
|
this.location = ServerConstants.HOME_LOCATION
|
||||||
this.properties.attackStyle = WeaponInterface.AttackStyle(0, WeaponInterface.BONUS_CRUSH)
|
this.properties.attackStyle = WeaponInterface.AttackStyle(0, WeaponInterface.BONUS_CRUSH)
|
||||||
init()
|
}
|
||||||
this.setAttribute("tutorial:complete", true)
|
|
||||||
|
fun flagTutComplete(complete: Boolean) {
|
||||||
|
this.setAttribute("/save:tutorial:complete", complete)
|
||||||
|
this.setAttribute("/save:rules:confirmed", complete)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update() {
|
override fun update() {
|
||||||
@@ -140,6 +149,37 @@ class MockPlayer(name: String) : Player(PlayerDetails(name)), AutoCloseable {
|
|||||||
RegionManager.move(this)
|
RegionManager.move(this)
|
||||||
this.playerFlags.lastSceneGraph = location
|
this.playerFlags.lastSceneGraph = location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun relog(ticksToWait: Int = -1) {
|
||||||
|
val json = PlayerSaver(this).populate()
|
||||||
|
val parse = PlayerSaveParser(this)
|
||||||
|
parse.saveFile = json
|
||||||
|
|
||||||
|
close()
|
||||||
|
timers.clearTimers()
|
||||||
|
inventory.clear()
|
||||||
|
bank.clear()
|
||||||
|
equipment.clear()
|
||||||
|
skills = Skills(this)
|
||||||
|
savedData = SavedData(this)
|
||||||
|
questRepository = QuestRepository(this)
|
||||||
|
varpManager = VarpManager(this)
|
||||||
|
varpMap.clear()
|
||||||
|
saveVarp.clear()
|
||||||
|
scripts = ScriptProcessor(this)
|
||||||
|
clearAttributes()
|
||||||
|
hasInit = false
|
||||||
|
|
||||||
|
if (ticksToWait > 0) TestUtils.advanceTicks(ticksToWait, false)
|
||||||
|
|
||||||
|
configureBasicProperties()
|
||||||
|
parse.parseData()
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun debug(string: String?) {
|
||||||
|
log (this::class.java, Log.DEBUG, "[$name] -> Received Debug: $string")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockSession : IoSession(null, null) {
|
class MockSession : IoSession(null, null) {
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
package content
|
|
||||||
|
|
||||||
import TestUtils
|
|
||||||
import content.global.ame.RandomEventManager
|
|
||||||
import core.game.node.item.Item
|
|
||||||
import org.junit.jupiter.api.Assertions
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.rs09.consts.Items
|
|
||||||
import content.global.ame.RandomEventNPC
|
|
||||||
import core.game.world.GameWorld
|
|
||||||
|
|
||||||
class RandomEventManagerTests {
|
|
||||||
init {
|
|
||||||
TestUtils.preTestSetup()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun loginShouldEnableManager() {
|
|
||||||
val p = TestUtils.getMockPlayer("Bill")
|
|
||||||
RandomEventManager().login(p)
|
|
||||||
val manager = content.global.ame.RandomEventManager.getInstance(p)
|
|
||||||
Assertions.assertNotNull(manager)
|
|
||||||
Assertions.assertEquals(true, manager!!.enabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun loginShouldSetNextSpawn() {
|
|
||||||
val p = TestUtils.getMockPlayer("Bill")
|
|
||||||
RandomEventManager().login(p)
|
|
||||||
val manager = content.global.ame.RandomEventManager.getInstance(p)
|
|
||||||
Assertions.assertNotNull(manager)
|
|
||||||
Assertions.assertEquals(true, manager!!.nextSpawn > GameWorld.ticks)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun shouldSpawnRandomEventWithinMAXTICKSGivenNoRestrictions() {
|
|
||||||
val p = TestUtils.getMockPlayer("Bill")
|
|
||||||
p.setAttribute("tutorial:complete", true) //tutorial has to be complete to spawn randoms
|
|
||||||
RandomEventManager.MIN_DELAY_TICKS = 10
|
|
||||||
RandomEventManager.MAX_DELAY_TICKS = 20
|
|
||||||
RandomEventManager().login(p)
|
|
||||||
TestUtils.advanceTicks(RandomEventManager.MAX_DELAY_TICKS + 5)
|
|
||||||
RandomEventManager.MIN_DELAY_TICKS = 3000
|
|
||||||
RandomEventManager.MAX_DELAY_TICKS = 9000
|
|
||||||
Assertions.assertNotNull(p.getAttribute("re-npc", null))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun teleportAndNotePunishmentShouldNotAffectAlreadyNotedItems() {
|
|
||||||
val p = TestUtils.getMockPlayer("Shitforbrains")
|
|
||||||
p.setAttribute("tutorial:complete", true)
|
|
||||||
RandomEventManager().login(p)
|
|
||||||
|
|
||||||
p.inventory.add(Item(Items.RAW_SHARK_384, 1000))
|
|
||||||
content.global.ame.RandomEventManager.getInstance(p)?.fireEvent()
|
|
||||||
p.getAttribute<RandomEventNPC>("re-npc")!!.noteAndTeleport()
|
|
||||||
|
|
||||||
Assertions.assertEquals(1000, p.inventory.getAmount(Items.RAW_SHARK_384))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun teleportAndNotePunishmentShouldNoteNotableUnnotedItems() {
|
|
||||||
val p = TestUtils.getMockPlayer("shitforbrains2")
|
|
||||||
p.setAttribute("tutorial:complete", true)
|
|
||||||
RandomEventManager().login(p)
|
|
||||||
|
|
||||||
p.inventory.add(Item(4151, 5))
|
|
||||||
content.global.ame.RandomEventManager.getInstance(p)?.fireEvent()
|
|
||||||
p.getAttribute<RandomEventNPC>("re-npc")!!.noteAndTeleport()
|
|
||||||
|
|
||||||
Assertions.assertEquals(5, p.inventory.getAmount(4152))
|
|
||||||
Assertions.assertEquals(0, p.inventory.getAmount(4151))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun teleportAndNotePunishmentShouldNotAffectUnnotableItems() {
|
|
||||||
val p = TestUtils.getMockPlayer("shitforbrains3")
|
|
||||||
p.setAttribute("tutorial:complete", true)
|
|
||||||
RandomEventManager().login(p)
|
|
||||||
|
|
||||||
p.inventory.add(Item(Items.AIR_RUNE_556, 30))
|
|
||||||
content.global.ame.RandomEventManager.getInstance(p)?.fireEvent()
|
|
||||||
p.getAttribute<RandomEventNPC>("re-npc")!!.noteAndTeleport()
|
|
||||||
|
|
||||||
Assertions.assertEquals(30, p.inventory.getAmount(Items.AIR_RUNE_556))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package content
|
||||||
|
|
||||||
|
import TestUtils
|
||||||
|
import content.global.ame.RandomEventNPC
|
||||||
|
import content.global.ame.RandomEvents
|
||||||
|
import core.api.*
|
||||||
|
import core.game.system.timer.impl.AntiMacro
|
||||||
|
import core.game.world.map.Location
|
||||||
|
import core.game.world.map.zone.impl.WildernessZone
|
||||||
|
import org.junit.jupiter.api.Assertions
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.rs09.consts.Items
|
||||||
|
import org.rs09.consts.NPCs
|
||||||
|
|
||||||
|
class RandomEventTests {
|
||||||
|
init {
|
||||||
|
TestUtils.preTestSetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun loginShouldRegisterRandomEventTimer() {
|
||||||
|
TestUtils.getMockPlayer("antimacroAutoRegister").use { p ->
|
||||||
|
Assertions.assertNotNull(getTimer<AntiMacro>(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun loginShouldSetNextSpawn() {
|
||||||
|
TestUtils.getMockPlayer("antimacroautosetsnextspawnifunset").use { p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null.")
|
||||||
|
Assertions.assertNotEquals(getWorldTicks(), timer.nextExecution)
|
||||||
|
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() >= AntiMacro.MIN_DELAY_TICKS)
|
||||||
|
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() <= AntiMacro.MAX_DELAY_TICKS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun remainingDelayShouldPersistRelog() {
|
||||||
|
TestUtils.getMockPlayer("antimacrotimeremainingpersists").use { p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null.")
|
||||||
|
timer.nextExecution = getWorldTicks() + 666
|
||||||
|
p.relog(ticksToWait = 100)
|
||||||
|
Assertions.assertEquals(getWorldTicks() + 666, getTimer<AntiMacro>(p)!!.nextExecution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun delayShouldBeRestartedOnceDepleted() {
|
||||||
|
TestUtils.getMockPlayer("delayrestartoncedepleted").use { p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null.")
|
||||||
|
TestUtils.advanceTicks(2, false)
|
||||||
|
timer.nextExecution = 5 //run in 5 ticks
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() >= AntiMacro.MIN_DELAY_TICKS)
|
||||||
|
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() <= AntiMacro.MAX_DELAY_TICKS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun shouldSpawnRandomEventGivenNoRestrictions() {
|
||||||
|
TestUtils.getMockPlayer("antimacroshouldspawnrandom").use {p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNotNull(p.getAttribute(AntiMacro.EVENT_NPC, null))
|
||||||
|
Assertions.assertEquals(true, p.getAttribute<RandomEventNPC>(AntiMacro.EVENT_NPC).isActive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun teleportAndNotePunishmentShouldNotAffectAlreadyNotedItems() {
|
||||||
|
TestUtils.getMockPlayer("teleportpunishment1").use {p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
|
||||||
|
addItem(p, Items.RAW_SHARK_384, 1000)
|
||||||
|
getAttribute<RandomEventNPC?>(p, AntiMacro.EVENT_NPC, null)!!.noteAndTeleport()
|
||||||
|
|
||||||
|
Assertions.assertEquals(1000, amountInInventory(p, Items.RAW_SHARK_384))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun teleportAndNotePunishmentShouldNoteNotableUnnotedItems() {
|
||||||
|
TestUtils.getMockPlayer("teleportpunishment2").use {p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
|
||||||
|
addItem(p, Items.ABYSSAL_WHIP_4151, 5)
|
||||||
|
getAttribute<RandomEventNPC?>(p, AntiMacro.EVENT_NPC, null)!!.noteAndTeleport()
|
||||||
|
|
||||||
|
Assertions.assertEquals(5, amountInInventory(p, Items.ABYSSAL_WHIP_4152))
|
||||||
|
Assertions.assertEquals(0, amountInInventory(p, Items.ABYSSAL_WHIP_4151))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun teleportAndNotePunishmentShouldNotAffectUnnotableItems() {
|
||||||
|
TestUtils.getMockPlayer("teleportpunishment3").use {p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
|
||||||
|
addItem(p, Items.AIR_RUNE_556, 30)
|
||||||
|
getAttribute<RandomEventNPC?>(p, AntiMacro.EVENT_NPC, null)!!.noteAndTeleport()
|
||||||
|
|
||||||
|
Assertions.assertEquals(30, amountInInventory(p, Items.AIR_RUNE_556))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun randomEventShouldNotSpawnInEventRestrictedArea() {
|
||||||
|
|
||||||
|
TestUtils.getMockPlayer("antimacronospawninrestrictedzone").use { p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
|
||||||
|
//Wilderness is Random Event restricted
|
||||||
|
WildernessZone.getInstance().configure()
|
||||||
|
val loc = Location.create(3131, 3595)
|
||||||
|
p.location = loc
|
||||||
|
|
||||||
|
Assertions.assertEquals(loc, p.location)
|
||||||
|
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNull(AntiMacro.getEventNpc(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun randomEventShouldNotSpawnIfOneAlreadyActive() {
|
||||||
|
TestUtils.getMockPlayer("antimacronospawnifalreadyhas").use { p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||||
|
|
||||||
|
val previousEvent = AntiMacro.getEventNpc(p)
|
||||||
|
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||||
|
Assertions.assertEquals(previousEvent, AntiMacro.getEventNpc(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun randomEventShouldSpawnIfCurrentOneIsInactive() {
|
||||||
|
TestUtils.getMockPlayer("antimacrospawnifcurrentinactive").use { p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||||
|
|
||||||
|
val previousEvent = AntiMacro.getEventNpc(p)
|
||||||
|
AntiMacro.terminateEventNpc(p)
|
||||||
|
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||||
|
Assertions.assertNotEquals(previousEvent, AntiMacro.getEventNpc(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun randomEventSystemShouldSupportPauseAndUnpause() {
|
||||||
|
TestUtils.getMockPlayer("antimacropause").use { p ->
|
||||||
|
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
|
||||||
|
AntiMacro.pause(p)
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNull(AntiMacro.getEventNpc(p))
|
||||||
|
|
||||||
|
AntiMacro.unpause(p)
|
||||||
|
timer.nextExecution = getWorldTicks() + 5
|
||||||
|
TestUtils.advanceTicks(10, false)
|
||||||
|
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun shouldBeAbleToForceRandomEvent() {
|
||||||
|
TestUtils.getMockPlayer("antimacroforcerand").use { p ->
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
AntiMacro.forceEvent(p)
|
||||||
|
TestUtils.advanceTicks(1, false)
|
||||||
|
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun shouldBeAbleToForceSpecificRandomEvent() {
|
||||||
|
TestUtils.getMockPlayer("antimacroforcespecific").use { p ->
|
||||||
|
TestUtils.advanceTicks(5, false)
|
||||||
|
AntiMacro.forceEvent(p, RandomEvents.TREE_SPIRIT)
|
||||||
|
TestUtils.advanceTicks(1, false)
|
||||||
|
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||||
|
Assertions.assertEquals(NPCs.TREE_SPIRIT_438, AntiMacro.getEventNpc(p)?.originalId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun parseAntiMacroCommandArgsShouldReturnExpectedValues() {
|
||||||
|
val testData = arrayOf(
|
||||||
|
Triple("revent -p test", "test", null),
|
||||||
|
Triple("revent -p test ", "test", null),
|
||||||
|
Triple("revent -p test -e certer ", "test", RandomEvents.CERTER),
|
||||||
|
Triple("revent -p test_user -e Sandwich lady", "test_user", RandomEvents.SANDWICH_LADY),
|
||||||
|
Triple("revent -p test user -e sandwich Lady ", "test_user", RandomEvents.SANDWICH_LADY),
|
||||||
|
Triple("revent -e sandwich Lady -p test user ", "test_user", RandomEvents.SANDWICH_LADY),
|
||||||
|
Triple("revent test", "test", null),
|
||||||
|
Triple("revent test -e sAndwich Lady", "test", RandomEvents.SANDWICH_LADY)
|
||||||
|
)
|
||||||
|
|
||||||
|
for ((commandStr, expectedUser, expectedEvent) in testData) {
|
||||||
|
val (resultUser, resultEvent) = AntiMacro.parseCommandArgs(commandStr, "revent")
|
||||||
|
Assertions.assertEquals(expectedUser, resultUser)
|
||||||
|
Assertions.assertEquals(expectedEvent, resultEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user