Implemented semi-authentic Pious Pete random event

This commit is contained in:
Oven Bread 2025-07-15 12:29:09 +00:00 committed by Ryan
parent 98f662d0c6
commit bef103e259
8 changed files with 323 additions and 0 deletions

View file

@ -6727,6 +6727,10 @@
"npc_id": "3205", "npc_id": "3205",
"loc_data": "{3139,3448,0,1,3}-" "loc_data": "{3139,3448,0,1,3}-"
}, },
{
"npc_id": "3207",
"loc_data": "{1970,5002,0,1,4}-"
},
{ {
"npc_id": "3213", "npc_id": "3213",
"loc_data": "{2568,3334,0,1,0}-" "loc_data": "{2568,3334,0,1,0}-"

View file

@ -10,6 +10,7 @@ import content.global.ame.events.evilchicken.EvilChickenNPC
import content.global.ame.events.freakyforester.FreakyForesterNPC import content.global.ame.events.freakyforester.FreakyForesterNPC
import content.global.ame.events.maze.MazeNPC import content.global.ame.events.maze.MazeNPC
import content.global.ame.events.genie.GenieNPC import content.global.ame.events.genie.GenieNPC
import content.global.ame.events.candlelight.PiousPeteNPC
import content.global.ame.events.pillory.PilloryNPC import content.global.ame.events.pillory.PilloryNPC
import content.global.ame.events.rickturpentine.RickTurpentineNPC import content.global.ame.events.rickturpentine.RickTurpentineNPC
import content.global.ame.events.rivertroll.RiverTrollRENPC import content.global.ame.events.rivertroll.RiverTrollRENPC
@ -21,6 +22,7 @@ import content.global.ame.events.strangeplant.StrangePlantNPC
import content.global.ame.events.swarm.SwarmNPC import content.global.ame.events.swarm.SwarmNPC
import content.global.ame.events.treespirit.TreeSpiritRENPC import content.global.ame.events.treespirit.TreeSpiritRENPC
import content.global.ame.events.zombie.ZombieRENPC import content.global.ame.events.zombie.ZombieRENPC
import core.ServerConstants
import core.api.utils.WeightBasedTable import core.api.utils.WeightBasedTable
import core.api.utils.WeightedItem import core.api.utils.WeightedItem
@ -29,6 +31,7 @@ import core.game.node.entity.skill.Skills
enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = null, val skillIds: IntArray = intArrayOf(), 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()),
CANDLELIGHT(npc = PiousPeteNPC(), skillIds = intArrayOf(Skills.PRAYER)),
CERTER(npc = CerterNPC(), loot = WeightBasedTable.create( CERTER(npc = CerterNPC(), loot = WeightBasedTable.create(
WeightedItem(Items.UNCUT_SAPPHIRE_1623,1,1,3.4), WeightedItem(Items.UNCUT_SAPPHIRE_1623,1,1,3.4),
WeightedItem(Items.KEBAB_1971,1,1,1.7), WeightedItem(Items.KEBAB_1971,1,1,1.7),
@ -82,6 +85,9 @@ 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 (!ServerConstants.INAUTHENTIC_CANDLELIGHT_RANDOM && event == CANDLELIGHT) {
continue
}
for (id in event.skillIds) { for (id in event.skillIds) {
val list = skillMap[id] ?: ArrayList<RandomEvents>().also { skillMap[id] = it } val list = skillMap[id] ?: ArrayList<RandomEvents>().also { skillMap[id] = it }
list.add (event) list.add (event)

View file

@ -0,0 +1,164 @@
package content.global.ame.events.candlelight
import core.api.*
import core.api.utils.PlayerCamera
import core.game.interaction.InteractionListener
import core.game.interaction.InterfaceListener
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import org.rs09.consts.Scenery
/**
* Candlelight Interface CANDLELIGHT_178
*
*/
class CandlelightInterface : InterfaceListener, InteractionListener, MapArea {
companion object {
const val CANDLELIGHT_INTERFACE = 178
const val CANDLELIGHT_RETURN_LOC = "/save:original-loc"
const val CANDLELIGHT_CANDLE_ARRAY = "/save:candlelight:candle-array"
const val CANDLELIGHT_CAMERA_AT = "candlelight:camera-at"
val CANDLE_LOC_ARRAY = arrayOf(
Location(1967, 4997),
Location(1968, 4998),
Location(1967, 4999),
Location(1968, 5000),
Location(1967, 5001),
Location(1968, 5002),
Location(1967, 5003),
Location(1968, 5004),
Location(1967, 5005),
Location(1968, 5006),
Location(1967, 5007),
)
fun initCandlelight(player: Player) {
val candleArray = intArrayOf(0,0,0,0,0,0,2,2,2,2,2)
candleArray.shuffle()
setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray)
for (candleIndex in 0..10) {
setVarbit(player, 1771 + candleIndex, candleArray[candleIndex])
}
}
fun areCandlesLit(player: Player): Boolean {
val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0))
for (candle in candleArray) {
if (candle == 0) {
return false
}
}
return true
}
fun lightCandle(player: Player) {
var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002))
val candleIndex = CANDLE_LOC_ARRAY.indexOf(currentCamLoc)
val varbit = candleIndex + 1771 // Essentially all varbits are 1771 .. 1881
if (candleIndex != -1) {
val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0))
if (candleArray[candleIndex] == 0) {
candleArray[candleIndex] = 1
setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray)
setVarbit(player, varbit, 1)
sendMessage(player, "You light the candle.")
} else if (candleArray[candleIndex] == 1) {
sendMessage(player, "This candle is already lit.")
} else {
sendMessage(player, "This candle is too short to light.")
}
} else {
sendMessage(player, "There is nothing to light here.")
}
}
fun moveCamera(player: Player, direction: Direction, firstTime: Boolean = false) {
var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002))
when(direction) {
Direction.NORTH -> currentCamLoc = currentCamLoc.transform(Direction.NORTH)
Direction.SOUTH -> currentCamLoc = currentCamLoc.transform(Direction.SOUTH)
Direction.EAST -> currentCamLoc = currentCamLoc.transform(Direction.EAST)
Direction.WEST -> currentCamLoc = currentCamLoc.transform(Direction.WEST)
else -> {}
}
if (currentCamLoc.x < 1967) { currentCamLoc.x = 1967 }
if (currentCamLoc.x > 1968) { currentCamLoc.x = 1968 }
if (currentCamLoc.y < 4997) { currentCamLoc.y = 4997 }
if (currentCamLoc.y > 5007) { currentCamLoc.y = 5007 }
setAttribute(player, CANDLELIGHT_CAMERA_AT, currentCamLoc)
PlayerCamera(player).rotateTo(currentCamLoc.x - 30, currentCamLoc.y,0,200) // height is kind of a relative value?
PlayerCamera(player).panTo(currentCamLoc.x + 2, currentCamLoc.y,350, if(firstTime) 400 else 10)
}
}
override fun defineInterfaceListeners() {
on(CANDLELIGHT_INTERFACE){ player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
1 -> moveCamera(player, Direction.WEST)
2 -> moveCamera(player, Direction.EAST)
3 -> lightCandle(player)/* Light */
4 -> moveCamera(player, Direction.SOUTH)
5 -> moveCamera(player, Direction.NORTH)
9 -> closeInterface(player)
}
return@on true
}
onOpen(CANDLELIGHT_INTERFACE){ player, component ->
// Move camera
return@onOpen true
}
onClose(CANDLELIGHT_INTERFACE){ player, component ->
PlayerCamera(player).reset()
// Reset camera
return@onClose true
}
}
override fun defineListeners() {
on((11364 .. 11394).toIntArray(), SCENERY, "light") { player, node ->
setAttribute(player, CANDLELIGHT_CAMERA_AT, Location(node.location.x, node.location.y))
moveCamera(player, Direction.NORTH_WEST, true)
openInterface(player, CANDLELIGHT_INTERFACE)
return@on true
}
}
override fun defineDestinationOverrides() {
setDest(SCENERY, (11364 .. 11394).toIntArray(),"light"){ player, node ->
return@setDest Location(1970, node.location.y)
}
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(ZoneBorders.forRegion(7758))
}
override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.TELEPORT, ZoneRestriction.OFF_MAP)
}
override fun areaEnter(entity: Entity) {
if (entity is Player) {
initCandlelight(entity)
entity.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 12)
}
}
override fun areaLeave(entity: Entity, logout: Boolean) {
if (entity is Player) {
entity.interfaceManager.restoreTabs()
}
}
}

