From 9b08f2175b358d046acec9d656da6a20ef2efdb3 Mon Sep 17 00:00:00 2001 From: Zerken Date: Sun, 30 Jul 2023 02:52:45 +0000 Subject: [PATCH] Implemented Freaky Forester random event Added admin ::freak command to trigger Freaky Forester --- Server/data/configs/drop_tables.json | 16 +++- Server/data/configs/npc_configs.json | 82 ++++++++++++++++++- .../main/content/global/ame/RandomEvents.kt | 2 + .../events/freakyforester/FreakListeners.kt | 62 ++++++++++++++ .../ame/events/freakyforester/FreakUtils.kt | 57 +++++++++++++ .../freakyforester/FreakyForesterDialogue.kt | 27 ++++++ .../freakyforester/FreakyForesterNPC.kt | 44 ++++++++++ .../events/freakyforester/PheasantBehavior.kt | 37 +++++++++ .../skill/hunter/implings/ImplingBehavior.kt | 2 +- .../node/entity/combat/CombatSwingHandler.kt | 11 ++- .../core/game/node/entity/npc/NPCBehavior.kt | 13 ++- .../node/entity/npc/drop/NPCDropTables.java | 2 +- .../system/command/sets/MiscCommandSet.kt | 5 ++ 13 files changed, 350 insertions(+), 10 deletions(-) create mode 100644 Server/src/main/content/global/ame/events/freakyforester/FreakListeners.kt create mode 100644 Server/src/main/content/global/ame/events/freakyforester/FreakUtils.kt create mode 100644 Server/src/main/content/global/ame/events/freakyforester/FreakyForesterDialogue.kt create mode 100644 Server/src/main/content/global/ame/events/freakyforester/FreakyForesterNPC.kt create mode 100644 Server/src/main/content/global/ame/events/freakyforester/PheasantBehavior.kt diff --git a/Server/data/configs/drop_tables.json b/Server/data/configs/drop_tables.json index f4ce90531..67306cc63 100644 --- a/Server/data/configs/drop_tables.json +++ b/Server/data/configs/drop_tables.json @@ -60209,7 +60209,21 @@ ], "charm": [], "ids": "3057,3059,3058,3060,3061,3062,3063,3064,3065,3066", - "description": "champion's challenge bosses", + "description": "Champion's Challenge NPC - activity", "main": [] + }, + { + "default": [], + "charm": [], + "ids": "2459,2460,2461,2462", + "description": "Pheasant NPC (level 4) - Freaky Forester - Random event", + "main": [ + { + "minAmount": "1", + "weight": "1.0", + "id": "6178", + "maxAmount": "1" + } + ] } ] \ No newline at end of file diff --git a/Server/data/configs/npc_configs.json b/Server/data/configs/npc_configs.json index a640ad51f..0ede1da6f 100644 --- a/Server/data/configs/npc_configs.json +++ b/Server/data/configs/npc_configs.json @@ -24138,6 +24138,82 @@ "range_level": "1", "attack_level": "1" }, + { + "examine": "A brightly coloured game bird.", + "melee_animation": "2372", + "range_animation": "2372", + "combat_audio": "690,692,691", + "attack_speed": "6", + "respawn_delay": "18", + "defence_animation": "2371", + "magic_animation": "2372", + "death_animation": "2373", + "name": "Pheasant", + "defence_level": "1", + "safespot": null, + "lifepoints": "5", + "strength_level": "1", + "id": "2459", + "range_level": "1", + "attack_level": "1" + }, + { + "examine": "A brightly coloured game bird.", + "melee_animation": "2372", + "range_animation": "2372", + "combat_audio": "690,692,691", + "attack_speed": "6", + "respawn_delay": "18", + "defence_animation": "2371", + "magic_animation": "2372", + "death_animation": "2373", + "name": "Pheasant", + "defence_level": "1", + "safespot": null, + "lifepoints": "5", + "strength_level": "1", + "id": "2460", + "range_level": "1", + "attack_level": "1" + }, + { + "examine": "A brightly coloured game bird.", + "melee_animation": "2372", + "range_animation": "2372", + "combat_audio": "690,692,691", + "attack_speed": "6", + "respawn_delay": "18", + "defence_animation": "2371", + "magic_animation": "2372", + "death_animation": "2373", + "name": "Pheasant", + "defence_level": "1", + "safespot": null, + "lifepoints": "5", + "strength_level": "1", + "id": "2461", + "range_level": "1", + "attack_level": "1" + }, + { + "examine": "A brightly coloured game bird.", + "melee_animation": "2372", + "range_animation": "2372", + "combat_audio": "690,692,691", + "attack_speed": "6", + "respawn_delay": "18", + "defence_animation": "2371", + "magic_animation": "2372", + "death_animation": "2373", + "name": "Pheasant", + "defence_level": "1", + "safespot": null, + "lifepoints": "5", + "strength_level": "1", + "id": "2462", + "range_level": "1", + "attack_level": "1" + }, { "examine": "A fowl beast.", "combat_style": "2", @@ -28767,8 +28843,8 @@ { "examine": "Champion of the giants.", "melee_animation": "6368", - "attack_speed": "4", "range_animation": "0", + "attack_speed": "4", "respawn_delay": "60", "defence_animation": "0", "weakness": "8", @@ -28812,9 +28888,9 @@ { "examine": "Champion of the goblins.", "melee_animation": "6188", - "attack_speed": "4", "range_animation": "0", "combat_audio": "469,472,471", + "attack_speed": "4", "magic_level": "26", "defence_animation": "0", "weakness": "10", @@ -28832,10 +28908,10 @@ { "examine": "Champion of the hobgoblins.", "combat_style": "1", - "attack_speed": "4", "melee_animation": "164", "range_animation": "164", "combat_audio": "469,472,471", + "attack_speed": "4", "respawn_delay": "60", "defence_animation": "165", "weakness": "0", diff --git a/Server/src/main/content/global/ame/RandomEvents.kt b/Server/src/main/content/global/ame/RandomEvents.kt index 2318b403c..19d49ce62 100644 --- a/Server/src/main/content/global/ame/RandomEvents.kt +++ b/Server/src/main/content/global/ame/RandomEvents.kt @@ -5,6 +5,7 @@ import content.global.ame.events.MysteriousOldManNPC import content.global.ame.events.certer.CerterNPC import content.global.ame.events.drilldemon.SeargentDamienNPC import content.global.ame.events.evilchicken.EvilChickenNPC +import content.global.ame.events.freakyforester.FreakyForesterNPC import content.global.ame.events.genie.GenieNPC import content.global.ame.events.rivertroll.RiverTrollRENPC import content.global.ame.events.rockgolem.RockGolemRENPC @@ -40,6 +41,7 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n DRILL_DEMON(npc = SeargentDamienNPC()), EVIL_CHICKEN(npc = EvilChickenNPC()), SURPRISE_EXAM(npc = MysteriousOldManNPC(), type = "sexam"), + FREAKY_FORESTER(npc = FreakyForesterNPC(), skillId = Skills.WOODCUTTING), TREE_SPIRIT(npc = TreeSpiritRENPC(), skillId = Skills.WOODCUTTING), RIVER_TROLL(RiverTrollRENPC(), skillId = Skills.FISHING), ROCK_GOLEM(RockGolemRENPC(), skillId = Skills.MINING), diff --git a/Server/src/main/content/global/ame/events/freakyforester/FreakListeners.kt b/Server/src/main/content/global/ame/events/freakyforester/FreakListeners.kt new file mode 100644 index 000000000..fe5fc7cf1 --- /dev/null +++ b/Server/src/main/content/global/ame/events/freakyforester/FreakListeners.kt @@ -0,0 +1,62 @@ +package content.global.ame.events.freakyforester + +import core.api.* +import org.rs09.consts.NPCs +import org.rs09.consts.Scenery +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.Entity +import core.game.system.task.Pulse +import core.game.world.map.zone.ZoneBorders +import core.game.world.map.zone.ZoneRestriction +import org.rs09.consts.Items + +class FreakListeners : InteractionListener, MapArea { + + private val exitPortal = Scenery.PORTAL_8972 + private val freakNpc = NPCs.FREAKY_FORESTER_2458 + private val pheasants = intArrayOf(NPCs.PHEASANT_2459,NPCs.PHEASANT_2460,NPCs.PHEASANT_2461,NPCs.PHEASANT_2462) + override fun defineListeners() { + on(freakNpc,IntType.NPC,"talk-to"){player, node -> + if (getAttribute(player, FreakUtils.freakTask, -1) == -1) FreakUtils.giveFreakTask(player) + openDialogue(player, FreakyForesterDialogue(), node.asNpc()) + return@on true + } + + on(pheasants,IntType.NPC,"attack") { player, node -> + if (getAttribute(player,FreakUtils.freakComplete, false)) { + sendMessage(player,"You don't need to attack any more pheasants. You're allowed to leave.") + } else if (inInventory(player, Items.RAW_PHEASANT_6178) || inInventory(player, Items.RAW_PHEASANT_6179) || getAttribute(player, FreakUtils.pheasantKilled, false)){ + sendMessage(player,"You don't need to attack any more pheasants.") + } else { + player.attack(node.asNpc()) + } + return@on true + } + + on(exitPortal,IntType.SCENERY,"enter") { player, _ -> + if (getAttribute(player,FreakUtils.freakComplete,false)) { + FreakUtils.cleanup(player) + submitWorldPulse(object : Pulse(2) { + override fun pulse(): Boolean { + FreakUtils.reward(player) + return true + } + }) + return@on true + } else sendMessage(player,"A supernatural force prevents you from leaving.") + return@on true + } + } + override fun defineAreaBorders(): Array { + return arrayOf(ZoneBorders(2587, 4758, 2616,4788)) + } + + override fun getRestrictions(): Array { + return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS) + } + + override fun areaEnter(entity: Entity) { + entity.locks.lockTeleport(1000000) + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/freakyforester/FreakUtils.kt b/Server/src/main/content/global/ame/events/freakyforester/FreakUtils.kt new file mode 100644 index 000000000..bac46f78f --- /dev/null +++ b/Server/src/main/content/global/ame/events/freakyforester/FreakUtils.kt @@ -0,0 +1,57 @@ +package content.global.ame.events.freakyforester + +import core.api.* +import org.rs09.consts.Items +import org.rs09.consts.NPCs +import core.game.node.entity.player.Player +import core.game.world.map.Location +import core.tools.RandomFunction + +object FreakUtils{ + const val freakNpc = NPCs.FREAKY_FORESTER_2458 + const val freakPreviousLoc = "/save:freakyf:location" + const val freakTask = "/save:freakyf:task" + const val freakComplete = "/save:freakyf:complete" + const val pheasantKilled = "freakyf:killed" + fun giveFreakTask(player: Player) { + when(RandomFunction.getRandom(4)) { + 0 -> setAttribute(player, freakTask, NPCs.PHEASANT_2459) + 1 -> setAttribute(player, freakTask, NPCs.PHEASANT_2460) + 2 -> setAttribute(player, freakTask, NPCs.PHEASANT_2461) + 3 -> setAttribute(player, freakTask, NPCs.PHEASANT_2462) + else -> setAttribute(player, freakTask, NPCs.PHEASANT_2459) + } + player.dialogueInterpreter.open(FreakyForesterDialogue(), freakNpc) + } + + fun teleport(player: Player) { + setAttribute(player, freakPreviousLoc, player.location) + teleport(player, Location.create(2599, 4777 ,0)) + } + + fun cleanup(player: Player) { + player.locks.unlockTeleport() + player.properties.teleportLocation = getAttribute(player,freakPreviousLoc,null) + removeAttributes(player, freakPreviousLoc, freakTask, freakComplete, pheasantKilled) + removeAll(player, Items.RAW_PHEASANT_6178) + removeAll(player, Items.RAW_PHEASANT_6178, Container.BANK) + removeAll(player, Items.RAW_PHEASANT_6179) + removeAll(player, Items.RAW_PHEASANT_6179, Container.BANK) + } + + fun reward(player: Player){ + val hasHat = hasAnItem(player, Items.LEDERHOSEN_HAT_6182).container != null + val hasTop = hasAnItem(player, Items.LEDERHOSEN_TOP_6180).container != null + val hasShort = hasAnItem(player, Items.LEDERHOSEN_SHORTS_6181).container != null + sendNPCDialogue(player, freakNpc, "You get a lederhosen item as a reward for your help, many thanks!") + when{ + (!hasHat) -> addItemOrDrop(player, Items.LEDERHOSEN_HAT_6182, 1) + (!hasTop) -> addItemOrDrop(player, Items.LEDERHOSEN_TOP_6180, 1) + (!hasShort) -> addItemOrDrop(player, Items.LEDERHOSEN_SHORTS_6181, 1) + else ->{ + sendNPCDialogue(player, freakNpc, "You get some money for your help, many thanks!") + addItemOrDrop(player, Items.COINS_995, 500) + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/freakyforester/FreakyForesterDialogue.kt b/Server/src/main/content/global/ame/events/freakyforester/FreakyForesterDialogue.kt new file mode 100644 index 000000000..c9ff3cc0a --- /dev/null +++ b/Server/src/main/content/global/ame/events/freakyforester/FreakyForesterDialogue.kt @@ -0,0 +1,27 @@ +package content.global.ame.events.freakyforester + +import core.api.* +import core.game.dialogue.DialogueFile +import core.game.dialogue.FacialExpression +import core.tools.END_DIALOGUE +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +class FreakyForesterDialogue : DialogueFile(){ + + override fun handle(componentID: Int, buttonID: Int) { + if (removeItem(player!!, Items.RAW_PHEASANT_6179) && !getAttribute(player!!, FreakUtils.freakComplete, false)) { + npcl(FacialExpression.NEUTRAL, "That's not the right one.").also { stage = END_DIALOGUE } + setAttribute(player!!, FreakUtils.pheasantKilled, false) + } else if (removeItem(player!!, Items.RAW_PHEASANT_6178) || getAttribute(player!!, FreakUtils.freakComplete, false)) { + npcl(FacialExpression.NEUTRAL, "Thanks, ${player!!.username}, you may leave the area now.").also { stage = END_DIALOGUE } + sendChat(findNPC(FreakUtils.freakNpc)!!, "Thanks, ${player!!.username}, you may leave the area now.") + setAttribute(player!!, FreakUtils.freakComplete, true) + } else when (getAttribute(player!!, FreakUtils.freakTask, -1)) { + NPCs.PHEASANT_2459 -> sendNPCDialogue(player!!, FreakUtils.freakNpc, "Hey there ${player!!.username}. Can you kill the one tailed pheasant please. Bring me the raw pheasant when you're done.").also { stage = END_DIALOGUE } + NPCs.PHEASANT_2460 -> sendNPCDialogue(player!!, FreakUtils.freakNpc, "Hey there ${player!!.username}. Can you kill the two tailed pheasant please. Bring me the raw pheasant when you're done.").also { stage = END_DIALOGUE } + NPCs.PHEASANT_2461 -> sendNPCDialogue(player!!, FreakUtils.freakNpc, "Hey there ${player!!.username}. Can you kill the three tailed pheasant please. Bring me the raw pheasant when you're done.").also { stage = END_DIALOGUE } + NPCs.PHEASANT_2462 -> sendNPCDialogue(player!!, FreakUtils.freakNpc, "Hey there ${player!!.username}. Can you kill the four tailed pheasant please. Bring me the raw pheasant when you're done.").also { stage = END_DIALOGUE } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/freakyforester/FreakyForesterNPC.kt b/Server/src/main/content/global/ame/events/freakyforester/FreakyForesterNPC.kt new file mode 100644 index 000000000..4932298f7 --- /dev/null +++ b/Server/src/main/content/global/ame/events/freakyforester/FreakyForesterNPC.kt @@ -0,0 +1,44 @@ +package content.global.ame.events.freakyforester + +import content.global.ame.RandomEventManager +import content.global.ame.RandomEventNPC +import core.api.* +import org.rs09.consts.NPCs +import core.api.utils.WeightBasedTable +import core.game.node.entity.npc.NPC +import core.game.system.task.Pulse +import core.game.world.update.flag.context.Graphics +import org.rs09.consts.Sounds + +class FreakyForesterNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.FREAKY_FORESTER_2458) { + + override fun init() { + super.init() + lock(player, 8) + submitWorldPulse(object : Pulse() { + var counter = 0 + override fun pulse(): Boolean { + when (counter++) { + 0 -> sendChat("Ah, ${player.username}, just the person I need!") + 4 -> { + sendGraphics(Graphics(308, 100, 50), player.location) + animate(player,714) + playAudio(player, Sounds.TELEPORT_ALL_200) + } + 7 -> { + FreakUtils.teleport(player) + FreakUtils.giveFreakTask(player) + RandomEventManager.getInstance(player)!!.event?.terminate() + openDialogue(player, FreakyForesterDialogue(), FreakUtils.freakNpc) + resetAnimator(player) + } + } + return false + } + }) + } + + override fun talkTo(npc: NPC) { + player.dialogueInterpreter.open(FreakyForesterDialogue(),npc) + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/ame/events/freakyforester/PheasantBehavior.kt b/Server/src/main/content/global/ame/events/freakyforester/PheasantBehavior.kt new file mode 100644 index 000000000..ad49212d2 --- /dev/null +++ b/Server/src/main/content/global/ame/events/freakyforester/PheasantBehavior.kt @@ -0,0 +1,37 @@ +package content.global.ame.events.freakyforester + +import core.api.getAttribute +import core.api.sendMessage +import core.api.sendNPCDialogue +import core.api.setAttribute +import core.game.node.entity.Entity +import core.game.node.entity.combat.BattleState +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.game.node.entity.player.Player +import core.game.node.item.Item +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +class PheasantBehavior : NPCBehavior(NPCs.PHEASANT_2459, NPCs.PHEASANT_2460, NPCs.PHEASANT_2461, NPCs.PHEASANT_2462) { + override fun onDropTableRolled(self: NPC, killer: Entity, drops: ArrayList) { + val assignedPheasant = getAttribute(killer, FreakUtils.freakTask, -1) + if (assignedPheasant == -1) return + drops.removeLast() + if (assignedPheasant == self.id) { + drops.add(Item (Items.RAW_PHEASANT_6178)) + } else { + drops.add(Item (Items.RAW_PHEASANT_6179)) + } + setAttribute(killer, FreakUtils.pheasantKilled, true) + } + + override fun beforeDamageReceived(self: NPC, attacker: Entity, state: BattleState) { + state.estimatedHit = 5 + state.secondaryHit = 0 + } + + override fun getXpMultiplier(self: NPC, attacker: Entity): Double { + return 0.0 + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/hunter/implings/ImplingBehavior.kt b/Server/src/main/content/global/skill/hunter/implings/ImplingBehavior.kt index d90134af3..30beec1d7 100644 --- a/Server/src/main/content/global/skill/hunter/implings/ImplingBehavior.kt +++ b/Server/src/main/content/global/skill/hunter/implings/ImplingBehavior.kt @@ -69,7 +69,7 @@ class ImplingBehavior : NPCBehavior (*Impling.getIds()) { } //manually clear any rolled drops so any drops set by JSON are properly ignored. - override fun onDropTableRolled (self: NPC, drops: ArrayList) { + override fun onDropTableRolled (self: NPC, killer: Entity, drops: ArrayList) { drops.clear() } diff --git a/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt b/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt index 4caa84ea6..a65b00d03 100644 --- a/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt +++ b/Server/src/main/core/game/node/entity/combat/CombatSwingHandler.kt @@ -483,10 +483,13 @@ abstract class CombatSwingHandler(var type: CombatStyle?) { is Player -> {player = entity; attStyle = entity.properties.attackStyle.style} else -> return } + if (victim is NPC) EXPERIENCE_MOD *= victim.behavior.getXpMultiplier(victim, player) if (state != null) { val hit = state.totalDamage if (entity is Player) { - player.skills.addExperience(Skills.HITPOINTS, hit * 1.33, true) + var experience = hit * 1.33 + if (victim is NPC) experience *= victim.behavior.getXpMultiplier(victim, player) + player.skills.addExperience(Skills.HITPOINTS, experience, true) } var skill = -1 @@ -513,8 +516,10 @@ abstract class CombatSwingHandler(var type: CombatStyle?) { WeaponInterface.STYLE_CAST -> skill = Skills.MAGIC WeaponInterface.STYLE_DEFENSIVE_CAST -> { - player.skills.addExperience(Skills.MAGIC, hit * 1.33, true) - player.skills.addExperience(Skills.DEFENCE, hit.toDouble(), true) + var experience = hit.toDouble() + if (victim is NPC) experience *= victim.behavior.getXpMultiplier(victim, player) + player.skills.addExperience(Skills.MAGIC, experience * 1.33, true) + player.skills.addExperience(Skills.DEFENCE, experience, true) return } } diff --git a/Server/src/main/core/game/node/entity/npc/NPCBehavior.kt b/Server/src/main/core/game/node/entity/npc/NPCBehavior.kt index f35c41f0a..6dbc967d6 100644 --- a/Server/src/main/core/game/node/entity/npc/NPCBehavior.kt +++ b/Server/src/main/core/game/node/entity/npc/NPCBehavior.kt @@ -99,9 +99,10 @@ open class NPCBehavior(vararg val ids: Int = intArrayOf()) : ContentInterface { /** * Called after this NPC's drop table is rolled, but before the items are actually dropped, so the list can be manipulated. * @param self the NPC instance this behavior belongs to + * @param killer the killer of the npc * @param drops the generated list of drops for this roll of the table */ - open fun onDropTableRolled(self: NPC, drops: ArrayList) {} + open fun onDropTableRolled(self: NPC, killer: Entity, drops: ArrayList) {} /** * Called by combat-related code to check if this NPC can be attacked by the `attacker` entity. @@ -139,4 +140,14 @@ open class NPCBehavior(vararg val ids: Int = intArrayOf()) : ContentInterface { open fun getClippingSupplier(self: NPC) : ClipMaskSupplier? { return StandardClipMaskSupplier } + + /** + * Modifies the combat experience gained from killing an entity + * @param self the NPC instance this behavior belongs to + * @param attacker entity attacking the npc + * @return multiplier for final xp gain + */ + open fun getXpMultiplier(self: NPC, attacker: Entity) : Double { + return 1.0 + } } diff --git a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java index 4a676150d..5d545bc69 100644 --- a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java +++ b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java @@ -75,7 +75,7 @@ public final class NPCDropTables { public void drop(NPC npc, Entity looter) { Player p = looter instanceof Player ? (Player) looter : null; ArrayList drops = table.roll(looter); - npc.behavior.onDropTableRolled(npc, drops); + npc.behavior.onDropTableRolled(npc, looter, drops); drops.forEach(item -> createDrop(item,p,npc,npc.getDropLocation())); } diff --git a/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt b/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt index 8e12a60c7..98fb94a9c 100644 --- a/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/MiscCommandSet.kt @@ -551,6 +551,11 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){ 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("revent", Privilege.ADMIN){ player, _ -> println(player.pulseManager.current) content.global.ame.RandomEventManager.getInstance(player)!!.fireEvent()