From c0c38f57954bdd658baaadeb4d4199f75f813d9b Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 10:54:12 +0100 Subject: [PATCH 01/14] Add mort myre snail combat --- .../mort_myre_swamp.anims.toml | 8 +++++++ .../mort_myre_swamp.combat.toml | 14 ++++++++++++ .../mort_myre_swamp/mort_myre_swamp.npcs.toml | 22 ++++++++----------- .../mort_myre_swamp.sounds.toml | 9 ++++++++ 4 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml create mode 100644 data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml create mode 100644 data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml new file mode 100644 index 0000000000..1a454783e7 --- /dev/null +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml @@ -0,0 +1,8 @@ +[snail_defend] +id = 1278 + +[snail_attack] +id = 1277 + +[snail_death] +id = 1279 diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml new file mode 100644 index 0000000000..26f92d5ef1 --- /dev/null +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml @@ -0,0 +1,14 @@ +[snail] +attack_speed = 4 +retreat_range = 8 +defend_anim = "snail_defend" +defend_sound = "snail_defend" +death_anim = "snail_death" +death_sound = "snail_death" + +[snail.range] +range = 4 +anim = "snail_attack" +projectile = "curse" +target_sound = {id = "snail_spit", radius = 10 } +target_hit = { offense = "range", max = 20 } diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml index ab9531ee74..a14a94063b 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml @@ -1,6 +1,7 @@ [ghast_mort_myre_swamp] id = 1052 categories = ["ghosts"] +hunt_mode = "spotted" examine = "Arrghhh... A Ghast." [ghast_level_30] @@ -68,8 +69,7 @@ att = 0 str = 0 def = 22 range = 5 -style = "range" -max_hit_melee = 20 +combat_def = "snail" attack_bonus = 10 hunt_mode = "cowardly" respawn_delay = 50 @@ -81,9 +81,8 @@ id = 1228 hitpoints = 130 def = 45 range = 12 +combat_def = "snail" attack_speed = 6 -style = "range" -max_hit_melee = 20 attack_bonus = 10 hunt_mode = "cowardly" respawn_delay = 50 @@ -97,9 +96,8 @@ att = 0 str = 0 def = 18 range = 7 +combat_def = "snail" attack_speed = 6 -style = "range" -max_hit_range = 20 attack_bonus = 10 hunt_mode = "cowardly" respawn_delay = 50 @@ -112,9 +110,8 @@ att = 0 str = 0 def = 40 range = 15 +combat_def = "snail" attack_speed = 6 -style = "range" -max_hit_range = 20 attack_bonus = 10 hunt_mode = "cowardly" respawn_delay = 50 @@ -126,9 +123,8 @@ id = 1231 hitpoints = 220 def = 20 range = 10 +combat_def = "snail" attack_speed = 6 -style = "range" -max_hit_range = 20 attack_bonus = 10 hunt_mode = "cowardly" respawn_delay = 50 @@ -137,7 +133,7 @@ examine = "A branch bark coloured blamish snail, these types are said to spit ac [myre_blamish_snail_2] id = 1232 -examine = "A marsh coloured blamish snail, these types are said to spit acid." +clone = "myre_blamish_snail" [blood_blamish_snail_2] id = 1233 @@ -145,11 +141,11 @@ clone = "blood_blamish_snail" [ochre_blamish_snail_2] id = 1234 -examine = "A muddy coloured blamish snail, these types are said to spit acid." +clone = "ochre_blamish_snail" [bruise_blamish_snail_2] id = 1235 -examine = "A bruise blue coloured blamish snail, these types are said to spit acid." +clone = "bruise_blamish_snail" [fishing_spot_mort_myre_swamp] id = 1236 diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml new file mode 100644 index 0000000000..c4aa39b998 --- /dev/null +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml @@ -0,0 +1,9 @@ +[snail_defend] +id = 789 + +[snail_spit] +id = 790 +radius = 10 + +[snail_death] +id = 787 From 96eab92176498cc0df41378a351c9fbbeb78e9c4 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 10:58:21 +0100 Subject: [PATCH 02/14] Add mort ton afflicted --- .../mort_myre_swamp.sounds.toml | 1 - .../morytania/mort_ton/mort_ton.combat.toml | 13 ++++++++++ .../morytania/mort_ton/mort_ton.npcs.toml | 26 ++++--------------- .../area/morytania/mort_ton/Afflicted.kt | 21 +++++++++++++++ 4 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 data/area/morytania/mort_ton/mort_ton.combat.toml create mode 100644 game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml index c4aa39b998..9180815a18 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml @@ -3,7 +3,6 @@ id = 789 [snail_spit] id = 790 -radius = 10 [snail_death] id = 787 diff --git a/data/area/morytania/mort_ton/mort_ton.combat.toml b/data/area/morytania/mort_ton/mort_ton.combat.toml new file mode 100644 index 0000000000..dfdf15c7be --- /dev/null +++ b/data/area/morytania/mort_ton/mort_ton.combat.toml @@ -0,0 +1,13 @@ +[afflicted] +attack_speed = 5 +retreat_range = 12 +defend_anim = "unarmed_defend" +defend_sound = "zombie_defend" +death_anim = "human_death" +death_sound = "zombie_death" + +[afflicted.melee] +range = 1 +anim = "unarmed_punch" +target_sound = "zombie_attack" +target_hit = { offense = "crush", max = 40 } diff --git a/data/area/morytania/mort_ton/mort_ton.npcs.toml b/data/area/morytania/mort_ton/mort_ton.npcs.toml index 51c44d2cd1..6ff6ac5cb4 100644 --- a/data/area/morytania/mort_ton/mort_ton.npcs.toml +++ b/data/area/morytania/mort_ton/mort_ton.npcs.toml @@ -35,8 +35,7 @@ hitpoints = 300 att = 30 str = 30 def = 40 -style = "crush" -max_hit_melee = 40 +combat_def = "afflicted" hunt_mode = "cowardly" respawn_delay = 25 drop_table = "afflicted" @@ -44,42 +43,27 @@ examine = "A local villager of Mort'ton." [afflicted_2] id = 1258 +clone = "afflicted" hitpoints = 280 att = 28 str = 28 def = 38 -style = "crush" -max_hit_melee = 40 -hunt_mode = "cowardly" -respawn_delay = 25 -drop_table = "afflicted" -examine = "A local villager of Mort'ton." [afflicted_3] id = 1261 +clone = "afflicted" hitpoints = 260 att = 26 str = 26 -def = 36 -style = "crush" -max_hit_melee = 40 -hunt_mode = "cowardly" -respawn_delay = 25 -drop_table = "afflicted" -examine = "A local villager of Mort'ton." [afflicted_4] id = 1262 +clone = "afflicted" hitpoints = 240 att = 24 str = 24 def = 34 -style = "crush" -max_hit_melee = 30 -hunt_mode = "cowardly" -respawn_delay = 25 -drop_table = "afflicted" -examine = "A local villager of Mort'ton." +max_hit_crush = 30 [ulsquire_shauncy] id = 7898 diff --git a/game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt b/game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt new file mode 100644 index 0000000000..b3bccf34cd --- /dev/null +++ b/game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt @@ -0,0 +1,21 @@ +package content.area.morytania.mort_ton + +import content.entity.player.dialogue.Shock +import content.entity.player.dialogue.type.npc +import world.gregs.voidps.engine.Script +import world.gregs.voidps.type.random + +class Afflicted : Script { + init { + npcOperate("Talk-to", "afflicted*") { + val words = setOf("ughugh", "knows'is", "nots", "pirsl", "wot's", "zurgle", "gurghl", "mee's", "seysyi", "sfriess", "says") + npc(buildString { + repeat(random.nextInt(1, 7)) { + append(words.random()) + append(" ") + } + }) + npc("~ This person doesn't make any sense at all. ~") + } + } +} From 987701a5ec9276e2b438c3516809269cb3359135 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 11:08:08 +0100 Subject: [PATCH 03/14] Add mort'ton loar shades --- .../morytania/mort_ton/mort_ton.anims.toml | 11 +++++++ .../morytania/mort_ton/mort_ton.combat.toml | 16 +++++++++- .../morytania/mort_ton/mort_ton.npcs.toml | 16 ++-------- .../morytania/mort_ton/mort_ton.sounds.toml | 11 +++++++ .../npc/monster/undead/shade/shade.anims.toml | 6 ++-- .../monster/undead/shade/shade.combat.toml | 16 +++++----- .../npc/monster/undead/shade/shade.npcs.toml | 2 +- .../monster/undead/shade/shade.sounds.toml | 6 ++-- data/skill/slayer/master/mazchna.tables.toml | 8 ++--- data/skill/slayer/master/vannaka.tables.toml | 8 ++--- .../content/area/morytania/mort_ton/Shades.kt | 30 +++++++++++++++++++ 11 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 data/area/morytania/mort_ton/mort_ton.anims.toml create mode 100644 data/area/morytania/mort_ton/mort_ton.sounds.toml create mode 100644 game/src/main/kotlin/content/area/morytania/mort_ton/Shades.kt diff --git a/data/area/morytania/mort_ton/mort_ton.anims.toml b/data/area/morytania/mort_ton/mort_ton.anims.toml new file mode 100644 index 0000000000..8b1d98e645 --- /dev/null +++ b/data/area/morytania/mort_ton/mort_ton.anims.toml @@ -0,0 +1,11 @@ +[shade_attack] +id = 1283 + +[shade_defend] +id = 1286 + +[shade_death] +id = 1287 + +[shade_rise] +id = 1288 \ No newline at end of file diff --git a/data/area/morytania/mort_ton/mort_ton.combat.toml b/data/area/morytania/mort_ton/mort_ton.combat.toml index dfdf15c7be..4b2cb8ab70 100644 --- a/data/area/morytania/mort_ton/mort_ton.combat.toml +++ b/data/area/morytania/mort_ton/mort_ton.combat.toml @@ -1,6 +1,6 @@ [afflicted] attack_speed = 5 -retreat_range = 12 +retreat_range = 8 defend_anim = "unarmed_defend" defend_sound = "zombie_defend" death_anim = "human_death" @@ -11,3 +11,17 @@ range = 1 anim = "unarmed_punch" target_sound = "zombie_attack" target_hit = { offense = "crush", max = 40 } + +[shade] +attack_speed = 4 +retreat_range = 8 +defend_anim = "shade_defend" +defend_sound = "shade_defend" +death_anim = "shade_death" +death_sound = "shade_death" + +[shade.melee] +range = 1 +anim = "shade_attack" +target_sound = "shade_attack" +target_hit = { offense = "crush", max = 40 } diff --git a/data/area/morytania/mort_ton/mort_ton.npcs.toml b/data/area/morytania/mort_ton/mort_ton.npcs.toml index 6ff6ac5cb4..afe059eb67 100644 --- a/data/area/morytania/mort_ton/mort_ton.npcs.toml +++ b/data/area/morytania/mort_ton/mort_ton.npcs.toml @@ -4,29 +4,19 @@ hitpoints = 380 att = 45 str = 30 def = 26 -style = "crush" -max_hit_melee = 40 hunt_mode = "cowardly" slayer_xp = 38.0 categories = ["shades"] immune_poison = true respawn_delay = 35 +drop_table = "loar_shade" examine = "A shadowy sort of entity, kind of creepy looking." -[loar_shade_shade] +[loar_shade] id = 1241 -hitpoints = 380 -att = 45 -str = 30 -def = 26 -style = "crush" -max_hit_melee = 40 +combat_def = "shade" hunt_mode = "cowardly" -slayer_xp = 38.0 -categories = ["shades"] immune_poison = true -respawn_delay = 35 -drop_table = "loar_shade" examine = "The shadowy remains of a long departed soul." [afflicted] diff --git a/data/area/morytania/mort_ton/mort_ton.sounds.toml b/data/area/morytania/mort_ton/mort_ton.sounds.toml new file mode 100644 index 0000000000..c6e54dff9d --- /dev/null +++ b/data/area/morytania/mort_ton/mort_ton.sounds.toml @@ -0,0 +1,11 @@ +[shade_appear] +id = 744 + +[shade_defend] +id = 747 + +[shade_attack] +id = 745 + +[shade_death] +id = 746 \ No newline at end of file diff --git a/data/entity/npc/monster/undead/shade/shade.anims.toml b/data/entity/npc/monster/undead/shade/shade.anims.toml index c04ac7d31f..dac85fc10f 100644 --- a/data/entity/npc/monster/undead/shade/shade.anims.toml +++ b/data/entity/npc/monster/undead/shade/shade.anims.toml @@ -1,8 +1,8 @@ -[shade_attack] +[stronghold_shade_attack] id = 391 -[shade_defend] +[stronghold_shade_defend] id = 389 -[shade_death] +[stronghold_shade_death] id = 843 diff --git a/data/entity/npc/monster/undead/shade/shade.combat.toml b/data/entity/npc/monster/undead/shade/shade.combat.toml index 52338f034f..be92c53131 100644 --- a/data/entity/npc/monster/undead/shade/shade.combat.toml +++ b/data/entity/npc/monster/undead/shade/shade.combat.toml @@ -1,13 +1,13 @@ -[shade] +[stronghold_shade] attack_speed = 4 retreat_range = 11 -defend_anim = "shade_defend" -defend_sound = "shade_defend" -death_anim = "shade_death" -death_sound = "shade_death" +defend_anim = "stronghold_shade_defend" +defend_sound = "stronghold_shade_defend" +death_anim = "stronghold_shade_death" +death_sound = "stronghold_shade_death" -[shade.melee] +[stronghold_shade.melee] range = 1 -anim = "shade_attack" -target_sound = "shade_attack" +anim = "stronghold_shade_attack" +target_sound = "stronghold_shade_attack" target_hit = { offense = "crush", max = 127 } diff --git a/data/entity/npc/monster/undead/shade/shade.npcs.toml b/data/entity/npc/monster/undead/shade/shade.npcs.toml index 883d3ad2ac..6846522349 100644 --- a/data/entity/npc/monster/undead/shade/shade.npcs.toml +++ b/data/entity/npc/monster/undead/shade/shade.npcs.toml @@ -5,7 +5,7 @@ hitpoints = 700 att = 64 str = 47 def = 42 -combat_def = "shade" +combat_def = "stronghold_shade" respawn_delay = 40 slayer_xp = 3.5 wander_range = 9 diff --git a/data/entity/npc/monster/undead/shade/shade.sounds.toml b/data/entity/npc/monster/undead/shade/shade.sounds.toml index 459baeac5d..3e4afe68b2 100644 --- a/data/entity/npc/monster/undead/shade/shade.sounds.toml +++ b/data/entity/npc/monster/undead/shade/shade.sounds.toml @@ -1,8 +1,8 @@ -[shade_defend] +[stronghold_shade_defend] id = 439 -[shade_attack] +[stronghold_shade_attack] id = 2548 -[shade_death] +[stronghold_shade_death] id = 438 diff --git a/data/skill/slayer/master/mazchna.tables.toml b/data/skill/slayer/master/mazchna.tables.toml index 84ace77aed..6958bec3f3 100644 --- a/data/skill/slayer/master/mazchna.tables.toml +++ b/data/skill/slayer/master/mazchna.tables.toml @@ -123,10 +123,10 @@ amount = [30, 50] weight = 7 tip = "Scorpions are almost always poisonous, their hard carapace makes them resistant to crushing and stabbing attacks." -#[.shades] -#amount = [30, 70] -#weight = 8 -#tip = "Shades are undead - The town of Mort'ton in Morytania is plagued by these creatures, so help if you can. There are some shades in the Stronghold of Security too, but you won't learn much from fighting those; stick to Mort'ton." +[.shades] +amount = [30, 70] +weight = 8 +tip = "Shades are undead - The town of Mort'ton in Morytania is plagued by these creatures, so help if you can. There are some shades in the Stronghold of Security too, but you won't learn much from fighting those; stick to Mort'ton." [.skeletons] amount = [30, 50] diff --git a/data/skill/slayer/master/vannaka.tables.toml b/data/skill/slayer/master/vannaka.tables.toml index 572eebfffb..ed6cdf693c 100644 --- a/data/skill/slayer/master/vannaka.tables.toml +++ b/data/skill/slayer/master/vannaka.tables.toml @@ -183,10 +183,10 @@ tip = "Pyrefiends are beings of fire and molten rock, they're quick and agile bu #weight = 6 #tip = "Sea Snakes are long and slithery with a venomous bite. The larger ones are more poisonous, so keep an eye on your health." -#[.shades] -#amount = [40, 90] -#weight = 8 -#tip = "Shades are undead so magic is your best bet against them. You can find Shades at Mort'ton." +[.shades] +amount = [40, 90] +weight = 8 +tip = "Shades are undead so magic is your best bet against them. You can find Shades at Mort'ton." [.shadow_warriors] amount = [30, 80] diff --git a/game/src/main/kotlin/content/area/morytania/mort_ton/Shades.kt b/game/src/main/kotlin/content/area/morytania/mort_ton/Shades.kt new file mode 100644 index 0000000000..9e413aa874 --- /dev/null +++ b/game/src/main/kotlin/content/area/morytania/mort_ton/Shades.kt @@ -0,0 +1,30 @@ +package content.area.morytania.mort_ton + +import content.entity.effect.transform +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.instruction.handle.interactPlayer +import world.gregs.voidps.engine.entity.character.areaSound +import world.gregs.voidps.engine.entity.character.mode.EmptyMode +import world.gregs.voidps.engine.entity.character.mode.PauseMode +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.queue.softQueue + +class Shades : Script { + init { + npcCombatDamage("loar_shadow") { (source) -> + if (transform != "") { + return@npcCombatDamage + } + anim("shade_rise") + areaSound("shade_appear", tile, radius = 10) + source.mode = EmptyMode + mode = PauseMode + transform(id.replace("_shadow", "_shade")) + softQueue("shade_transform", 1) { + if (source is Player) { + interactPlayer(source, "Attack") + } + } + } + } +} From 8fc7fca1d9013e363c7133450331981b831a8e00 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 11:47:00 +0100 Subject: [PATCH 04/14] Add mort myre swamp ghasts and swamp decay --- .../mort_myre_swamp.anims.toml | 3 + .../mort_myre_swamp.areas.toml | 4 + .../mort_myre_swamp.combat.toml | 47 ++- .../mort_myre_swamp/mort_myre_swamp.gfx.toml | 3 + .../mort_myre_swamp.npc-spawns.toml | 358 +++++++++--------- .../mort_myre_swamp/mort_myre_swamp.npcs.toml | 4 +- .../mort_myre_swamp.sounds.toml | 6 + .../area/morytania/mort_myre_swamp/Ghast.kt | 62 +++ .../morytania/mort_myre_swamp/SwampDecay.kt | 55 +++ .../content/entity/npc/combat/Attack.kt | 2 +- 10 files changed, 361 insertions(+), 183 deletions(-) create mode 100644 data/area/morytania/mort_myre_swamp/mort_myre_swamp.gfx.toml create mode 100644 game/src/main/kotlin/content/area/morytania/mort_myre_swamp/Ghast.kt create mode 100644 game/src/main/kotlin/content/area/morytania/mort_myre_swamp/SwampDecay.kt diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml index 1a454783e7..a515bce24c 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.anims.toml @@ -6,3 +6,6 @@ id = 1277 [snail_death] id = 1279 + +[ghast_attack] +id = 1093 diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.areas.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.areas.toml index bc83b52010..4645dd96dd 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.areas.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.areas.toml @@ -9,3 +9,7 @@ y = [3407, 3417] [mort_myre_swamp_south_fishing_spot] x = [3437, 3445] y = [3270, 3280] + +[mort_myre_swamp] +x = [3392, 3519] +y = [3329, 3454] diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml index 26f92d5ef1..90560e5124 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.combat.toml @@ -10,5 +10,50 @@ death_sound = "snail_death" range = 4 anim = "snail_attack" projectile = "curse" -target_sound = {id = "snail_spit", radius = 10 } +target_sound = { id = "snail_spit", radius = 10 } target_hit = { offense = "range", max = 20 } + +[ghast] +attack_speed = 20 +retreat_range = 8 +defend_anim = "ghast_defend" +defend_sound = "ghast_defend" +death_anim = "ghast_death" +death_sound = "ghast_death" + +[ghast.skip] +chance = 10 +range = 1 + +[ghast.miss] +chance = 7 +range = 1 +say = "OOooooohhh" +anim = "ghast_attack" +target_sound = "ghast_attack" +impact_regardless = true +impact_message = "An attacking Ghast just misses you." + +[ghast.rot] +condition = "has_food" +chance = 3 +range = 1 +anim = "ghast_attack" +say = "Oouuaarrr!" +target_sounds = [ + { id = "ghast_attack" }, + { id = "food_rot" }, +] +impact_regardless = true +impact_message = "You feel something attacking your backpack, and smell a terrible stench." + +[ghast.energy] +condition = "has_no_food" +chance = 3 +range = 1 +anim = "ghast_attack" +say = "OOooooohhh" +target_sound = "ghast_attack" +impact_regardless = true +target_hit = { offense = "damage", min = 10, max = 20, accuracy_roll = false } +impact_message = "A supernatural force draws energy from you." diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.gfx.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.gfx.toml new file mode 100644 index 0000000000..cbc4ef1a32 --- /dev/null +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.gfx.toml @@ -0,0 +1,3 @@ +[swamp_decay] +id = 267 +height = 10 diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npc-spawns.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npc-spawns.toml index d3acc51d08..6065a12878 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npc-spawns.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npc-spawns.toml @@ -1,180 +1,180 @@ spawns = [ # 13619 { id = "bill_blakey", x = 3424, y = 3320, direction = "EAST", members = true }, - { id = "ghast_mort_myre_swamp", x = 3401, y = 3361, members = true }, - { id = "ghast_mort_myre_swamp", x = 3404, y = 3371, members = true }, - { id = "ghast_mort_myre_swamp", x = 3406, y = 3354, members = true }, - { id = "ghast_mort_myre_swamp", x = 3407, y = 3379, members = true }, - { id = "ghast_mort_myre_swamp", x = 3408, y = 3386, members = true }, - { id = "ghast_mort_myre_swamp", x = 3411, y = 3380, members = true }, - { id = "ghast_mort_myre_swamp", x = 3412, y = 3357, members = true }, - { id = "ghast_mort_myre_swamp", x = 3414, y = 3365, members = true }, - { id = "ghast_mort_myre_swamp", x = 3415, y = 3372, members = true }, - { id = "ghast_mort_myre_swamp", x = 3415, y = 3390, members = true }, - { id = "ghast_mort_myre_swamp", x = 3416, y = 3345, members = true }, - { id = "ghast_mort_myre_swamp", x = 3417, y = 3337, members = true }, - { id = "ghast_mort_myre_swamp", x = 3417, y = 3385, members = true }, - { id = "ghast_mort_myre_swamp", x = 3418, y = 3356, members = true }, - { id = "ghast_mort_myre_swamp", x = 3419, y = 3361, members = true }, - { id = "ghast_mort_myre_swamp", x = 3420, y = 3333, members = true }, - { id = "ghast_mort_myre_swamp", x = 3423, y = 3348, members = true }, - { id = "ghast_mort_myre_swamp", x = 3424, y = 3337, members = true }, - { id = "ghast_mort_myre_swamp", x = 3426, y = 3366, members = true }, - { id = "ghast_mort_myre_swamp", x = 3427, y = 3379, members = true }, - { id = "ghast_mort_myre_swamp", x = 3427, y = 3389, members = true }, - { id = "ghast_mort_myre_swamp", x = 3429, y = 3330, members = true }, - { id = "ghast_mort_myre_swamp", x = 3429, y = 3352, members = true }, - { id = "ghast_mort_myre_swamp", x = 3430, y = 3344, members = true }, - { id = "ghast_mort_myre_swamp", x = 3431, y = 3366, members = true }, - { id = "ghast_mort_myre_swamp", x = 3436, y = 3389, members = true }, - { id = "ghast_mort_myre_swamp", x = 3441, y = 3364, members = true }, - { id = "ghast_mort_myre_swamp", x = 3443, y = 3383, members = true }, - { id = "ghast_mort_myre_swamp", x = 3447, y = 3391, members = true }, - { id = "ghast_mort_myre_swamp", x = 3449, y = 3345, members = true }, - { id = "ghast_mort_myre_swamp", x = 3453, y = 3357, members = true }, - { id = "ghast_mort_myre_swamp", x = 3453, y = 3386, members = true }, - { id = "ghast_mort_myre_swamp", x = 3454, y = 3346, members = true }, - { id = "ghast_mort_myre_swamp", x = 3454, y = 3369, members = true }, - { id = "ghast_mort_myre_swamp", x = 3410, y = 3398, members = true }, - { id = "ghast_mort_myre_swamp", x = 3413, y = 3423, members = true }, - { id = "ghast_mort_myre_swamp", x = 3413, y = 3443, members = true }, - { id = "ghast_mort_myre_swamp", x = 3414, y = 3418, members = true }, - { id = "ghast_mort_myre_swamp", x = 3415, y = 3407, members = true }, - { id = "ghast_mort_myre_swamp", x = 3415, y = 3432, members = true }, - { id = "ghast_mort_myre_swamp", x = 3419, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3419, y = 3413, members = true }, - { id = "ghast_mort_myre_swamp", x = 3420, y = 3425, members = true }, - { id = "ghast_mort_myre_swamp", x = 3420, y = 3435, members = true }, - { id = "ghast_mort_myre_swamp", x = 3420, y = 3440, members = true }, - { id = "ghast_mort_myre_swamp", x = 3422, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3424, y = 3403, members = true }, - { id = "ghast_mort_myre_swamp", x = 3425, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3426, y = 3419, members = true }, - { id = "ghast_mort_myre_swamp", x = 3427, y = 3431, members = true }, - { id = "ghast_mort_myre_swamp", x = 3428, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3428, y = 3445, members = true }, - { id = "ghast_mort_myre_swamp", x = 3429, y = 3436, members = true }, - { id = "ghast_mort_myre_swamp", x = 3432, y = 3419, members = true }, - { id = "ghast_mort_myre_swamp", x = 3432, y = 3445, members = true }, - { id = "ghast_mort_myre_swamp", x = 3437, y = 3401, members = true }, - { id = "ghast_mort_myre_swamp", x = 3437, y = 3435, members = true }, - { id = "ghast_mort_myre_swamp", x = 3441, y = 3415, members = true }, - { id = "ghast_mort_myre_swamp", x = 3441, y = 3428, members = true }, - { id = "ghast_mort_myre_swamp", x = 3442, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3443, y = 3432, members = true }, - { id = "ghast_mort_myre_swamp", x = 3444, y = 3406, members = true }, - { id = "ghast_mort_myre_swamp", x = 3445, y = 3394, members = true }, - { id = "ghast_mort_myre_swamp", x = 3448, y = 3393, members = true }, - { id = "ghast_mort_myre_swamp", x = 3450, y = 3423, members = true }, - { id = "ghast_mort_myre_swamp", x = 3450, y = 3430, members = true }, - { id = "ghast_mort_myre_swamp", x = 3451, y = 3396, members = true }, - { id = "ghast_mort_myre_swamp", x = 3453, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3453, y = 3436, members = true }, - { id = "ghast_mort_myre_swamp", x = 3454, y = 3414, members = true }, - { id = "ghast_mort_myre_swamp", x = 3456, y = 3343, members = true }, - { id = "ghast_mort_myre_swamp", x = 3456, y = 3366, members = true }, - { id = "ghast_mort_myre_swamp", x = 3456, y = 3390, members = true }, - { id = "ghast_mort_myre_swamp", x = 3457, y = 3351, members = true }, - { id = "ghast_mort_myre_swamp", x = 3457, y = 3356, members = true }, - { id = "ghast_mort_myre_swamp", x = 3457, y = 3370, members = true }, - { id = "ghast_mort_myre_swamp", x = 3457, y = 3378, members = true }, - { id = "ghast_mort_myre_swamp", x = 3458, y = 3340, members = true }, - { id = "ghast_mort_myre_swamp", x = 3460, y = 3375, members = true }, - { id = "ghast_mort_myre_swamp", x = 3463, y = 3336, members = true }, - { id = "ghast_mort_myre_swamp", x = 3463, y = 3341, members = true }, - { id = "ghast_mort_myre_swamp", x = 3463, y = 3353, members = true }, - { id = "ghast_mort_myre_swamp", x = 3464, y = 3372, members = true }, - { id = "ghast_mort_myre_swamp", x = 3464, y = 3380, members = true }, - { id = "ghast_mort_myre_swamp", x = 3465, y = 3359, members = true }, - { id = "ghast_mort_myre_swamp", x = 3466, y = 3332, members = true }, - { id = "ghast_mort_myre_swamp", x = 3467, y = 3380, members = true }, - { id = "ghast_mort_myre_swamp", x = 3468, y = 3348, members = true }, - { id = "ghast_mort_myre_swamp", x = 3469, y = 3368, members = true }, - { id = "ghast_mort_myre_swamp", x = 3469, y = 3390, members = true }, - { id = "ghast_mort_myre_swamp", x = 3470, y = 3381, members = true }, - { id = "ghast_mort_myre_swamp", x = 3472, y = 3362, members = true }, - { id = "ghast_mort_myre_swamp", x = 3473, y = 3352, members = true }, - { id = "ghast_mort_myre_swamp", x = 3474, y = 3380, members = true }, - { id = "ghast_mort_myre_swamp", x = 3474, y = 3387, members = true }, - { id = "ghast_mort_myre_swamp", x = 3475, y = 3373, members = true }, - { id = "ghast_mort_myre_swamp", x = 3477, y = 3354, members = true }, - { id = "ghast_mort_myre_swamp", x = 3478, y = 3328, members = true }, - { id = "ghast_mort_myre_swamp", x = 3482, y = 3343, members = true }, - { id = "ghast_mort_myre_swamp", x = 3485, y = 3373, members = true }, - { id = "ghast_mort_myre_swamp", x = 3486, y = 3329, members = true }, - { id = "ghast_mort_myre_swamp", x = 3486, y = 3380, members = true }, - { id = "ghast_mort_myre_swamp", x = 3487, y = 3368, members = true }, - { id = "ghast_mort_myre_swamp", x = 3488, y = 3343, members = true }, - { id = "ghast_mort_myre_swamp", x = 3488, y = 3350, members = true }, - { id = "ghast_mort_myre_swamp", x = 3488, y = 3357, members = true }, - { id = "ghast_mort_myre_swamp", x = 3491, y = 3376, members = true }, - { id = "ghast_mort_myre_swamp", x = 3491, y = 3381, members = true }, - { id = "ghast_mort_myre_swamp", x = 3491, y = 3388, members = true }, - { id = "ghast_mort_myre_swamp", x = 3492, y = 3360, members = true }, - { id = "ghast_mort_myre_swamp", x = 3492, y = 3371, members = true }, - { id = "ghast_mort_myre_swamp", x = 3494, y = 3328, members = true }, - { id = "ghast_mort_myre_swamp", x = 3494, y = 3341, members = true }, - { id = "ghast_mort_myre_swamp", x = 3498, y = 3354, members = true }, - { id = "ghast_mort_myre_swamp", x = 3500, y = 3385, members = true }, - { id = "ghast_mort_myre_swamp", x = 3501, y = 3388, members = true }, - { id = "ghast_mort_myre_swamp", x = 3502, y = 3328, members = true }, - { id = "ghast_mort_myre_swamp", x = 3502, y = 3350, members = true }, - { id = "ghast_mort_myre_swamp", x = 3502, y = 3363, members = true }, - { id = "ghast_mort_myre_swamp", x = 3503, y = 3359, members = true }, - { id = "ghast_mort_myre_swamp", x = 3505, y = 3379, members = true }, - { id = "ghast_mort_myre_swamp", x = 3507, y = 3348, members = true }, - { id = "ghast_mort_myre_swamp", x = 3508, y = 3367, members = true }, - { id = "ghast_mort_myre_swamp", x = 3510, y = 3341, members = true }, - { id = "ghast_mort_myre_swamp", x = 3510, y = 3381, members = true }, - { id = "ghast_mort_myre_swamp", x = 3512, y = 3328, members = true }, - { id = "ghast_mort_myre_swamp", x = 3513, y = 3383, members = true }, - { id = "ghast_mort_myre_swamp", x = 3517, y = 3329, members = true }, - { id = "ghast_mort_myre_swamp", x = 3517, y = 3336, members = true }, - { id = "ghast_mort_myre_swamp", x = 3457, y = 3411, members = true }, - { id = "ghast_mort_myre_swamp", x = 3458, y = 3401, members = true }, - { id = "ghast_mort_myre_swamp", x = 3461, y = 3406, members = true }, - { id = "ghast_mort_myre_swamp", x = 3462, y = 3399, members = true }, - { id = "ghast_mort_myre_swamp", x = 3463, y = 3416, members = true }, - { id = "ghast_mort_myre_swamp", x = 3463, y = 3448, members = true }, - { id = "ghast_mort_myre_swamp", x = 3464, y = 3441, members = true }, - { id = "ghast_mort_myre_swamp", x = 3467, y = 3415, members = true }, - { id = "ghast_mort_myre_swamp", x = 3469, y = 3397, members = true }, - { id = "ghast_mort_myre_swamp", x = 3473, y = 3394, members = true }, - { id = "ghast_mort_myre_swamp", x = 3473, y = 3412, members = true }, - { id = "ghast_mort_myre_swamp", x = 3475, y = 3401, members = true }, - { id = "ghast_mort_myre_swamp", x = 3481, y = 3406, members = true }, - { id = "ghast_mort_myre_swamp", x = 3482, y = 3419, members = true }, - { id = "ghast_mort_myre_swamp", x = 3482, y = 3431, members = true }, - { id = "ghast_mort_myre_swamp", x = 3482, y = 3442, members = true }, - { id = "ghast_mort_myre_swamp", x = 3485, y = 3436, members = true }, - { id = "ghast_mort_myre_swamp", x = 3485, y = 3451, members = true }, - { id = "ghast_mort_myre_swamp", x = 3486, y = 3399, members = true }, - { id = "ghast_mort_myre_swamp", x = 3486, y = 3407, members = true }, - { id = "ghast_mort_myre_swamp", x = 3487, y = 3423, members = true }, - { id = "ghast_mort_myre_swamp", x = 3490, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3490, y = 3446, members = true }, - { id = "ghast_mort_myre_swamp", x = 3491, y = 3430, members = true }, - { id = "ghast_mort_myre_swamp", x = 3492, y = 3405, members = true }, - { id = "ghast_mort_myre_swamp", x = 3496, y = 3395, members = true }, - { id = "ghast_mort_myre_swamp", x = 3497, y = 3409, members = true }, - { id = "ghast_mort_myre_swamp", x = 3497, y = 3417, members = true }, - { id = "ghast_mort_myre_swamp", x = 3498, y = 3452, members = true }, - { id = "ghast_mort_myre_swamp", x = 3500, y = 3422, members = true }, - { id = "ghast_mort_myre_swamp", x = 3501, y = 3403, members = true }, - { id = "ghast_mort_myre_swamp", x = 3502, y = 3415, members = true }, - { id = "ghast_mort_myre_swamp", x = 3508, y = 3393, members = true }, - { id = "ghast_mort_myre_swamp", x = 3508, y = 3400, members = true }, - { id = "ghast_mort_myre_swamp", x = 3509, y = 3421, members = true }, - { id = "ghast_mort_myre_swamp", x = 3511, y = 3397, members = true }, - { id = "ghast_mort_myre_swamp", x = 3511, y = 3408, members = true }, - { id = "ghast_mort_myre_swamp", x = 3514, y = 3418, members = true }, - { id = "ghast_mort_myre_swamp", x = 3515, y = 3414, members = true }, - { id = "ghast_mort_myre_swamp", x = 3516, y = 3393, members = true }, - { id = "ghast_mort_myre_swamp", x = 3516, y = 3404, members = true }, - { id = "ghast_mort_myre_swamp", x = 3517, y = 3452, members = true }, - { id = "ghast_mort_myre_swamp", x = 3518, y = 3399, members = true }, - { id = "ghast_mort_myre_swamp", x = 3518, y = 3417, members = true }, - { id = "ghast_mort_myre_swamp", x = 3518, y = 3428, members = true }, + { id = "ghast", x = 3401, y = 3361, members = true }, + { id = "ghast", x = 3404, y = 3371, members = true }, + { id = "ghast", x = 3406, y = 3354, members = true }, + { id = "ghast", x = 3407, y = 3379, members = true }, + { id = "ghast", x = 3408, y = 3386, members = true }, + { id = "ghast", x = 3411, y = 3380, members = true }, + { id = "ghast", x = 3412, y = 3357, members = true }, + { id = "ghast", x = 3414, y = 3365, members = true }, + { id = "ghast", x = 3415, y = 3372, members = true }, + { id = "ghast", x = 3415, y = 3390, members = true }, + { id = "ghast", x = 3416, y = 3345, members = true }, + { id = "ghast", x = 3417, y = 3337, members = true }, + { id = "ghast", x = 3417, y = 3385, members = true }, + { id = "ghast", x = 3418, y = 3356, members = true }, + { id = "ghast", x = 3419, y = 3361, members = true }, + { id = "ghast", x = 3420, y = 3333, members = true }, + { id = "ghast", x = 3423, y = 3348, members = true }, + { id = "ghast", x = 3424, y = 3337, members = true }, + { id = "ghast", x = 3426, y = 3366, members = true }, + { id = "ghast", x = 3427, y = 3379, members = true }, + { id = "ghast", x = 3427, y = 3389, members = true }, + { id = "ghast", x = 3429, y = 3330, members = true }, + { id = "ghast", x = 3429, y = 3352, members = true }, + { id = "ghast", x = 3430, y = 3344, members = true }, + { id = "ghast", x = 3431, y = 3366, members = true }, + { id = "ghast", x = 3436, y = 3389, members = true }, + { id = "ghast", x = 3441, y = 3364, members = true }, + { id = "ghast", x = 3443, y = 3383, members = true }, + { id = "ghast", x = 3447, y = 3391, members = true }, + { id = "ghast", x = 3449, y = 3345, members = true }, + { id = "ghast", x = 3453, y = 3357, members = true }, + { id = "ghast", x = 3453, y = 3386, members = true }, + { id = "ghast", x = 3454, y = 3346, members = true }, + { id = "ghast", x = 3454, y = 3369, members = true }, + { id = "ghast", x = 3410, y = 3398, members = true }, + { id = "ghast", x = 3413, y = 3423, members = true }, + { id = "ghast", x = 3413, y = 3443, members = true }, + { id = "ghast", x = 3414, y = 3418, members = true }, + { id = "ghast", x = 3415, y = 3407, members = true }, + { id = "ghast", x = 3415, y = 3432, members = true }, + { id = "ghast", x = 3419, y = 3395, members = true }, + { id = "ghast", x = 3419, y = 3413, members = true }, + { id = "ghast", x = 3420, y = 3425, members = true }, + { id = "ghast", x = 3420, y = 3435, members = true }, + { id = "ghast", x = 3420, y = 3440, members = true }, + { id = "ghast", x = 3422, y = 3395, members = true }, + { id = "ghast", x = 3424, y = 3403, members = true }, + { id = "ghast", x = 3425, y = 3395, members = true }, + { id = "ghast", x = 3426, y = 3419, members = true }, + { id = "ghast", x = 3427, y = 3431, members = true }, + { id = "ghast", x = 3428, y = 3395, members = true }, + { id = "ghast", x = 3428, y = 3445, members = true }, + { id = "ghast", x = 3429, y = 3436, members = true }, + { id = "ghast", x = 3432, y = 3419, members = true }, + { id = "ghast", x = 3432, y = 3445, members = true }, + { id = "ghast", x = 3437, y = 3401, members = true }, + { id = "ghast", x = 3437, y = 3435, members = true }, + { id = "ghast", x = 3441, y = 3415, members = true }, + { id = "ghast", x = 3441, y = 3428, members = true }, + { id = "ghast", x = 3442, y = 3395, members = true }, + { id = "ghast", x = 3443, y = 3432, members = true }, + { id = "ghast", x = 3444, y = 3406, members = true }, + { id = "ghast", x = 3445, y = 3394, members = true }, + { id = "ghast", x = 3448, y = 3393, members = true }, + { id = "ghast", x = 3450, y = 3423, members = true }, + { id = "ghast", x = 3450, y = 3430, members = true }, + { id = "ghast", x = 3451, y = 3396, members = true }, + { id = "ghast", x = 3453, y = 3395, members = true }, + { id = "ghast", x = 3453, y = 3436, members = true }, + { id = "ghast", x = 3454, y = 3414, members = true }, + { id = "ghast", x = 3456, y = 3343, members = true }, + { id = "ghast", x = 3456, y = 3366, members = true }, + { id = "ghast", x = 3456, y = 3390, members = true }, + { id = "ghast", x = 3457, y = 3351, members = true }, + { id = "ghast", x = 3457, y = 3356, members = true }, + { id = "ghast", x = 3457, y = 3370, members = true }, + { id = "ghast", x = 3457, y = 3378, members = true }, + { id = "ghast", x = 3458, y = 3340, members = true }, + { id = "ghast", x = 3460, y = 3375, members = true }, + { id = "ghast", x = 3463, y = 3336, members = true }, + { id = "ghast", x = 3463, y = 3341, members = true }, + { id = "ghast", x = 3463, y = 3353, members = true }, + { id = "ghast", x = 3464, y = 3372, members = true }, + { id = "ghast", x = 3464, y = 3380, members = true }, + { id = "ghast", x = 3465, y = 3359, members = true }, + { id = "ghast", x = 3466, y = 3332, members = true }, + { id = "ghast", x = 3467, y = 3380, members = true }, + { id = "ghast", x = 3468, y = 3348, members = true }, + { id = "ghast", x = 3469, y = 3368, members = true }, + { id = "ghast", x = 3469, y = 3390, members = true }, + { id = "ghast", x = 3470, y = 3381, members = true }, + { id = "ghast", x = 3472, y = 3362, members = true }, + { id = "ghast", x = 3473, y = 3352, members = true }, + { id = "ghast", x = 3474, y = 3380, members = true }, + { id = "ghast", x = 3474, y = 3387, members = true }, + { id = "ghast", x = 3475, y = 3373, members = true }, + { id = "ghast", x = 3477, y = 3354, members = true }, + { id = "ghast", x = 3478, y = 3328, members = true }, + { id = "ghast", x = 3482, y = 3343, members = true }, + { id = "ghast", x = 3485, y = 3373, members = true }, + { id = "ghast", x = 3486, y = 3329, members = true }, + { id = "ghast", x = 3486, y = 3380, members = true }, + { id = "ghast", x = 3487, y = 3368, members = true }, + { id = "ghast", x = 3488, y = 3343, members = true }, + { id = "ghast", x = 3488, y = 3350, members = true }, + { id = "ghast", x = 3488, y = 3357, members = true }, + { id = "ghast", x = 3491, y = 3376, members = true }, + { id = "ghast", x = 3491, y = 3381, members = true }, + { id = "ghast", x = 3491, y = 3388, members = true }, + { id = "ghast", x = 3492, y = 3360, members = true }, + { id = "ghast", x = 3492, y = 3371, members = true }, + { id = "ghast", x = 3494, y = 3328, members = true }, + { id = "ghast", x = 3494, y = 3341, members = true }, + { id = "ghast", x = 3498, y = 3354, members = true }, + { id = "ghast", x = 3500, y = 3385, members = true }, + { id = "ghast", x = 3501, y = 3388, members = true }, + { id = "ghast", x = 3502, y = 3328, members = true }, + { id = "ghast", x = 3502, y = 3350, members = true }, + { id = "ghast", x = 3502, y = 3363, members = true }, + { id = "ghast", x = 3503, y = 3359, members = true }, + { id = "ghast", x = 3505, y = 3379, members = true }, + { id = "ghast", x = 3507, y = 3348, members = true }, + { id = "ghast", x = 3508, y = 3367, members = true }, + { id = "ghast", x = 3510, y = 3341, members = true }, + { id = "ghast", x = 3510, y = 3381, members = true }, + { id = "ghast", x = 3512, y = 3328, members = true }, + { id = "ghast", x = 3513, y = 3383, members = true }, + { id = "ghast", x = 3517, y = 3329, members = true }, + { id = "ghast", x = 3517, y = 3336, members = true }, + { id = "ghast", x = 3457, y = 3411, members = true }, + { id = "ghast", x = 3458, y = 3401, members = true }, + { id = "ghast", x = 3461, y = 3406, members = true }, + { id = "ghast", x = 3462, y = 3399, members = true }, + { id = "ghast", x = 3463, y = 3416, members = true }, + { id = "ghast", x = 3463, y = 3448, members = true }, + { id = "ghast", x = 3464, y = 3441, members = true }, + { id = "ghast", x = 3467, y = 3415, members = true }, + { id = "ghast", x = 3469, y = 3397, members = true }, + { id = "ghast", x = 3473, y = 3394, members = true }, + { id = "ghast", x = 3473, y = 3412, members = true }, + { id = "ghast", x = 3475, y = 3401, members = true }, + { id = "ghast", x = 3481, y = 3406, members = true }, + { id = "ghast", x = 3482, y = 3419, members = true }, + { id = "ghast", x = 3482, y = 3431, members = true }, + { id = "ghast", x = 3482, y = 3442, members = true }, + { id = "ghast", x = 3485, y = 3436, members = true }, + { id = "ghast", x = 3485, y = 3451, members = true }, + { id = "ghast", x = 3486, y = 3399, members = true }, + { id = "ghast", x = 3486, y = 3407, members = true }, + { id = "ghast", x = 3487, y = 3423, members = true }, + { id = "ghast", x = 3490, y = 3395, members = true }, + { id = "ghast", x = 3490, y = 3446, members = true }, + { id = "ghast", x = 3491, y = 3430, members = true }, + { id = "ghast", x = 3492, y = 3405, members = true }, + { id = "ghast", x = 3496, y = 3395, members = true }, + { id = "ghast", x = 3497, y = 3409, members = true }, + { id = "ghast", x = 3497, y = 3417, members = true }, + { id = "ghast", x = 3498, y = 3452, members = true }, + { id = "ghast", x = 3500, y = 3422, members = true }, + { id = "ghast", x = 3501, y = 3403, members = true }, + { id = "ghast", x = 3502, y = 3415, members = true }, + { id = "ghast", x = 3508, y = 3393, members = true }, + { id = "ghast", x = 3508, y = 3400, members = true }, + { id = "ghast", x = 3509, y = 3421, members = true }, + { id = "ghast", x = 3511, y = 3397, members = true }, + { id = "ghast", x = 3511, y = 3408, members = true }, + { id = "ghast", x = 3514, y = 3418, members = true }, + { id = "ghast", x = 3515, y = 3414, members = true }, + { id = "ghast", x = 3516, y = 3393, members = true }, + { id = "ghast", x = 3516, y = 3404, members = true }, + { id = "ghast", x = 3517, y = 3452, members = true }, + { id = "ghast", x = 3518, y = 3399, members = true }, + { id = "ghast", x = 3518, y = 3417, members = true }, + { id = "ghast", x = 3518, y = 3428, members = true }, { id = "myre_blamish_snail", x = 3425, y = 3317, members = true }, { id = "myre_blamish_snail", x = 3427, y = 3319, members = true }, { id = "myre_blamish_snail", x = 3430, y = 3291, members = true }, @@ -324,11 +324,11 @@ spawns = [ { id = "fishing_spot_mort_myre_swamp_south", x = 3443, y = 3272, members = true }, { id = "fishing_spot_mort_myre_swamp_south", x = 3445, y = 3274, members = true }, { id = "curpile_fyod_mort_myre_swamp", x = 3508, y = 3440, members = true }, - { id = "ghast_mort_myre_swamp", x = 3523, y = 3436, members = true }, - { id = "ghast_mort_myre_swamp", x = 3526, y = 3398, members = true }, - { id = "ghast_mort_myre_swamp", x = 3531, y = 3425, members = true }, - { id = "ghast_mort_myre_swamp", x = 3548, y = 3450, members = true }, - { id = "ghast_mort_myre_swamp", x = 3563, y = 3444, members = true }, + { id = "ghast", x = 3523, y = 3436, members = true }, + { id = "ghast", x = 3526, y = 3398, members = true }, + { id = "ghast", x = 3531, y = 3425, members = true }, + { id = "ghast", x = 3548, y = 3450, members = true }, + { id = "ghast", x = 3563, y = 3444, members = true }, { id = "myre_blamish_snail", x = 3524, y = 3413, members = true }, { id = "myre_blamish_snail", x = 3530, y = 3441, members = true }, { id = "myre_blamish_snail", x = 3541, y = 3410, members = true }, diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml index a14a94063b..9e7f529203 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml @@ -1,7 +1,7 @@ -[ghast_mort_myre_swamp] +[ghast] id = 1052 categories = ["ghosts"] -hunt_mode = "spotted" +hunt_mode = "aggressive" examine = "Arrghhh... A Ghast." [ghast_level_30] diff --git a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml index 9180815a18..f5a1ffc0da 100644 --- a/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml +++ b/data/area/morytania/mort_myre_swamp/mort_myre_swamp.sounds.toml @@ -6,3 +6,9 @@ id = 790 [snail_death] id = 787 + +[ghast_attack] +id = 433 + +[food_rot] +id = 1494 diff --git a/game/src/main/kotlin/content/area/morytania/mort_myre_swamp/Ghast.kt b/game/src/main/kotlin/content/area/morytania/mort_myre_swamp/Ghast.kt new file mode 100644 index 0000000000..86423637ce --- /dev/null +++ b/game/src/main/kotlin/content/area/morytania/mort_myre_swamp/Ghast.kt @@ -0,0 +1,62 @@ +package content.area.morytania.mort_myre_swamp + +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.entity.character.Character +import world.gregs.voidps.engine.entity.character.mode.Retreat +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.engine.inv.replace + +class Ghast : Script { + init { + npcCondition("has_food") { + hasFood(it) + } + npcCondition("has_no_food") { + !hasFood(it) + } + + npcAttack("ghast", "miss") { + mode = Retreat(this, it) + } + + npcAttack("ghast", "energy") { + mode = Retreat(this, it) + } + + npcAttack("ghast", "rot") { + rotFood(it) + mode = Retreat(this, it) + } + } + + fun hasFood(character: Character): Boolean { + if (character !is Player) { + return false + } + for (item in character.inventory.items) { + if (item.isEmpty()) { + continue + } + if (item.def.options.contains("Eat")) { + return true + } + } + return false + } + + fun rotFood(character: Character) { + if (character !is Player) { + return + } + for (item in character.inventory.items) { + if (item.isEmpty()) { + continue + } + if (item.def.options.contains("Eat")) { + character.inventory.replace(item.id, "rotten_food") + return + } + } + } +} diff --git a/game/src/main/kotlin/content/area/morytania/mort_myre_swamp/SwampDecay.kt b/game/src/main/kotlin/content/area/morytania/mort_myre_swamp/SwampDecay.kt new file mode 100644 index 0000000000..87c5d1a41c --- /dev/null +++ b/game/src/main/kotlin/content/area/morytania/mort_myre_swamp/SwampDecay.kt @@ -0,0 +1,55 @@ +package content.area.morytania.mort_myre_swamp + +import content.entity.combat.hit.hit +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.data.definition.Areas +import world.gregs.voidps.engine.entity.item.Item +import world.gregs.voidps.engine.inv.any +import world.gregs.voidps.engine.inv.equipment +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.engine.timer.Timer +import world.gregs.voidps.type.random +import kotlin.random.nextInt + +class SwampDecay : Script { + val immunity = listOf( + Item("silver_sickle_b"), + Item("silver_sickle_emerald_b"), + Item("rod_of_ivandis"), + Item("rod_of_ivandis_2"), + Item("rod_of_ivandis_3"), + Item("rod_of_ivandis_4"), + Item("rod_of_ivandis_5"), + Item("rod_of_ivandis_6"), + Item("rod_of_ivandis_7"), + Item("rod_of_ivandis_8"), + Item("rod_of_ivandis_9"), + Item("rod_of_ivandis_10"), + ) + + init { + entered("mort_myre_swamp") { + softTimers.start("swamp_decay") + } + + timerStart("swamp_decay") { + 230 // 2 minutes 18 seconds + } + + timerTick("swamp_decay") { + if (inventory.any(immunity) || equipment.any(immunity)) { + return@timerTick Timer.CONTINUE + } + if (tile in Areas["mort_myre_swamp"]) { + message("The swamp decays you!") + hit(this, weapon = Item.EMPTY, spell = "", special = false, offensiveType = "damage", damage = random.nextInt(10..30)) + gfx("swamp_decay") + Timer.CONTINUE + } else { + message("The swamp decay effect is now over.") + Timer.CANCEL + } + } + } +} diff --git a/game/src/main/kotlin/content/entity/npc/combat/Attack.kt b/game/src/main/kotlin/content/entity/npc/combat/Attack.kt index 97d0883249..d381af58c5 100644 --- a/game/src/main/kotlin/content/entity/npc/combat/Attack.kt +++ b/game/src/main/kotlin/content/entity/npc/combat/Attack.kt @@ -95,7 +95,7 @@ class Attack( val hit = attack.targetHits[i] delay = delays.getOrNull(i) ?: -1 if (delay == -1) { - delay = if (Hit.meleeType(hit.offense)) 0 else 64 + delay = if (Hit.meleeType(hit.offense) || hit.offense == "damage") 0 else 64 } if (hit.delay != null) { delay += hit.delay!! From 9c3a8d826c331d01aa6146d8bb8bd5165ca975c1 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 19:44:18 +0100 Subject: [PATCH 05/14] Add post npc death handling --- game/src/main/kotlin/content/entity/combat/Combat.kt | 8 +++----- game/src/main/kotlin/content/entity/death/NPCDeath.kt | 11 ++++++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/game/src/main/kotlin/content/entity/combat/Combat.kt b/game/src/main/kotlin/content/entity/combat/Combat.kt index 382bef5889..713177dd0f 100644 --- a/game/src/main/kotlin/content/entity/combat/Combat.kt +++ b/game/src/main/kotlin/content/entity/combat/Combat.kt @@ -12,6 +12,7 @@ import world.gregs.voidps.engine.client.variable.start import world.gregs.voidps.engine.client.variable.stop import world.gregs.voidps.engine.data.definition.CombatDefinitions import world.gregs.voidps.engine.entity.character.Character +import world.gregs.voidps.engine.entity.character.Death import world.gregs.voidps.engine.entity.character.mode.EmptyMode import world.gregs.voidps.engine.entity.character.mode.PauseMode import world.gregs.voidps.engine.entity.character.mode.Retreat @@ -82,10 +83,7 @@ class Combat(val combatDefinitions: CombatDefinitions) : this.target = null } - playerDeath { - stop(this) - } - + playerDeath(handler = ::stop) npcDeath(handler = ::stop) combatDamage(handler = ::damage) @@ -102,7 +100,7 @@ class Combat(val combatDefinitions: CombatDefinitions) : } } - fun stop(character: Character) { + fun stop(character: Character, onDeath: Death.OnDeath) { character.stop("under_attack") for (attacker in character.attackers) { if (attacker.target == character) { diff --git a/game/src/main/kotlin/content/entity/death/NPCDeath.kt b/game/src/main/kotlin/content/entity/death/NPCDeath.kt index 444533c3d4..de01d592a3 100644 --- a/game/src/main/kotlin/content/entity/death/NPCDeath.kt +++ b/game/src/main/kotlin/content/entity/death/NPCDeath.kt @@ -59,7 +59,7 @@ class NPCDeath( dead = true steps.clear() val npc = this - Death.killed(npc) + val onDeath = Death.killed(npc) strongQueue(name = "death", 1) { val killer = killer val tile = if (transformId == "wall_beast") tile.addY(-1) else tile @@ -73,13 +73,18 @@ class NPCDeath( if (killer is Player) { AuditLog.event(killer, "killed", npc, tile) slay(killer, npc) - dropLoot(npc, killer, tile) + if (onDeath.dropItems) { + dropLoot(npc, killer, tile) + } } attackers.clear() softTimers.stopAll() + if (Death.afterDeath(npc)) { + return@strongQueue + } hide = true val respawn = get("respawn_tile") - if (respawn != null) { + if (respawn != null && onDeath.respawn) { tele(respawn) delay(npc["respawn_delay", 60]) clearAnim() From 910b0c3a929295b1b2e91e0b28e3588e771b93e2 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 19:44:41 +0100 Subject: [PATCH 06/14] Add warning dismiss message --- .../content/entity/player/dialogue/type/Warning.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/game/src/main/kotlin/content/entity/player/dialogue/type/Warning.kt b/game/src/main/kotlin/content/entity/player/dialogue/type/Warning.kt index 3f3ed7fc83..688b2547d3 100644 --- a/game/src/main/kotlin/content/entity/player/dialogue/type/Warning.kt +++ b/game/src/main/kotlin/content/entity/player/dialogue/type/Warning.kt @@ -1,6 +1,7 @@ package content.entity.player.dialogue.type import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.message import world.gregs.voidps.engine.client.ui.close import world.gregs.voidps.engine.client.ui.open import world.gregs.voidps.engine.entity.character.player.Player @@ -22,10 +23,12 @@ class Warning : Script { init { interfaceOption("Yes", "warning_*:yes") { + info(it.id) (dialogueSuspension as StringSuspension).resume("yes") } interfaceOption("Ok", "warning_*:yes") { + info(it.id) (dialogueSuspension as StringSuspension).resume("yes") } @@ -34,6 +37,7 @@ class Warning : Script { } continueDialogue("warning_*:yes") { + info(it) (dialogueSuspension as StringSuspension).resume("yes") } @@ -51,4 +55,11 @@ class Warning : Script { } } } + + private fun Player.info(id: String) { + if (get(id, 0) == 7) { + // https://youtu.be/6j15c74a3uM?t=76 + message("You have toggled this warning screen off. You will not see this warning screen unless you speak to the Doomsayer in Lumbridge to turn it on again.") + } + } } From cf445bdaf03a3f242481b798355cf7370e68c627 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 19:44:53 +0100 Subject: [PATCH 07/14] Add post death --- .../voidps/engine/entity/character/Death.kt | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Death.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Death.kt index 156f32f5b8..043df844df 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Death.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Death.kt @@ -13,6 +13,7 @@ interface Death { data class OnDeath( var dropItems: Boolean = true, var teleport: Tile? = null, + var respawn: Boolean = true, ) fun playerDeath(handler: Player.(OnDeath) -> Unit) { @@ -20,13 +21,20 @@ interface Death { playerHandlers.add(handler) } - fun npcDeath(npc: String = "*", handler: NPC.() -> Unit) { + fun npcDeath(npc: String = "*", handler: NPC.(OnDeath) -> Unit) { Script.checkLoading() Wildcards.find(npc, Wildcard.Npc) { id -> npcHandlers.getOrPut(id) { mutableListOf() }.add(handler) } } + fun npcAfterDeath(npc: String = "*", handler: NPC.() -> Unit) { + Script.checkLoading() + Wildcards.find(npc, Wildcard.Npc) { id -> + npcAfterHandlers.getOrPut(id) { mutableListOf() }.add(handler) + } + } + fun npcCanDie(npc: String = "*", handler: NPC.() -> Boolean) { Script.checkLoading() Wildcards.find(npc, Wildcard.Npc) { id -> @@ -36,8 +44,9 @@ interface Death { companion object : AutoCloseable { private val playerHandlers = ObjectArrayList Unit>(20) - private val npcHandlers = Object2ObjectOpenHashMap Unit>>(20) + private val npcHandlers = Object2ObjectOpenHashMap Unit>>(20) private val npcDeathHandlers = Object2ObjectOpenHashMap Boolean>>(20) + private val npcAfterHandlers = Object2ObjectOpenHashMap Unit>>(20) fun killed(player: Player): OnDeath { val onDeath = OnDeath() @@ -47,13 +56,27 @@ interface Death { return onDeath } - fun killed(npc: NPC) { + fun killed(npc: NPC): OnDeath { + val onDeath = OnDeath() for (handler in npcHandlers[npc.id] ?: emptyList()) { - handler.invoke(npc) + handler.invoke(npc, onDeath) } for (handler in npcHandlers["*"] ?: emptyList()) { + handler.invoke(npc, onDeath) + } + return onDeath + } + + fun afterDeath(npc: NPC): Boolean { + for (handler in npcAfterHandlers[npc.id] ?: emptyList()) { + handler.invoke(npc) + return true + } + for (handler in npcAfterHandlers["*"] ?: emptyList()) { handler.invoke(npc) + return true } + return false } fun canDie(npc: NPC): Boolean { From 098f482a0bf6079c5cc50b91ef66aadfc63afe7f Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 19:45:07 +0100 Subject: [PATCH 08/14] Add tile list table support --- .../world/gregs/voidps/engine/data/definition/Tables.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/Tables.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/Tables.kt index f10ee0d662..f9424fc966 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/Tables.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/Tables.kt @@ -124,6 +124,10 @@ object Tables { fun itemListOrNull(path: String): List? = getOrNull(path, ColumnType.IntList)?.map { ItemDefinitions.get(it).stringId } + fun tileList(path: String): List = get(path, ColumnType.IntList).map { Tile(it) } + + fun tileListOrNull(path: String): List? = getOrNull(path, ColumnType.IntList)?.map { Tile(it) } + fun objList(path: String): List = get(path, ColumnType.IntList).map { ObjectDefinitions.get(it).stringId } fun objListOrNull(path: String): List? = getOrNull(path, ColumnType.IntList)?.map { ObjectDefinitions.get(it).stringId } From 0e61b54e14c9ec434960063c4c6a727b10e12216 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 20:48:48 +0100 Subject: [PATCH 09/14] Add item on deposit box depositing --- .../stronghold_of_player_safety.anims.toml | 4 +- data/entity/player/human.anims.toml | 5 +- .../StrongholdOfPlayerSafety.kt | 4 +- .../content/entity/player/bank/BankDeposit.kt | 119 ++++++++++++------ .../content/entity/player/bank/BankOpen.kt | 2 + .../network/login/protocol/JagExtensions.kt | 2 +- 6 files changed, 89 insertions(+), 47 deletions(-) diff --git a/data/area/misthalin/edgeville/stronghold_of_player_safety/stronghold_of_player_safety.anims.toml b/data/area/misthalin/edgeville/stronghold_of_player_safety/stronghold_of_player_safety.anims.toml index 88d3001be0..128aeba351 100644 --- a/data/area/misthalin/edgeville/stronghold_of_player_safety/stronghold_of_player_safety.anims.toml +++ b/data/area/misthalin/edgeville/stronghold_of_player_safety/stronghold_of_player_safety.anims.toml @@ -4,8 +4,8 @@ id = 8804 [push_ground_lever] id = 8805 -[lever_down] +[stronghold_lever_down] id = 8802 -[lever_up] +[stronghold_lever_up] id = 8803 \ No newline at end of file diff --git a/data/entity/player/human.anims.toml b/data/entity/player/human.anims.toml index f24a91b670..2bf6e1b409 100644 --- a/data/entity/player/human.anims.toml +++ b/data/entity/player/human.anims.toml @@ -65,4 +65,7 @@ id = 537 id = 810 [open_chest_mid] -id = 2094 \ No newline at end of file +id = 2094 + +[human_lever_down] +id = 834 diff --git a/game/src/main/kotlin/content/area/misthalin/edgeville/stronghold_of_player_safety/StrongholdOfPlayerSafety.kt b/game/src/main/kotlin/content/area/misthalin/edgeville/stronghold_of_player_safety/StrongholdOfPlayerSafety.kt index 999d195769..0bdbd0c6cb 100644 --- a/game/src/main/kotlin/content/area/misthalin/edgeville/stronghold_of_player_safety/StrongholdOfPlayerSafety.kt +++ b/game/src/main/kotlin/content/area/misthalin/edgeville/stronghold_of_player_safety/StrongholdOfPlayerSafety.kt @@ -47,7 +47,7 @@ class StrongholdOfPlayerSafety : Script { objectOperate("Pull", "stronghold_of_player_safety_an_old_lever_closed") { (target) -> arriveDelay() animDelay("pull_ground_lever") - target.anim("lever_down") + target.anim("stronghold_lever_down") areaSound("lever", tile) delay(2) areaSound("unlock", tile) @@ -60,7 +60,7 @@ class StrongholdOfPlayerSafety : Script { objectOperate("Pull", "stronghold_of_player_safety_an_old_lever_opened") { (target) -> arriveDelay() animDelay("push_ground_lever") - target.anim("lever_up") + target.anim("stronghold_lever_up") areaSound("lever", target.tile) delay(1) areaSound("unlock", target.tile) diff --git a/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt b/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt index 4a9464fdec..ed9cc25e6b 100644 --- a/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt +++ b/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt @@ -2,10 +2,13 @@ package content.entity.player.bank import com.github.michaelbull.logging.InlineLogger import content.entity.player.bank.Bank.tabIndex +import content.entity.player.dialogue.type.choice import content.entity.player.dialogue.type.intEntry import world.gregs.voidps.engine.Script import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.client.ui.chat.toDigitGroupString import world.gregs.voidps.engine.client.ui.menu +import world.gregs.voidps.engine.entity.character.mode.interact.ItemOnObjectInteract import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.item.Item import world.gregs.voidps.engine.inv.Inventory @@ -18,8 +21,6 @@ import world.gregs.voidps.engine.inv.transact.operation.ShiftItem.shift class BankDeposit : Script { - val logger = InlineLogger() - init { interfaceOption(id = "bank_side:inventory") { (item, _, option) -> val amount = when (option) { @@ -101,52 +102,88 @@ class BankDeposit : Script { } } - fun deposit(player: Player, inventory: Inventory, item: Item, amount: Int): Boolean { - if ((player.menu != "bank" && player.menu != "bank_deposit_box") || amount < 1) { - return true - } - if (item.def["unbankable", 0] == 1) { - player.message("This item cannot be banked.") - return true + fun bankAll(player: Player, inventory: Inventory) { + for (index in inventory.indices) { + val item = inventory[index] + if (item.isNotEmpty()) { + deposit(player, inventory, item, item.amount) + } } + } - val notNoted = if (item.isNote) item.noted else item - if (notNoted == null) { - logger.warn { "Issue depositing noted item $item" } - return true - } + companion object { + private val logger = InlineLogger() - val tab = player["open_bank_tab", 1] - 1 - val bank = player.bank - var shifted = false - inventory.transaction { - val existing = bank.indexOf(notNoted.id) - val moved = moveToLimit(item.id, amount, bank, notNoted.id) - if (moved == 0) { - error = TransactionError.Full() - } else if (moved > 0 && tab > 0 && existing == -1) { - // Shift item into tab - val index = bank.freeIndex() - 1 - val to = tabIndex(player, tab + 1) - link(bank).shift(index, to) - shifted = true + private fun deposit(player: Player, inventory: Inventory, item: Item, amount: Int, check: Boolean = true) { + if ((check && player.menu != "bank" && player.menu != "bank_deposit_box") || amount < 1) { + return + } + + if (item.def["unbankable", 0] == 1) { + player.message("This item cannot be banked.") + return + } + + val notNoted = if (item.isNote) item.noted else item + if (notNoted == null) { + logger.warn { "Issue depositing noted item $item" } + return + } + + val tab = player["open_bank_tab", 1] - 1 + val bank = player.bank + var shifted = false + inventory.transaction { + val existing = bank.indexOf(notNoted.id) + val moved = moveToLimit(item.id, amount, bank, notNoted.id) + if (moved == 0) { + error = TransactionError.Full() + } else if (moved > 0 && tab > 0 && existing == -1) { + // Shift item into tab + val index = bank.freeIndex() - 1 + val to = tabIndex(player, tab + 1) + link(bank).shift(index, to) + shifted = true + } + } + when (inventory.transaction.error) { + TransactionError.None -> if (shifted) player.inc("bank_tab_$tab") + is TransactionError.Full -> player.message("Your bank is too full to deposit any more.") + TransactionError.Invalid -> logger.info { "Bank deposit issue: $player $item $amount $inventory " } + else -> {} } } - when (inventory.transaction.error) { - TransactionError.None -> if (shifted) player.inc("bank_tab_$tab") - is TransactionError.Full -> player.message("Your bank is too full to deposit any more.") - TransactionError.Invalid -> logger.info { "Bank deposit issue: $player $item $amount $inventory " } - else -> {} - } - return true - } - fun bankAll(player: Player, inventory: Inventory) { - for (index in inventory.indices) { - val item = inventory[index] - if (item.isNotEmpty()) { - deposit(player, inventory, item, item.amount) + suspend fun itemOnDeposit(player: Player, it: ItemOnObjectInteract) { + val count = player.inventory.count(it.item.id) + player.choice("How many would you like to deposit?") { + option("One") { + anim("human_lever_down") + deposit(player, player.inventory, it.item, 1, check = false) + } + if (count == 2) { + option("Both") { + anim("human_lever_down") + deposit(player, player.inventory, it.item, 2, check = false) + } + } else if (count > 5) { + option("Five") { + anim("human_lever_down") + deposit(player, player.inventory, it.item, 5, check = false) + } + } + option("X") { + val amount = intEntry("How many would you like to deposit? 1 - ${count.toDigitGroupString()}") + if (amount > 0) { + anim("human_lever_down") + deposit(player, player.inventory, it.item, amount, check = false) + } + } + option("All") { + anim("human_lever_down") + deposit(player, player.inventory, it.item, count, check = false) + } } } } diff --git a/game/src/main/kotlin/content/entity/player/bank/BankOpen.kt b/game/src/main/kotlin/content/entity/player/bank/BankOpen.kt index 6cea482ef0..ce436cfa05 100644 --- a/game/src/main/kotlin/content/entity/player/bank/BankOpen.kt +++ b/game/src/main/kotlin/content/entity/player/bank/BankOpen.kt @@ -85,6 +85,8 @@ class BankOpen(val accounts: AccountDefinitions) : Script { objectOperate("Deposit", "bank_deposit_box*") { open("bank_deposit_box") } + + itemOnObjectOperate(obj = "bank_deposit_box*", handler = BankDeposit::itemOnDeposit) } fun bank(player: Player, args: List) { diff --git a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/JagExtensions.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/JagExtensions.kt index ba1b2fe331..cdd2cb790f 100644 --- a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/JagExtensions.kt +++ b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/JagExtensions.kt @@ -178,7 +178,7 @@ fun Source.readShortAdd(): Int = (readByte().toInt() shl 8) or readByteAdd() fun Source.readShortAddLittle(): Int = ((readByte().toInt() - 128) and 0xff) or (readByte().toInt() shl 8) -fun Source.readUnsignedShortAdd(): Int = (readByte().toInt() shl 8) or ((readByte() - 128) and 0xff) +fun Source.readUnsignedShortAdd(): Int = (readUByte().toInt() shl 8) or ((readUByte().toInt() - 128) and 0xff) fun Source.readUnsignedShortLittle(): Int = readUByte().toInt() or (readUByte().toInt() shl 8) From 3d6c0c7759dd4f07a5803d485619f8d90efc17fc Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 20:51:30 +0100 Subject: [PATCH 10/14] Add item on deposit box depositing --- .../content/entity/player/bank/BankDeposit.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt b/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt index ed9cc25e6b..1290e8cc25 100644 --- a/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt +++ b/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt @@ -173,17 +173,19 @@ class BankDeposit : Script { deposit(player, player.inventory, it.item, 5, check = false) } } - option("X") { - val amount = intEntry("How many would you like to deposit? 1 - ${count.toDigitGroupString()}") - if (amount > 0) { + if (count > 2) { + option("X") { + val amount = intEntry("How many would you like to deposit? 1 - ${count.toDigitGroupString()}") + if (amount > 0) { + anim("human_lever_down") + deposit(player, player.inventory, it.item, amount, check = false) + } + } + option("All") { anim("human_lever_down") - deposit(player, player.inventory, it.item, amount, check = false) + deposit(player, player.inventory, it.item, count, check = false) } } - option("All") { - anim("human_lever_down") - deposit(player, player.inventory, it.item, count, check = false) - } } } } From d017ed8fbe01a82dfd97da825fdea15c3ef19e5a Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 20:51:59 +0100 Subject: [PATCH 11/14] Add living rock caverns --- .../dwarven_mines/dwarven_mine.teles.toml | 1 - .../living_rock_cavern.objs.toml | 3 - .../living_rock_caverns.anims.toml | 50 ++++++++ .../living_rock_caverns.areas.toml | 2 +- .../living_rock_caverns.combat.toml | 38 ++++++ .../living_rock_caverns.items.toml} | 0 .../living_rock_caverns.npc-spawns.toml | 40 +++--- .../living_rock_caverns.npcs.toml | 49 ++++++- .../living_rock_caverns.objs.toml | 17 +++ .../living_rock_caverns.tables.toml | 27 ++++ data/skill/fishing/fishing_spots.tables.toml | 4 +- data/skill/mining/rocks.tables.toml | 6 + data/skill/slayer/slayer.tables.toml | 2 +- .../living_rock_caverns/Farli.kt | 91 +++++++++++++ .../living_rock_caverns/LivingRockCaverns.kt | 103 +++++++++++++++ .../LivingRockCreatures.kt | 121 ++++++++++++++++++ .../kotlin/content/skill/mining/Mining.kt | 84 +++++++----- .../kotlin/content/skill/mining/Pickaxe.kt | 16 +++ game/src/main/resources/game.properties | 9 ++ 19 files changed, 599 insertions(+), 64 deletions(-) delete mode 100644 data/area/asgarnia/dwarven_mines/living_rock_cavern.objs.toml create mode 100644 data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.anims.toml create mode 100644 data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.combat.toml rename data/area/asgarnia/dwarven_mines/{living_rock_cavern.items.toml => living_rock_caverns/living_rock_caverns.items.toml} (100%) create mode 100644 data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.objs.toml create mode 100644 data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.tables.toml create mode 100644 game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt create mode 100644 game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt create mode 100644 game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt diff --git a/data/area/asgarnia/dwarven_mines/dwarven_mine.teles.toml b/data/area/asgarnia/dwarven_mines/dwarven_mine.teles.toml index 8243189e9f..21895105c1 100644 --- a/data/area/asgarnia/dwarven_mines/dwarven_mine.teles.toml +++ b/data/area/asgarnia/dwarven_mines/dwarven_mine.teles.toml @@ -35,4 +35,3 @@ delta = { y = -6400 } option = "Climb-up" tile = { x = 3019, y = 9740 } delta = { y = -6400 } - diff --git a/data/area/asgarnia/dwarven_mines/living_rock_cavern.objs.toml b/data/area/asgarnia/dwarven_mines/living_rock_cavern.objs.toml deleted file mode 100644 index 7edfb26725..0000000000 --- a/data/area/asgarnia/dwarven_mines/living_rock_cavern.objs.toml +++ /dev/null @@ -1,3 +0,0 @@ -[bank_booth_living_rock_cavern] -id = 18491 -examine = "The bank teller will serve you from here." diff --git a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.anims.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.anims.toml new file mode 100644 index 0000000000..02b04caecc --- /dev/null +++ b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.anims.toml @@ -0,0 +1,50 @@ +[living_rock_caverns_climb_rope] +id = 2413 + +[living_rock_caverns_climb_ledge] +id = 12216 + +[living_rock_caverns_rope_drop] +id = 12225 + +[living_rock_caverns_rope] +id = 12217 + +[living_rock_protector_idle] +id = 12193 + +[living_rock_striker_idle] +id = 12202 + +[protector_defend] +id = 12194 + +[protector_attack] +id = 12204 + +[striker_throw] +id = 12196 + +[living_rock_protector_fade] +id = 12197 + +[living_rock_striker_fade] +id = 12198 + +[protector_death] +id = 12199 + +[striker_defend] +id = 12201 + +[living_rock_patriarch_fade] +id = 12222 + +[patriarch_defend] +id = 12208 + +[patriarch_death] +id = 12206 + +[patriarch_attack] +id = 12205 \ No newline at end of file diff --git a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.areas.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.areas.toml index 0762045c50..d8b6470d33 100644 --- a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.areas.toml +++ b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.areas.toml @@ -1,3 +1,3 @@ -[living_rock_caverns_fishing_area] +[living_rock_caverns] x = [3584, 3710] y = [5056, 5182] diff --git a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.combat.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.combat.toml new file mode 100644 index 0000000000..9a03820778 --- /dev/null +++ b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.combat.toml @@ -0,0 +1,38 @@ +[living_rock_protector] +attack_speed = 6 +retreat_range = 8 +defend_anim = "protector_defend" +death_anim = "protector_death" + +[living_rock_protector.attack] +range = 1 +anim = "protector_attack" +target_hit = { offense = "crush", max = 120 } + +[living_rock_striker] +attack_speed = 6 +retreat_range = 8 +defend_anim = "striker_defend" +death_anim = "protector_death" + +[living_rock_striker.attack] +range = 1 +anim = "protector_attack" +target_hit = { offense = "crush", max = 90 } + +[living_rock_striker.range] +range = 6 +anim = "striker_throw" +#projectile = "" +target_hit = { offense = "range", max = 140 } + +[living_rock_patriarch] +attack_speed = 6 +retreat_range = 8 +defend_anim = "patriarch_defend" +death_anim = "patriarch_death" + +[living_rock_patriarch.attack] +range = 1 +anim = "patriarch_attack" +target_hit = { offense = "crush", max = 160 } diff --git a/data/area/asgarnia/dwarven_mines/living_rock_cavern.items.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.items.toml similarity index 100% rename from data/area/asgarnia/dwarven_mines/living_rock_cavern.items.toml rename to data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.items.toml diff --git a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npc-spawns.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npc-spawns.toml index 5c1087c25b..ea7b5f7e50 100644 --- a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npc-spawns.toml +++ b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npc-spawns.toml @@ -56,24 +56,24 @@ spawns = [ { id = "rock_critter", x = 3630, y = 5145, members = true }, { id = "rock_critter", x = 3631, y = 5132, members = true }, { id = "rock_critter", x = 3647, y = 5147, members = true }, - { id = "cavefish_shoal", x = 3614, y = 5111 }, - { id = "cavefish_shoal", x = 3616, y = 5118 }, - { id = "cavefish_shoal", x = 3629, y = 5083 }, - { id = "cavefish_shoal", x = 3633, y = 5081 }, - { id = "cavefish_shoal", x = 3615, y = 5127 }, - { id = "cavefish_shoal", x = 3623, y = 5132 }, - { id = "cavefish_shoal", x = 3628, y = 5132 }, - { id = "cavefish_shoal", x = 3637, y = 5138 }, - { id = "cavefish_shoal", x = 3653, y = 5085 }, - { id = "cavefish_shoal", x = 3674, y = 5115 }, - { id = "cavefish_shoal", x = 3652, y = 5146 }, - { id = "cavefish_shoal", x = 3657, y = 5144 }, - { id = "cavefish_shoal", x = 3696, y = 5142 }, - { id = "rocktail_shoal", x = 3616, y = 5088 }, - { id = "rocktail_shoal", x = 3625, y = 5114 }, - { id = "rocktail_shoal", x = 3645, y = 5082 }, - { id = "rocktail_shoal", x = 3631, y = 5144 }, - { id = "rocktail_shoal", x = 3683, y = 5109 }, - { id = "rocktail_shoal", x = 3653, y = 5141 }, - { id = "living_rock_caverns_controller", x = 3654, y = 5118 }, + { id = "fishing_spot_cavefish_shoal", x = 3614, y = 5111 }, + { id = "fishing_spot_cavefish_shoal", x = 3616, y = 5118 }, + { id = "fishing_spot_cavefish_shoal", x = 3629, y = 5083 }, + { id = "fishing_spot_cavefish_shoal", x = 3633, y = 5081 }, + { id = "fishing_spot_cavefish_shoal", x = 3615, y = 5127 }, + { id = "fishing_spot_cavefish_shoal", x = 3623, y = 5132 }, + { id = "fishing_spot_cavefish_shoal", x = 3628, y = 5132 }, + { id = "fishing_spot_cavefish_shoal", x = 3637, y = 5138 }, + { id = "fishing_spot_cavefish_shoal", x = 3653, y = 5085 }, + { id = "fishing_spot_cavefish_shoal", x = 3674, y = 5115 }, + { id = "fishing_spot_cavefish_shoal", x = 3652, y = 5146 }, + { id = "fishing_spot_cavefish_shoal", x = 3657, y = 5144 }, + { id = "fishing_spot_cavefish_shoal", x = 3696, y = 5142 }, + { id = "fishing_spot_rocktail_shoal", x = 3616, y = 5088 }, + { id = "fishing_spot_rocktail_shoal", x = 3625, y = 5114 }, + { id = "fishing_spot_rocktail_shoal", x = 3645, y = 5082 }, + { id = "fishing_spot_rocktail_shoal", x = 3631, y = 5144 }, + { id = "fishing_spot_rocktail_shoal", x = 3683, y = 5109 }, + { id = "fishing_spot_rocktail_shoal", x = 3653, y = 5141 }, + { id = "farli", x = 3655, y = 5115 }, ] diff --git a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npcs.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npcs.toml index 08ace6bd01..733a9b0f43 100644 --- a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npcs.toml +++ b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.npcs.toml @@ -1,24 +1,65 @@ [living_rock_protector] id = 8832 +hitpoints = 2250 +slayer_xp = 225.0 +hunt_mode = "aggressive" +hunt_range = 1 +combat_def = "living_rock_protector" categories = ["living_rock_creatures"] +immune_poison = true +# Made up stats +att = 130 +str = 130 +def = 80 examine = "A being of ore and minerals." +[living_rock_protector_remains] +id = 8837 + [living_rock_striker] id = 8833 +hitpoints = 3160 +slayer_xp = 316.0 +hunt_mode = "aggressive" +hunt_range = 1 +immune_poison = true +combat_def = "living_rock_striker" +categories = ["living_rock_creatures"] +# Made up stats +att = 150 +str = 150 +def = 80 +range = 100 +examine = "A being of ore and minerals." + +[living_rock_striker_remains] +id = 8838 + +[living_rock_patriarch] +id = 8834 +hitpoints = 4000 +slayer_xp = 530.0 +hunt_mode = "aggressive" +hunt_range = 1 +immune_poison = true +combat_def = "living_rock_patriarch" categories = ["living_rock_creatures"] examine = "A being of ore and minerals." +[living_rock_patriarch_remains] +id = 8839 + [rock_critter] id = 8840 examine = "What are these things?" -[cavefish_shoal] +[fishing_spot_cavefish_shoal] id = 8841 examine = "It looks like there are fish swimming in the water." -[rocktail_shoal] +[fishing_spot_rocktail_shoal] id = 8842 examine = "It looks like there are fish swimming in the water." -[living_rock_caverns_controller] -id = 8831 \ No newline at end of file +[farli] +id = 8831 diff --git a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.objs.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.objs.toml new file mode 100644 index 0000000000..02581e9185 --- /dev/null +++ b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.objs.toml @@ -0,0 +1,17 @@ +[pulley_lift] +id = 45079 + +[living_rock_caverns_rope] +id = 45078 + +[living_rock_caverns_entrance] +id = 45077 + +[farli] +id = 45091 + +[mineral_deposit_coal] +id = 5999 + +[mineral_deposit_gold] +id = 45076 diff --git a/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.tables.toml b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.tables.toml new file mode 100644 index 0000000000..5c4a280a6a --- /dev/null +++ b/data/area/asgarnia/dwarven_mines/living_rock_caverns/living_rock_caverns.tables.toml @@ -0,0 +1,27 @@ +[living_rock_cavern_spawns] +tiles = "list" + +[.coal] +tiles = [ + { x = 3690, y = 5146 }, + { x = 3690, y = 5125 }, + { x = 3687, y = 5107 }, + { x = 3664, y = 5090 }, + { x = 3615, y = 5090 }, + { x = 3625, y = 5107 }, + { x = 3647, y = 5142 }, +] + +[.gold] +tiles = [ + { x = 3677, y = 5160 }, + { x = 3667, y = 5075 }, + { x = 3637, y = 5094 }, + { x = 3629, y = 5148 }, +] + +[.patriarch] +tiles = [ + { x = 3634, y = 5103 }, + { x = 3676, y = 5135 }, +] \ No newline at end of file diff --git a/data/skill/fishing/fishing_spots.tables.toml b/data/skill/fishing/fishing_spots.tables.toml index 3666148544..cdc311d024 100644 --- a/data/skill/fishing/fishing_spots.tables.toml +++ b/data/skill/fishing/fishing_spots.tables.toml @@ -188,7 +188,7 @@ net = [] net = ["raw_shrimps", "raw_anchovies"] bait = ["raw_sardine", "raw_herring"] -[.cavefish_shoal] +[.fishing_spot_cavefish_shoal] bait = ["raw_cavefish"] [.fishing_spot_ardougne] @@ -251,5 +251,5 @@ lure = ["raw_trout", "raw_salmon", "raw_rainbow_fish"] bait = ["raw_pike"] lure = ["raw_trout", "raw_salmon", "raw_rainbow_fish"] -[.rocktail_shoal] +[.fishing_spot_rocktail_shoal] bait = ["raw_rocktail"] diff --git a/data/skill/mining/rocks.tables.toml b/data/skill/mining/rocks.tables.toml index e46908ddaa..6961e913d3 100644 --- a/data/skill/mining/rocks.tables.toml +++ b/data/skill/mining/rocks.tables.toml @@ -1093,3 +1093,9 @@ ores = ["tin_ore"] [.tin_rocks_tutorial_island_1] ores = ["tin_ore"] + +[.mineral_deposit_coal] +ores = ["coal"] + +[.mineral_deposit_gold] +ores = ["gold_ore"] diff --git a/data/skill/slayer/slayer.tables.toml b/data/skill/slayer/slayer.tables.toml index 5ec893f803..4eaa7177d8 100644 --- a/data/skill/slayer/slayer.tables.toml +++ b/data/skill/slayer/slayer.tables.toml @@ -296,7 +296,7 @@ combat_level = 20 [.scabarites] npc = "giant_scarab_normal" -quest = "dealing_with-scabaras" +quest = "contact" [.scorpions] npc = "scorpion" diff --git a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt new file mode 100644 index 0000000000..30c6e1d6b4 --- /dev/null +++ b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt @@ -0,0 +1,91 @@ +package content.area.asgarnia.dwarven_mines.living_rock_caverns + +import content.entity.player.dialogue.Angry +import content.entity.player.dialogue.Confused +import content.entity.player.dialogue.Happy +import content.entity.player.dialogue.Idle +import content.entity.player.dialogue.Neutral +import content.entity.player.dialogue.Quiz +import content.entity.player.dialogue.Shock +import content.entity.player.dialogue.Unamused +import content.entity.player.dialogue.type.ChoiceOption +import content.entity.player.dialogue.type.choice +import content.entity.player.dialogue.type.npc +import content.entity.player.dialogue.type.player +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.ui.dialogue.talkWith +import world.gregs.voidps.engine.entity.character.npc.NPCs +import world.gregs.voidps.type.Tile + +class Farli : Script { + private val name = "Farli" + + init { + objectOperate("Talk-to", "farli") { + talkWith(NPCs.find(Tile(3655, 5115), "farli")) + npc("Hello there!", title = name) + player("Hi.") + npc("What brings you down here then?", title = name) + choice { + thisPlace() + whoAreYou() + pulley() + dontTalk() + } + } + } + + private fun ChoiceOption.thisPlace() { + option("What is this place?") { + npc("It's a cavern.", title = name) + player("Really? Great, thanks for that.") + npc("No problem!", title = name) + player("So, is there actually anything in this cavern?") + npc("Well, there's rocks. A bit of water here and there too.", title = name) + player("Right. Good to know. I'm glad you were here, actually, because, you know, I'd have been lost without that.") + npc("Happy to help!", title = name) + } + } + + private fun ChoiceOption.whoAreYou() { + option("Who are you?") { + npc("I'm Farli. I came down here to explore the moment the cavern entrance opened up.", title = name) + player("Have you discovered anything down there?") + npc("Well, I did stumble across some nice-looking deposits of ore and some strange fish in the waters, but I haven't really been able to investigate further.", title = name) + player("Why not?") + npc("It's as if the rocks are moving... Whenever I've tried to map this place, I find rocks are in different places to when I checked before!", title = name) + player("Moving rocks? Are you sure you haven't been drinking?") + npc("Well, yes. I mean no. Look, that's not important. What is important is that the rocks down here are moving!", title = name) + player("I'll be sure to check that out...") + npc("It's true! One time I was mining a rock, or what I thought was a rock, and it upped and ran off with my best pickaxe!", title = name) + player("...") + choice { + thisPlace() + pulley() + dontTalk() + } + } + } + + private fun ChoiceOption.pulley() { + option("What does this pulley do?") { + npc("Oh, that's just to get my supplies in and out of the cavern.", title = name) + player("How does that work then?") + npc("The miners above use the mine cart system to move about what we need from Keldagrim.", title = name) + player("Hmm, that could be handy for depositing things into my bank. You think you could arrange that?") + npc("Hmm, maybe. I suppose if you're down here to help then I can sort something out.", title = name) + player("Thanks!") + choice { + thisPlace() + whoAreYou() + dontTalk() + } + } + } + + private fun ChoiceOption.dontTalk() { + option("Actually, I don't want to talk to you.") { + npc("Hmph! How rude!", title = name) + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt new file mode 100644 index 0000000000..181ef5c438 --- /dev/null +++ b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt @@ -0,0 +1,103 @@ +package content.area.asgarnia.dwarven_mines.living_rock_caverns + +import content.entity.effect.transform +import content.entity.player.bank.BankDeposit +import content.entity.player.dialogue.type.warning +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.ui.open +import world.gregs.voidps.engine.data.Settings +import world.gregs.voidps.engine.data.definition.Areas +import world.gregs.voidps.engine.data.definition.Tables +import world.gregs.voidps.engine.entity.World +import world.gregs.voidps.engine.entity.character.move.tele +import world.gregs.voidps.engine.entity.character.npc.NPCs +import world.gregs.voidps.engine.entity.obj.GameObjects +import world.gregs.voidps.engine.timer.toTicks +import world.gregs.voidps.type.Direction +import world.gregs.voidps.type.Tile +import world.gregs.voidps.type.random +import java.util.concurrent.TimeUnit + +class LivingRockCaverns : Script { + init { + objectOperate("Climb", "living_rock_caverns_entrance") { (target) -> + if (!warning("living_rock_caverns")) { + return@objectOperate + } + walkToDelay(target.tile) + face(Direction.WEST) + delay(1) + anim("living_rock_caverns_climb_ledge") + delay(2) + tele(3651, 5122) + val rope = GameObjects.find(Tile(3651, 5123), "living_rock_caverns_rope") + anim("living_rock_caverns_rope") // TODO proper anim + rope.anim("living_rock_caverns_rope_drop") + face(Direction.SOUTH) + delay(3) + } + + objectOperate("Climb", "living_rock_caverns_rope") { (target) -> + face(Direction.NORTH) + anim("living_rock_caverns_climb_rope") + delay(2) + tele(3012, 9832) + } + + worldSpawn { + update() + } + + settingsReload { + if (Settings["events.livingRockCaverns.respawnTimeMinutes", 60] > 0 && !World.contains("living_rock_caverns_timer")) { + update() + } else if (Settings["events.livingRockCaverns.respawnTimeMinutes", 60] <= 0 && World.contains("living_rock_caverns_timer")) { + World.clearQueue("living_rock_caverns_timer") + } + } + + objectOperate("Deposit", "pulley_lift") { + open("bank_deposit_box") + } + + itemOnObjectOperate(obj = "pulley_lift", handler = BankDeposit::itemOnDeposit) + } + + fun update() { + val minutes = Settings["events.livingRockCaverns.respawnTimeMinutes", 60] + rockSpawn(minutes, "coal") + rockSpawn(minutes, "gold") + if (minutes <= 0) { + return + } + World.queue("living_rock_caverns_timer", TimeUnit.MINUTES.toTicks(minutes)) { + var patriarchSpawned = false + for (region in Areas["living_rock_caverns"].toRegions()) { + for (npc in NPCs.at(region.toLevel(0))) { + if (npc.id == "living_rock_patriarch") { + if (npc.transform == "") { + patriarchSpawned = true + } else { + NPCs.remove(npc) + } + continue + } + npc.anim("${npc.id}_idle") + } + } + if (!patriarchSpawned) { + NPCs.add("living_rock_patriarch", Tables.tileList("living_rock_cavern_spawns.patriarch").random(random)) + } + } + } + + private fun rockSpawn(minutes: Int, type: String) { + val tiles = Tables.tileList("living_rock_cavern_spawns.$type.tiles") + .shuffled(random) + .take(Settings["events.livingRockCaverns.${type}Deposits", 1]) + for (tile in tiles) { + GameObjects.add("mineral_deposit_$type", tile, ticks = if (minutes <= 0) GameObjects.NEVER else TimeUnit.MINUTES.toTicks(minutes)) + } + } + +} \ No newline at end of file diff --git a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt new file mode 100644 index 0000000000..33d8605109 --- /dev/null +++ b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt @@ -0,0 +1,121 @@ +package content.area.asgarnia.dwarven_mines.living_rock_caverns + +import content.entity.combat.damageDealers +import content.entity.combat.dead +import content.entity.combat.killer +import content.entity.effect.clearTransform +import content.entity.effect.transform +import content.skill.mining.Pickaxe +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.client.variable.remaining +import world.gregs.voidps.engine.client.variable.start +import world.gregs.voidps.engine.entity.Spawn +import world.gregs.voidps.engine.entity.character.mode.EmptyMode +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.skill.Skill +import world.gregs.voidps.engine.entity.character.player.skill.exp.exp +import world.gregs.voidps.engine.entity.character.player.skill.level.Level.has +import world.gregs.voidps.engine.inv.add +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.engine.timer.Timer +import world.gregs.voidps.engine.timer.toTicks +import world.gregs.voidps.type.Tile +import world.gregs.voidps.type.random +import java.util.concurrent.TimeUnit +import kotlin.random.nextInt + +class LivingRockCreatures : Script { + init { + npcDeath("living_rock_*") { + it.respawn = false + } + + npcApproach("Mine", "living_rock_*_remains") { (target) -> + if (!target["public", false] && target.killer != this) { + // https://youtu.be/vLvQLkEnuao?t=156 + message("You must wait at least one minute before you can mine a living rock creature that someone else defeated.") + return@npcApproach + } + if (target["minerals", 0] <= 0) { + return@npcApproach + } + if (inventory.isFull() && !inventory.contains("living_minerals")) { + message("Your inventory is too full to hold any more minerals.") // TODO proper message + return@npcApproach + } + if (!has(Skill.Mining, 77, true)) { + return@npcApproach + } + val pickaxe = Pickaxe.bestRequirements(this, message = true) ?: return@npcApproach + val delay = if (pickaxe.id == "dragon_pickaxe" && random.nextInt(6) == 0) 2 else pickaxe.def["mining_delay", 8] + val remaining = remaining("action_delay") + if (remaining < 0) { + face(target) + anim("${pickaxe.id}_swing_low") + start("action_delay", delay) + pause(delay) + } else if (remaining > 0) { + pause(delay) + } + val amount = target["minerals", 0] + if (amount <= 0) { + return@npcApproach + } + if (inventory.add("living_minerals", amount)) { + target.clear("minerals") + clearAnim() + exp(Skill.Mining, 25.0) + message("You manage to mine some minerals.") // TODO proper message + target.anim("${target.id}_fade") + delay(2) + respawn(target) + } + } + + npcApproach("Prospect", "living_rock_*_remains") { (target) -> + approachRange(1) + arriveDelay() + message("These remains contains ${target["minerals", 0]} minerals.") // TODO proper message + } + + npcAfterDeath("living_rock_*") { + hide = false + dead = false + transform("${id}_remains") + set("minerals", random.nextInt(5..24)) + softTimers.start("decay_rock_remains") + } + + npcTimerStart("decay_rock_remains") { + TimeUnit.MINUTES.toTicks(1) + } + + npcTimerTick("decay_rock_remains") { + if (get("public", false)) { + respawn(this) + Timer.CANCEL + } else { + set("public", true) + Timer.CONTINUE + } + } + } + + fun respawn(npc: NPC) { + val respawn = npc.get("respawn_tile") + if (respawn != null) { + npc.clearAnim() + npc.clearTransform() + npc.damageDealers.clear() + npc.levels.clear() + npc.hide = false + npc.dead = false + npc.mode = EmptyMode + Spawn.npc(npc) + } else { + NPCs.remove(npc) + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/content/skill/mining/Mining.kt b/game/src/main/kotlin/content/skill/mining/Mining.kt index 5619fb71af..ca5ea6c480 100644 --- a/game/src/main/kotlin/content/skill/mining/Mining.kt +++ b/game/src/main/kotlin/content/skill/mining/Mining.kt @@ -5,6 +5,7 @@ import content.entity.player.bank.bank import net.pearx.kasechange.toLowerSpaceCase import world.gregs.voidps.engine.Script import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.client.ui.chat.plural import world.gregs.voidps.engine.client.variable.remaining import world.gregs.voidps.engine.client.variable.start import world.gregs.voidps.engine.client.variable.stop @@ -18,15 +19,15 @@ import world.gregs.voidps.engine.entity.character.player.equip.equipped import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.entity.character.player.skill.exp.exp import world.gregs.voidps.engine.entity.character.player.skill.level.Level.has -import world.gregs.voidps.engine.entity.character.player.skill.level.Level.hasRequirementsToUse import world.gregs.voidps.engine.entity.character.player.skill.level.Level.success -import world.gregs.voidps.engine.entity.item.Item +import world.gregs.voidps.engine.entity.item.floor.FloorItems import world.gregs.voidps.engine.entity.obj.GameObject import world.gregs.voidps.engine.entity.obj.GameObjects -import world.gregs.voidps.engine.inv.add +import world.gregs.voidps.engine.inv.addToLimit import world.gregs.voidps.engine.inv.inventory import world.gregs.voidps.network.login.protocol.visual.update.player.EquipSlot import world.gregs.voidps.type.random +import kotlin.random.nextInt class Mining : Script { @@ -67,11 +68,7 @@ class Mining : Script { break } - val pickaxe = Pickaxe.best(this) - if (!hasRequirements(this, pickaxe, true) || pickaxe == null) { - break - } - + val pickaxe = Pickaxe.bestRequirements(this, message = true) ?: break val delay = if (pickaxe.id == "dragon_pickaxe" && random.nextInt(6) == 0) 2 else pickaxe.def["mining_delay", 8] if (first) { message("You swing your pickaxe at the rock.", ChatType.Filter) @@ -92,7 +89,7 @@ class Mining : Script { if (ore.bool("gems")) { val glory = equipped(EquipSlot.Amulet).id.startsWith("amulet_of_glory_") if (success(levels.get(Skill.Mining), if (glory) 3..3 else 1..1)) { - addOre(this, gems.random()) + addOre(this, gems.random(), target) continue } } @@ -107,9 +104,12 @@ class Mining : Script { val chance = ore.intRange("chance") if (success(levels.get(Skill.Mining), chance)) { val xp = ore.int("xp") / 10.0 - exp(Skill.Mining, xp) ShootingStarHandler.extraOreHandler(this, item, xp) - if (!addOre(this, item) || deplete(target, ore.int("life"))) { + val added = addOre(this, item, target) + if (added > 0) { + exp(Skill.Mining, xp * added) + } + if (added < 1 || deplete(target, ore.int("life"))) { clearAnim() break } @@ -127,11 +127,12 @@ class Mining : Script { message("There is currently no ore available in this rock.") return@objectApproach } - if (queue.contains("prospect")) { - return@objectApproach - } message("You examine the rock for ores...") delay(4) + if (target.id.startsWith("mineral_deposit_")) { + message("This rock contains ${target.id.removePrefix("mineral_deposit_").toLowerSpaceCase()}.") + return@objectApproach + } val ore = Rows.getOrNull("ores.${target.def(this).stringId}") if (ore == null) { message("This rock contains no ore.") @@ -141,40 +142,59 @@ class Mining : Script { } } - fun hasRequirements(player: Player, pickaxe: Item?, message: Boolean = false): Boolean { - if (pickaxe == null) { - if (message) { - player.message("You need a pickaxe to mine this rock.") - player.message("You do not have a pickaxe which you have the mining level to use.") - } - return false - } - return player.hasRequirementsToUse(pickaxe, message, setOf(Skill.Mining, Skill.Firemaking)) - } - - fun addOre(player: Player, ore: String): Boolean { + fun addOre(player: Player, ore: String, target: GameObject): Int { if (ore == "stardust") { ShootingStarHandler.addStarDustCollected() val totalStarDust = player.inventory.count(ore) + player.bank.count(ore) if (totalStarDust >= 200) { player.message("You have the maximum amount of stardust but was still rewarded experience.") - return true + return -1 } } - val added = player.inventory.add(ore) - if (added) { - player.message("You manage to mine some ${ore.toLowerSpaceCase()}.") - } else { - player.inventoryFull() + var amount = when (target.id) { + "mineral_deposit_gold" -> random.nextInt(1..4) + "mineral_deposit_coal" -> random.nextInt(1..2) + else -> 1 + } + val added = player.inventory.addToLimit(ore, amount) + when (added) { + 1 -> player.message("You manage to mine some ${ore.toLowerSpaceCase()}.") + 2 -> player.message("You manage to mine two ${ore.toLowerSpaceCase().plural(added)}!") + 3 -> player.message("You manage to mine three ${ore.toLowerSpaceCase().plural(added)}!") + else -> player.inventoryFull() + } + if (diaryDoubleOre(player, ore)) { + player.message("Your Varrock armour allows you to mine an additional ore.") + amount++ + } + if (added < amount) { + FloorItems.add(player.tile, ore, amount - added) + return amount } return added } + private fun diaryDoubleOre(player: Player, ore: String): Boolean { + val level1 = ore == "copper_ore" || ore == "tin_ore" || ore == "iron_ore" || ore == "coal" + val level2 = level1 || ore == "mithril_ore" + val level3 = level2 || ore == "adamant_ore" + return when (player.equipped(EquipSlot.Chest).id) { + "varrock_armour_1" if (level1 && random.nextInt(100) < 8) -> true + "varrock_armour_2" if (level2 && random.nextInt(100) < 10) -> true + "varrock_armour_3" if (level3 && random.nextInt(100) < 12) -> true + "varrock_armour_4" if (level3 && random.nextInt(100) < 14) -> true + else -> false + } + } + fun deplete(obj: GameObject, life: Int): Boolean { if (obj.id.startsWith("crashed_star_tier_")) { ShootingStarHandler.handleMinedStarDust(obj) return false } + if (obj.id.startsWith("mineral_deposit_")) { + return false + } if (life >= 0) { GameObjects.replace(obj, "depleted${obj.id.dropWhile { it != '_' }}", ticks = life) return true diff --git a/game/src/main/kotlin/content/skill/mining/Pickaxe.kt b/game/src/main/kotlin/content/skill/mining/Pickaxe.kt index cae2265009..dc939e56f1 100644 --- a/game/src/main/kotlin/content/skill/mining/Pickaxe.kt +++ b/game/src/main/kotlin/content/skill/mining/Pickaxe.kt @@ -1,5 +1,6 @@ package content.skill.mining +import world.gregs.voidps.engine.client.message import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.entity.character.player.skill.level.Level.hasRequirementsToUse @@ -21,4 +22,19 @@ object Pickaxe { ) fun best(player: Player): Item? = pickaxes.firstOrNull { pickaxe -> player.hasRequirementsToUse(pickaxe, skills = setOf(Skill.Mining, Skill.Firemaking)) && player.carriesItem(pickaxe.id) } + + fun bestRequirements(player: Player, message: Boolean = false): Item? { + val pickaxe = best(player) + if (pickaxe == null) { + if (message) { + player.message("You need a pickaxe to mine this rock.") + player.message("You do not have a pickaxe which you have the mining level to use.") + } + return null + } + if (player.hasRequirementsToUse(pickaxe, message, setOf(Skill.Mining, Skill.Firemaking))) { + return pickaxe + } + return null + } } diff --git a/game/src/main/resources/game.properties b/game/src/main/resources/game.properties index 32a740bfe7..9905ae84b5 100644 --- a/game/src/main/resources/game.properties +++ b/game/src/main/resources/game.properties @@ -244,6 +244,15 @@ grandExchange.instantBuyOverMarketPrice=0.0 # Wave to start all fight caves on (63 for jad) fightCave.startWave = 1 +# How frequently to respawn living rock cavern deposits and Rock Patriarch (-1 for never) +events.livingRockCaverns.respawnTimeMinutes=60 + +# Number of living rock caverns coal spawns (7 for all) +events.livingRockCaverns.coalDeposits=2 + +# Number of living rock caverns gold spawns (4 for all) +events.livingRockCaverns.goldDeposits=1 + #=================================== # AI & Bots #=================================== From 5d54166ba650f0cd223dcfaaabd5fdcc0ccdcfe8 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 20:52:31 +0100 Subject: [PATCH 12/14] Add living rock creatures task --- data/skill/slayer/master/kuradal.tables.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/skill/slayer/master/kuradal.tables.toml b/data/skill/slayer/master/kuradal.tables.toml index 6e5dea5921..a08e6a823f 100644 --- a/data/skill/slayer/master/kuradal.tables.toml +++ b/data/skill/slayer/master/kuradal.tables.toml @@ -108,10 +108,10 @@ amount = [170, 250] weight = 5 tip = "Kalphites are large insects that live in hives under the desert sands. I am sure that, by now, you have seen them to the south-west of Shantay Pass." -#[.living_rock_creatures] -#amount = [120, 170] -#weight = 10 -#tip = "Found beneath the Dwarven mines, these are tough beings of rock. They can use ranged or melee attacks against you, so plan accordingly!" +[.living_rock_creatures] +amount = [120, 170] +weight = 10 +tip = "Found beneath the Dwarven mines, these are tough beings of rock. They can use ranged or melee attacks against you, so plan accordingly!" [.mithril_dragons] amount = [30, 35] From 76961d6cb10c7c7c8bc642e91685e10f0c20e7a5 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 20:53:28 +0100 Subject: [PATCH 13/14] Formatting --- .../dwarven_mines/living_rock_caverns/Farli.kt | 2 +- .../living_rock_caverns/LivingRockCaverns.kt | 3 +-- .../living_rock_caverns/LivingRockCreatures.kt | 2 +- .../content/area/morytania/mort_ton/Afflicted.kt | 14 ++++++++------ .../content/entity/player/bank/BankDeposit.kt | 1 - 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt index 30c6e1d6b4..41d0525389 100644 --- a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt +++ b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/Farli.kt @@ -88,4 +88,4 @@ class Farli : Script { npc("Hmph! How rude!", title = name) } } -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt index 181ef5c438..7548407a55 100644 --- a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt +++ b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt @@ -99,5 +99,4 @@ class LivingRockCaverns : Script { GameObjects.add("mineral_deposit_$type", tile, ticks = if (minutes <= 0) GameObjects.NEVER else TimeUnit.MINUTES.toTicks(minutes)) } } - -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt index 33d8605109..adab339113 100644 --- a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt +++ b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCreatures.kt @@ -118,4 +118,4 @@ class LivingRockCreatures : Script { NPCs.remove(npc) } } -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt b/game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt index b3bccf34cd..f10e9a4abb 100644 --- a/game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt +++ b/game/src/main/kotlin/content/area/morytania/mort_ton/Afflicted.kt @@ -9,12 +9,14 @@ class Afflicted : Script { init { npcOperate("Talk-to", "afflicted*") { val words = setOf("ughugh", "knows'is", "nots", "pirsl", "wot's", "zurgle", "gurghl", "mee's", "seysyi", "sfriess", "says") - npc(buildString { - repeat(random.nextInt(1, 7)) { - append(words.random()) - append(" ") - } - }) + npc( + buildString { + repeat(random.nextInt(1, 7)) { + append(words.random()) + append(" ") + } + }, + ) npc("~ This person doesn't make any sense at all. ~") } } diff --git a/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt b/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt index 1290e8cc25..72f924b8f2 100644 --- a/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt +++ b/game/src/main/kotlin/content/entity/player/bank/BankDeposit.kt @@ -102,7 +102,6 @@ class BankDeposit : Script { } } - fun bankAll(player: Player, inventory: Inventory) { for (index in inventory.indices) { val item = inventory[index] From 83cb8836668bcae56766574340cb752174c0f451 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 30 Mar 2026 21:09:39 +0100 Subject: [PATCH 14/14] Fix living rock caverns event disabling in tests --- .../dwarven_mines/living_rock_caverns/LivingRockCaverns.kt | 5 ++++- game/src/main/resources/game.properties | 2 +- game/src/test/kotlin/WorldTest.kt | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt index 7548407a55..dd924a939d 100644 --- a/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt +++ b/game/src/main/kotlin/content/area/asgarnia/dwarven_mines/living_rock_caverns/LivingRockCaverns.kt @@ -65,9 +65,12 @@ class LivingRockCaverns : Script { fun update() { val minutes = Settings["events.livingRockCaverns.respawnTimeMinutes", 60] + if (minutes < 0) { + return + } rockSpawn(minutes, "coal") rockSpawn(minutes, "gold") - if (minutes <= 0) { + if (minutes == 0) { return } World.queue("living_rock_caverns_timer", TimeUnit.MINUTES.toTicks(minutes)) { diff --git a/game/src/main/resources/game.properties b/game/src/main/resources/game.properties index 9905ae84b5..21c351d540 100644 --- a/game/src/main/resources/game.properties +++ b/game/src/main/resources/game.properties @@ -244,7 +244,7 @@ grandExchange.instantBuyOverMarketPrice=0.0 # Wave to start all fight caves on (63 for jad) fightCave.startWave = 1 -# How frequently to respawn living rock cavern deposits and Rock Patriarch (-1 for never) +# How frequently to respawn living rock cavern deposits and Rock Patriarch (0 = never respawn, -1 = completely disabled) events.livingRockCaverns.respawnTimeMinutes=60 # Number of living rock caverns coal spawns (7 for all) diff --git a/game/src/test/kotlin/WorldTest.kt b/game/src/test/kotlin/WorldTest.kt index 7e6bf5439b..39597dd43b 100644 --- a/game/src/test/kotlin/WorldTest.kt +++ b/game/src/test/kotlin/WorldTest.kt @@ -290,6 +290,7 @@ abstract class WorldTest : KoinTest { properties["grandExchange.priceLimit"] = true properties["world.npcs.randomWalk"] = false properties["events.shootingStars.enabled"] = false + properties["events.livingRockCaverns.respawnTimeMinutes"] = "-1" properties["events.penguinHideAndSeek.enabled"] = false properties["storage.autoSave.minutes"] = 0 properties["storage.disabled"] = true