Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
spawns = [
{ id = "pheasant_1_tail", x = 2596, y = 4772, direction = "SOUTH" },
{ id = "pheasant_1_tail_2", x = 2605, y = 4773, direction = "SOUTH" },
{ id = "pheasant_2_tails", x = 2598, y = 4780, direction = "SOUTH" },
{ id = "pheasant_2_tails_2", x = 2607, y = 4779, direction = "SOUTH" },
{ id = "pheasant_3_tails", x = 2595, y = 4777, direction = "SOUTH" },
{ id = "pheasant_3_tails_2", x = 2609, y = 4776, direction = "SOUTH" },
{ id = "pheasant_4_tails", x = 2601, y = 4783, direction = "SOUTH" },
{ id = "pheasant_4_tails_2", x = 2604, y = 4769, direction = "SOUTH" },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[freaky_forester_task]
format = "int"
persist = true
3 changes: 3 additions & 0 deletions data/activity/event/random/maze/maze.ifaces.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[maze_timer]
id = 209
type = "overlay"
47 changes: 47 additions & 0 deletions data/activity/event/random/maze/maze.objs.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[maze_wall]
id = 3626

# The cache has no swung-open wall variant; the opened ids reuse the same
# object which the door handler swings by rotation. Opened ids are defined
# first so map objects resolve to the closed state.
[maze_door_1_opened]
id = 3628

[maze_door_2_opened]
id = 3629

[maze_door_3_opened]
id = 3630

[maze_door_4_opened]
id = 3631

[maze_door_5_opened]
id = 3632

[maze_door_1_closed]
id = 3628

[maze_door_2_closed]
id = 3629

[maze_door_3_closed]
id = 3630

[maze_door_4_closed]
id = 3631

[maze_door_5_closed]
id = 3632

[maze_chest]
id = 3635
examine = "A chest, I wonder what's inside."

[maze_chest_opened]
id = 3636
examine = "An open chest."

[strange_shrine]
id = 3634
examine = "A strange shrine."
118 changes: 118 additions & 0 deletions data/activity/event/random/maze/maze.tables.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
[maze_rewards]
item = "item"
divisor = "int"

[.coins]
item = "coins"
divisor = 1

[.feather]
item = "feather"
divisor = 2

[.iron_arrow]
item = "iron_arrow"
divisor = 3

[.chaos_rune]
item = "chaos_rune"
divisor = 9

[.steel_arrow]
item = "steel_arrow"
divisor = 12

[.death_rune]
item = "death_rune"
divisor = 18

[.coal]
item = "coal"
divisor = 45

[.nature_rune]
item = "nature_rune"
divisor = 162

[.mithril_ore]
item = "mithril_ore"
divisor = 180

[maze_chest_rewards]
item = "item"
amount = "int"
text = "string"

[.air_rune]
item = "air_rune"
amount = 15
text = "You've found some air runes!"

[.water_rune]
item = "water_rune"
amount = 10
text = "You've found some water runes!"

[.earth_rune]
item = "earth_rune"
amount = 10
text = "You've found some earth runes!"

[.fire_rune]
item = "fire_rune"
amount = 10
text = "You've found some fire runes!"

[.bronze_arrow]
item = "bronze_arrow"
amount = 20
text = "You've found some bronze arrows!"

[.bronze_bolts]
item = "bronze_bolts"
amount = 10
text = "You've found some bronze bolts!"

[.iron_arrow]
item = "iron_arrow"
amount = 15
text = "You've found some iron arrows!"

[.attack_potion]
item = "attack_potion_2"
amount = 1
text = "You've found an attack potion!"

[.strength_potion]
item = "strength_potion_2"
amount = 1
text = "You've found a strength potion!"

[.defence_potion]
item = "defence_potion_2"
amount = 1
text = "You've found a defence potion!"

[maze_start_points]
tile = "tile"

[.south_east]
tile = { x = 2928, y = 4553 }

[.south_middle]
tile = { x = 2917, y = 4553 }

[.south_west]
tile = { x = 2908, y = 4555 }

[.west_south]
tile = { x = 2891, y = 4589 }

[.west_north]
tile = { x = 2891, y = 4595 }

[.north_middle]
tile = { x = 2926, y = 4597 }

[.north_east]
tile = { x = 2931, y = 4597 }
3 changes: 3 additions & 0 deletions data/activity/event/random/maze/maze.varps.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[maze_timer_bar]
id = 531
format = "int"
3 changes: 3 additions & 0 deletions data/activity/event/random/maze/maze.vars.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[maze_chests_opened]
format = "int"
persist = true
23 changes: 23 additions & 0 deletions data/activity/event/random/random_event.areas.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[random_event_exile_lumbridge]
x = [3221, 3223]
y = [3217, 3219]

[random_event_exile_varrock]
x = [3211, 3213]
y = [3422, 3424]

[random_event_exile_falador]
x = [2963, 2965]
y = [3377, 3379]

[random_event_exile_edgeville]
x = [3092, 3094]
y = [3493, 3495]

[random_event_exile_draynor]
x = [3092, 3094]
y = [3243, 3245]

[random_event_exile_al_kharid]
x = [3292, 3294]
y = [3183, 3185]
5 changes: 0 additions & 5 deletions data/activity/event/random/random_event.drops.toml

This file was deleted.

5 changes: 4 additions & 1 deletion data/activity/event/random/random_event.npcs.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[mysterious_old_man]
id = 410
examine = "An old man with an aura of magic."

[freaky_forester]
id = 2458
wander_range = 3
Expand All @@ -12,7 +16,6 @@ def = 3
style = "stab"
max_hit_melee = 10
respawn_delay = 5
drop_table = "pheasant"
examine = "A brightly coloured game bird."

[pheasant_1_tail_2]
Expand Down
45 changes: 45 additions & 0 deletions data/activity/event/random/random_event.tables.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[random_events]
event = "string"
weight = "int"

[.maze]
event = "maze"
weight = 10

[.freaky_forester]
event = "freaky_forester"
weight = 10

[random_event_settings]
value = "int"

# 1-in-N chance of an event per experience drop
[.roll_chance]
value = 300

[.min_cooldown_minutes]
value = 45

[.max_cooldown_minutes]
value = 90

[random_event_exiles]
area = "string"

[.lumbridge]
area = "random_event_exile_lumbridge"

[.varrock]
area = "random_event_exile_varrock"

[.falador]
area = "random_event_exile_falador"

[.edgeville]
area = "random_event_exile_edgeville"

[.draynor]
area = "random_event_exile_draynor"

[.al_kharid]
area = "random_event_exile_al_kharid"
11 changes: 11 additions & 0 deletions data/activity/event/random/random_event.vars.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[random_event]
format = "string"
persist = true

[random_event_origin]
format = "int"
persist = true

[random_event_cooldown]
format = "int"
persist = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[tutorial_island]
x = [3040, 3160]
y = [3040, 3136]
tags = ["no_random_events"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package content.activity.event.random

import world.gregs.voidps.engine.Script
import world.gregs.voidps.engine.entity.character.mode.Follow
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.npc.NPCs
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.timer.Timer
import world.gregs.voidps.type.random

/**
* Shared behaviour for in-place "nagging" random events (Certer, Sandwich Lady, Evil Twin...).
* The event NPC spawns next to the player, follows them, repeats nag lines, and applies the
* ignore penalty [RandomEvents.noteAndTeleport] once its lifetime runs out. Each event's own
* `npcOperate("Talk-to")` handler drives the puzzle and calls [endInPlaceEvent] when solved.
*/
class InPlaceRandomEvent : Script {

init {
npcTimerStart(NAG_TIMER) { 1 }
npcTimerTick(NAG_TIMER) { tick(this) }
}

private fun tick(npc: NPC): Int {
val owner = npc.owner
// Owner logged out or moved on to a different event: remove this orphaned NPC quietly.
// (The event can't be escaped by running - Follow keeps the NPC on the player - so the
// only exits are solving it or the ignore penalty below.)
if (owner == null || owner.get<String>("random_event") != npc.get<String>("random_event")) {
NPCs.remove(npc)
return Timer.CANCEL
}
if (!npc.watching(owner)) {
npc.watch(owner)
}
val remaining = npc.dec("random_event_life", refresh = false)
if (remaining <= 0) {
RandomEvents.noteAndTeleport(owner)
NPCs.remove(npc)
return Timer.CANCEL
}
val interval = npc.get("random_event_nag_interval", DEFAULT_INTERVAL)
if (remaining % interval == 0) {
npc.nag()
}
return Timer.CONTINUE
}

private fun NPC.nag() {
val lines: List<String> = get("random_event_nag_lines") ?: return
if (lines.isNotEmpty()) {
say(lines.random(random))
}
}

companion object {
const val NAG_TIMER = "random_event_nag"
private const val DEFAULT_INTERVAL = 25
}
}

/**
* Spawn an in-place random event NPC beside the player. It follows the player, nags every
* [nagInterval] ticks with a random line from [nagLines], and exiles the player via the ignore
* penalty after [lifetime] ticks. Returns the spawned NPC, or null if no walkable tile was found.
*/
fun Player.startInPlaceEvent(
id: String,
nagLines: List<String>,
lifetime: Int = 300,
nagInterval: Int = 25,
): NPC? {
val npc = NPCs.addRandom(id, tile.toCuboid(1), owner = this) ?: NPCs.add(id, tile, ticks = -1, owner = this)
npc["random_event"] = get<String>("random_event") ?: id
npc["random_event_life"] = lifetime
npc["random_event_nag_interval"] = nagInterval
npc["random_event_nag_lines"] = nagLines
npc.mode = Follow(npc, this)
npc.watch(this)
npc.softTimers.start(InPlaceRandomEvent.NAG_TIMER)
return npc
}

/**
* Stop an in-place event NPC's nag timer and remove it. The event's Talk-to handler calls this
* once the puzzle is solved (or dismissed); reward + [RandomEvents.complete] remain its job.
*/
fun endInPlaceEvent(npc: NPC) {
npc.softTimers.stop(InPlaceRandomEvent.NAG_TIMER)
NPCs.remove(npc)
}
Loading