View file

@ -0,0 +1,94 @@
package content.global.ame.events.candlelight
import content.global.ame.RandomEvents
import content.global.ame.events.pillory.PilloryInterface
import content.global.ame.returnPlayer
import core.api.*
import core.game.dialogue.*
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
// iface 178
@Initializable
class PiousPeteDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player): DialoguePlugin {
return PiousPeteDialogue(player)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, PiousPeteDialogueFile(), npc)
return false
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.PIOUS_PETE_3207, NPCs._6564)
}
}
class PiousPeteDialogueFile : DialogueLabeller() {
override fun addConversation() {
npc(ChatAnim.THINKING, "Have you lit all the tall candles?")
exec { player, npc ->
if (CandlelightInterface.areCandlesLit(player)) {
loadLabel(player, "yeslit")
} else {
loadLabel(player, "nolit")
}
}
label("nolit")
player(ChatAnim.HALF_GUILTY, "Sorry, not yet.")
npc(ChatAnim.SAD, "Please help me in lighting the candles. I just need you to light all the tall candles, but not the short ones.")
line("Click on the pillars to open an interface", "to move around and light the candles.")
label("yeslit")
player(ChatAnim.FRIENDLY, "Yes, the tall ones are all lit.")
npc(ChatAnim.HAPPY, "Thank you my brother! I will now return you where you came from with a parting gift.")
npc(ChatAnim.FRIENDLY, "Take care brother!")
exec { player, npc ->
queueScript(player, 0, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
lock(player, 6)
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
1 -> {
returnPlayer(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
closeInterface(player)
return@queueScript delayScript(player, 3)
}
2 -> {
val loot = RandomEvents.CERTER.loot!!.roll(player)[0]
addItemOrDrop(player, loot.id, loot.amount)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
}
}
}
class PiousPeteStartingDialogueFile : DialogueLabeller() {
override fun addConversation() {
npc("I'm sorry to drag you away from your tasks, but I need a little help with something.")
player(ChatAnim.THINKING,"How can I help?")
npc("This is a chapel dedicated to our lord, Saradomin, and I'm tasked with maintaining this chapel.")
npc(ChatAnim.SAD,"My task is to light the chapel candles, but I couldn't reach them myself and I kept getting dazzled by the light whenever I tried.")
npc("So I need your help in lighting the candles. I need you to light all the tall candles, but not the short ones.")
npc(ChatAnim.FRIENDLY, "Once all the tall candles are all lit, come back and see me, and I will reward you for your work.")
}
}

View file

@ -0,0 +1,49 @@
package content.global.ame.events.candlelight
import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.link.TeleportManager
import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
/** "::revent -p player_name -e candlelight" **/
class PiousPeteNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PRIEST_3206) {
override fun init() {
super.init()
// Supposed to be "I'm sorry to drag you away from your tasks, but I need a little help with something." but it's too goddamn long.
sendChat("${player.username.capitalize()}! I need a little help with something.")
face(player)
queueScript(player, 4, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
lock(player, 6)
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
1 -> {
CandlelightInterface.initCandlelight(player)
kidnapPlayer(player, Location(1972, 5002, 0), TeleportManager.TeleportType.INSTANT)
// AntiMacro.terminateEventNpc(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
openDialogue(player, PiousPeteStartingDialogueFile(), NPC(NPCs.PIOUS_PETE_3207))
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
}
override fun talkTo(npc: NPC) {
player.dialogueInterpreter.open(PiousPeteDialogueFile(),npc)
}
}

View file

@ -318,6 +318,9 @@ class ServerConstants {
@JvmField @JvmField
var NEW_PLAYER_ANNOUNCEMENT = true var NEW_PLAYER_ANNOUNCEMENT = true
@JvmField
var INAUTHENTIC_CANDLELIGHT_RANDOM = false
@JvmField @JvmField
var HOLIDAY_EVENT_RANDOMS = true var HOLIDAY_EVENT_RANDOMS = true

View file

@ -160,6 +160,7 @@ object ServerConfigParser {
ServerConstants.GRAFANA_TTL_DAYS = data.getLong("integrations.grafana_log_ttl_days", 7L).toInt() ServerConstants.GRAFANA_TTL_DAYS = data.getLong("integrations.grafana_log_ttl_days", 7L).toInt()
ServerConstants.BETTER_DFS = data.getBoolean("world.better_dfs", true) ServerConstants.BETTER_DFS = data.getBoolean("world.better_dfs", true)
ServerConstants.NEW_PLAYER_ANNOUNCEMENT = data.getBoolean("world.new_player_announcement", true) ServerConstants.NEW_PLAYER_ANNOUNCEMENT = data.getBoolean("world.new_player_announcement", true)
ServerConstants.INAUTHENTIC_CANDLELIGHT_RANDOM = data.getBoolean("world.inauthentic_candlelight_random", false)
ServerConstants.HOLIDAY_EVENT_RANDOMS = data.getBoolean("world.holiday_event_randoms", true) ServerConstants.HOLIDAY_EVENT_RANDOMS = data.getBoolean("world.holiday_event_randoms", true)
ServerConstants.FORCE_HALLOWEEN_EVENTS = data.getBoolean("world.force_halloween_randoms", false) ServerConstants.FORCE_HALLOWEEN_EVENTS = data.getBoolean("world.force_halloween_randoms", false)
ServerConstants.FORCE_CHRISTMAS_EVENTS = data.getBoolean("world.force_christmas_randoms", false) ServerConstants.FORCE_CHRISTMAS_EVENTS = data.getBoolean("world.force_christmas_randoms", false)

View file

@ -99,6 +99,8 @@ better_agility_pyramid_gp = true
better_dfs = true better_dfs = true
#new player announcement #new player announcement
new_player_announcement = true new_player_announcement = true
#enables inauthentic candlelight random event (adds an additional normal random event)
inauthentic_candlelight_random = true
#enables holiday random events (no effect on normal random events) #enables holiday random events (no effect on normal random events)
holiday_event_randoms = true holiday_event_randoms = true
#force holiday randoms (can only force one at a time) #force holiday randoms (can only force one at a time)