Implemented Pillory random event (this event occurs while pick-pocketing)

This commit is contained in:
Oven Bread 2024-11-14 12:02:37 +00:00 committed by Ryan
parent 7a6adda997
commit 1a67932351
4 changed files with 272 additions and 30 deletions

View file

@ -9,6 +9,7 @@ import content.global.ame.events.evilbob.EvilBobNPC
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.pillory.PilloryNPC
import content.global.ame.events.rickturpentine.RickTurpentineNPC
import content.global.ame.events.rivertroll.RiverTrollRENPC
import content.global.ame.events.rockgolem.RockGolemRENPC
@ -52,6 +53,7 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
RICK_TURPENTINE(npc = RickTurpentineNPC(), loot = CERTER.loot),
SURPRISE_EXAM(npc = MysteriousOldManNPC(), type = "sexam"),
FREAKY_FORESTER(npc = FreakyForesterNPC(), skillIds = intArrayOf(Skills.WOODCUTTING)),
PILLORY(npc = PilloryNPC(), skillIds = intArrayOf(Skills.THIEVING)),
TREE_SPIRIT(npc = TreeSpiritRENPC(), skillIds = intArrayOf(Skills.WOODCUTTING)),
RIVER_TROLL(RiverTrollRENPC(), skillIds = intArrayOf(Skills.FISHING)),
ROCK_GOLEM(RockGolemRENPC(), skillIds = intArrayOf(Skills.MINING)),

View file

