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:
@@ -23,6 +23,7 @@ import org.rs09.consts.Components
|
||||
import core.ServerConstants
|
||||
import core.api.Event
|
||||
import core.api.utils.PlayerCamera
|
||||
import core.game.system.timer.impl.AntiMacro
|
||||
import core.tools.SystemLogger
|
||||
import core.game.world.GameWorld
|
||||
import core.tools.Log
|
||||
@@ -238,7 +239,7 @@ abstract class Cutscene(val player: Player) {
|
||||
player.lock()
|
||||
player.hook(Event.SelfDeath, CUTSCENE_DEATH_HOOK)
|
||||
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()
|
||||
player.unhook(CUTSCENE_DEATH_HOOK)
|
||||
player.logoutListeners.remove("cutscene")
|
||||
content.global.ame.RandomEventManager.getInstance(player)?.enabled = true
|
||||
AntiMacro.unpause(player)
|
||||
PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 0))
|
||||
try {
|
||||
endActions?.invoke()
|
||||
|
||||
@@ -105,7 +105,7 @@ public abstract class Entity extends Node {
|
||||
* The reward locks.
|
||||
*/
|
||||
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];
|
||||
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ public class Player extends Entity {
|
||||
/**
|
||||
* The quest repository.
|
||||
*/
|
||||
private QuestRepository questRepository = new QuestRepository(this);
|
||||
public QuestRepository questRepository = new QuestRepository(this);
|
||||
|
||||
/**
|
||||
* The prayer manager.
|
||||
@@ -239,7 +239,7 @@ public class Player extends Entity {
|
||||
/**
|
||||
* The saved data.
|
||||
*/
|
||||
private SavedData savedData = new SavedData(this);
|
||||
public SavedData savedData = new SavedData(this);
|
||||
|
||||
/**
|
||||
* The request manager.
|
||||
|
||||
@@ -39,7 +39,7 @@ class PlayerSaveParser(val player: Player) {
|
||||
var saveFile: JSONObject? = null
|
||||
var read = true
|
||||
|
||||
init {
|
||||
fun parse() {
|
||||
val JSON = File(ServerConstants.PLAYER_SAVE_PATH + player.name + ".json")
|
||||
if(JSON.exists())
|
||||
{
|
||||
@@ -49,36 +49,38 @@ class PlayerSaveParser(val player: Player) {
|
||||
if (read) {
|
||||
saveFile = parser.parse(reader) as JSONObject
|
||||
}
|
||||
|
||||
if (read) {
|
||||
parseData()
|
||||
}
|
||||
}
|
||||
|
||||
fun parse() {
|
||||
if (read) {
|
||||
parseCore()
|
||||
parseAttributes()
|
||||
parseSkills()
|
||||
parseSettings()
|
||||
parseQuests()
|
||||
parseAppearance()
|
||||
parseGrave()
|
||||
parseVarps()
|
||||
parseStates()
|
||||
parseSpellbook()
|
||||
parseSavedData()
|
||||
parseAutocastSpell()
|
||||
parseFarming()
|
||||
parseConfigs()
|
||||
parseMonitor()
|
||||
parseMusic()
|
||||
parseFamiliars()
|
||||
parseBankPin()
|
||||
parseHouse()
|
||||
parseIronman()
|
||||
parseEmoteManager()
|
||||
parseStatistics()
|
||||
parseAchievements()
|
||||
parsePouches()
|
||||
parsePouches()
|
||||
}
|
||||
fun parseData() {
|
||||
parseCore()
|
||||
parseAttributes()
|
||||
parseSkills()
|
||||
parseSettings()
|
||||
parseQuests()
|
||||
parseAppearance()
|
||||
parseGrave()
|
||||
parseVarps()
|
||||
parseStates()
|
||||
parseSpellbook()
|
||||
parseSavedData()
|
||||
parseAutocastSpell()
|
||||
parseFarming()
|
||||
parseConfigs()
|
||||
parseMonitor()
|
||||
parseMusic()
|
||||
parseFamiliars()
|
||||
parseBankPin()
|
||||
parseHouse()
|
||||
parseIronman()
|
||||
parseEmoteManager()
|
||||
parseStatistics()
|
||||
parseAchievements()
|
||||
parsePouches()
|
||||
parsePouches()
|
||||
}
|
||||
|
||||
fun runContentHooks()
|
||||
|
||||
@@ -34,7 +34,7 @@ class PlayerSaver (val player: Player){
|
||||
companion object {
|
||||
val contentHooks = ArrayList<PersistPlayer>()
|
||||
}
|
||||
private fun populate(): JSONObject {
|
||||
fun populate(): JSONObject {
|
||||
val saveFile = JSONObject()
|
||||
saveCoreData(saveFile)
|
||||
saveSkills(saveFile)
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.rs09.consts.Items;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static core.api.ContentAPIKt.getWorldTicks;
|
||||
import static java.lang.Math.floor;
|
||||
import static java.lang.Math.max;
|
||||
|
||||
@@ -119,7 +120,8 @@ public final class Skills {
|
||||
*/
|
||||
private int skillMilestone;
|
||||
|
||||
public int lastTrainedSkill = -1;
|
||||
public int lastTrainedSkill = -1;
|
||||
public int lastXpGain = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Skills} {@code Object}.
|
||||
@@ -271,7 +273,8 @@ public final class Skills {
|
||||
lastUpdateXp = this.experience.clone();
|
||||
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("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, _ ->
|
||||
player.details.credits += 100
|
||||
}
|
||||
|
||||
@@ -56,6 +56,12 @@ class TimerManager (val entity: Entity) {
|
||||
timer.save(obj, entity)
|
||||
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) {
|
||||
|
||||
@@ -30,7 +30,6 @@ object TimerRegistry {
|
||||
|
||||
@JvmStatic
|
||||
fun addAutoTimers (entity: Entity) {
|
||||
(entity as? Player)?.debug ("Adding auto timers...")
|
||||
for (timer in autoTimers) {
|
||||
if (!hasTimerActive (entity, timer.identifier))
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user