@ -0,0 +1,220 @@
package content.global.ame.events.pillory
import content.global.ame.RandomEvents
import core.api.*
import core.game.dialogue.FacialExpression
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.interaction.InterfaceListener
import core.game.interaction.QueueStrength
import core.game.node.entity.Entity
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.NPCs
import org.rs09.consts.Scenery
import org.rs09.consts.Sounds
/**
* Pillory Unlocking Interface PILLORY_189
*
* https://www.youtube.com/watch?v=caWn7pE2mkE
* https://www.youtube.com/watch?v=TMVR5cZZwZ0
* https://www.youtube.com/watch?v=Ym9LCDP-Q74
* https://www.youtube.com/watch?v=_vn0QZTtI6U (Failure)
* https://www.youtube.com/watch?v=zmXDikQIua4
*
* Child IDs
* 4 - Rotating Lock Model
* 5 6 7 - Swinging Keys Models
* 8 9 10 - Buttons for the Swinging Keys Models
* 11 12 13 14 15 16 - Padlocks at the Top
* 17 18 19 20 21 22 - Padlocks stars? Model 15272, Anim 4135
*
* Model IDs
* Using the amazeballs ::listifmodels
* 9749, 9750, 9751, 9752 - Swinging Keys Models
* 9753, 9754, 9755, 9756 - Rotating Lock Models
* 9757 9758 locked unlock
*/
class PilloryInterface : InterfaceListener, InteractionListener, MapArea {
companion object {
const val PILLORY_LOCK_INTERFACE = 189
const val PILLORY_ATRRIBUTE_RETURN_LOC = "/save:original-loc"
const val PILLORY_ATTRIBUTE_EVENT_KEYS = "pillory:event-keys"
const val PILLORY_ATTRIBUTE_EVENT_LOCK = "pillory:event-lock"
const val PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT = "/save:pillory:target-correct"
const val PILLORY_ATRRIBUTE_CORRECT_COUNTER = "/save:pillory:num-correct"
val LOCATIONS = arrayOf(
// Varrock Cages
Location(3226, 3407, 0),
Location(3228, 3407, 0),
Location(3230, 3407, 0),
// Seers Village Cages
Location(2681, 3489, 0),
Location(2683, 3489, 0),
Location(2685, 3489, 0),
// Yannile Cages
Location(2604, 3105, 0),
Location(2606, 3105, 0),
Location(2608, 3105, 0),
)
fun initPillory(player: Player) {
setAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT, 3)
setAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 0)
player.dialogueInterpreter.sendPlainMessage(true, "", "Solve the pillory puzzle to be returned to where you came from.")
}
fun randomPillory(player: Player) {
// Shuffle all 4 kinds of keys in, pick 3 for the keys, pick 1 from the 3 as the lock.
val keys = (0..3).toIntArray().let{ keys -> keys.shuffle(); return@let keys }
val lock = intArrayOf(keys[1], keys[2], keys[3]).random() // Last 3 as there are 4 keys. key[0] is fallback.
setAttribute(player, PILLORY_ATTRIBUTE_EVENT_KEYS, keys)
setAttribute(player, PILLORY_ATTRIBUTE_EVENT_LOCK, lock)
player.packetDispatch.sendModelOnInterface(9753 + lock, PILLORY_LOCK_INTERFACE, 4, 0)
player.packetDispatch.sendModelOnInterface(9749 + keys[1], PILLORY_LOCK_INTERFACE, 5, 0)
player.packetDispatch.sendModelOnInterface(9749 + keys[2], PILLORY_LOCK_INTERFACE, 6, 0)
player.packetDispatch.sendModelOnInterface(9749 + keys[3], PILLORY_LOCK_INTERFACE, 7, 0)
val numberToGetCorrect = getAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT, 3)
val correctCount = getAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 0)
for (i in 1.. 6) {
// Set if lock is red or green.
if (i <= correctCount) {
player.packetDispatch.sendModelOnInterface(9758, PILLORY_LOCK_INTERFACE, 10 + i, 0)
} else {
player.packetDispatch.sendModelOnInterface(9757, PILLORY_LOCK_INTERFACE, 10 + i, 0)
}
// Set if hide or show lock.
player.packetDispatch.sendInterfaceConfig(PILLORY_LOCK_INTERFACE, 10 + i, i > numberToGetCorrect)
}
}
fun selectedKey(player: Player, buttonID: Int) {
val keys = getAttribute(player, PILLORY_ATTRIBUTE_EVENT_KEYS, intArrayOf(0, 0, 0))
val lock = getAttribute(player, PILLORY_ATTRIBUTE_EVENT_LOCK, -1)
if (keys[buttonID] == lock) {
// CORRECT ANSWER
setAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, getAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 0) + 1)
if (getAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT, 3) <= getAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, -1)) {
player.dialogueInterpreter.sendPlainMessage(true, "", "You've escaped!")
sendMessage(player, "You've escaped!")
removeAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT)
removeAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER)
closeInterface(player)
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 -> {
val loot = RandomEvents.CERTER.loot!!.roll(player)[0]
addItemOrDrop(player, loot.id, loot.amount)
teleport(player, getAttribute(player, PILLORY_ATRRIBUTE_RETURN_LOC, Location.create(3222, 3218, 0)))
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
removeAttribute(player, PILLORY_ATRRIBUTE_RETURN_LOC)
closeInterface(player)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
return
}
randomPillory(player)
player.dialogueInterpreter.sendPlainMessage(
true,
"",
"Correct!",
"" + getAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 0) + " down, " +
(getAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT, 3) - getAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 0)) + " to go!")
// Animation for the star, but it doesn't work.
player.packetDispatch.sendInterfaceConfig(PILLORY_LOCK_INTERFACE, 16 + getAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 1), false)
sendAnimationOnInterface(player, 4135, PILLORY_LOCK_INTERFACE, 16 + getAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 1))
} else {
// WRONG ANSWER
player.dialogueInterpreter.close()
player.dialogueInterpreter.sendDialogues(NPCs.TRAMP_2794 , FacialExpression.OLD_ANGRY1, "Bah, that's not right.","Use the key that matches the hole", "in the spinning lock.")
if (getAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT, 0) < 6) {
setAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT, getAttribute(player, PILLORY_ATRRIBUTE_NEEDED_TO_GET_CORRECT, 0) + 1)
}
setAttribute(player, PILLORY_ATRRIBUTE_CORRECT_COUNTER, 0)
closeInterface(player)
}
}
}
override fun defineInterfaceListeners() {
on(PILLORY_LOCK_INTERFACE){ player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
8 -> selectedKey(player, 1)
9 -> selectedKey(player, 2)
10 -> selectedKey(player, 3)
}
return@on true
}
onOpen(PILLORY_LOCK_INTERFACE){ player, component ->
return@onOpen true
}
}
override fun defineListeners() {
on(Scenery.CAGE_6836, IntType.SCENERY, "unlock") { player, node ->
if (player.location in LOCATIONS) { // When you aren't inside.
randomPillory(player)
openInterface(player, PILLORY_LOCK_INTERFACE)
player.dialogueInterpreter.sendPlainMessage(true, "", "Pick the <col=8A0808>swinging key</col> that matches the", "hole in the <col=8A0808>spinning lock</col>.")
} else {
sendMessage(player, "You can't unlock the pillory, you'll let all the prisoners out!")
}
return@on true
}
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(
// Varrock Cages
ZoneBorders(3226, 3407, 3226, 3407),
ZoneBorders(3228, 3407, 3228, 3407),
ZoneBorders(3230, 3407, 3230, 3407),
// Seers Village Cages
ZoneBorders(2681, 3489, 2681, 3489),
ZoneBorders(2683, 3489, 2683, 3489),
ZoneBorders(2685, 3489, 2685, 3489),
// Yannile Cages
ZoneBorders(2604, 3105, 2604, 3105),
ZoneBorders(2606, 3105, 2606, 3105),
ZoneBorders(2608, 3105, 2608, 3105),
)
}
override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.TELEPORT)
}
override fun areaEnter(entity: Entity) {
if (entity is Player) {
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,50 @@
package content.global.ame.events.pillory
import content.global.ame.RandomEventNPC
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.system.timer.impl.AntiMacro
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] <lt>player name<gt> [-e <lt>event name<gt>]"
class PilloryNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PILLORY_GUARD_2791) {
override fun init() {
super.init()
sendChat("${player.username}, you're under arrest!")
face(player)
player.dialogueInterpreter.sendPlainMessage(true, "", "Solve the pillory puzzle to be returned to where you came from.")
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 -> {
if (getAttribute<Location?>(player, PilloryInterface.PILLORY_ATRRIBUTE_RETURN_LOC, null) == null) {
setAttribute(player, PilloryInterface.PILLORY_ATRRIBUTE_RETURN_LOC, player.location)
}
PilloryInterface.initPillory(player)
teleport(player, PilloryInterface.LOCATIONS.random()) // 9 random spots!
AntiMacro.terminateEventNpc(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
}
override fun talkTo(npc: NPC) {
//player.dialogueInterpreter.open(FreakyForesterDialogue(),npc)
}
}

View file

@ -1,30 +0,0 @@
package content.region.kandarin.seers.handlers;
import core.cache.def.impl.SceneryDefinition;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used to unlock the sheers cage.
* @author 'Vexia
* @versio 1.0
*/
@Initializable
public final class SeersCageUnlockPlugin extends OptionHandler {
@Override
public boolean handle(Player player, Node node, String option) {
player.getPacketDispatch().sendMessage("You can't unlock the pillory, you'll let all the prisoners out!");
return true;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(6836).getHandlers().put("option:unlock", this);
return this;
}
}