From a56ae7595b6845ded78e6ba79ab8781d9b641792 Mon Sep 17 00:00:00 2001 From: GregHib Date: Fri, 27 Mar 2026 20:57:01 +0000 Subject: [PATCH 1/8] Start adding dungeon and bosses --- .../dungeon/pollninveach_dungeon.npcs.toml | 81 +++++++++++++++++++ .../dungeon/pollnivneach_dungeon.anims.toml | 17 ++++ .../dungeon/pollnivneach_dungeon.combat.toml | 67 +++++++++++++++ .../dungeon/pollnivneach_dungeon.gfx.toml | 26 ++++++ .../dungeon/pollnivneach_dungeon.objs.toml | 17 ++++ .../dungeon/pollnivneach_dungeon.teles.toml | 59 ++++++++++++++ .../pollnivneach/pollnivneach.objs.toml | 9 +++ .../pollnivneach/pollnivneach.teles.toml | 20 +++++ .../dungeon/PollnivneachDungeon.kt | 81 +++++++++++++++++++ 9 files changed, 377 insertions(+) create mode 100644 data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.anims.toml create mode 100644 data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml create mode 100644 data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml create mode 100644 data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.objs.toml create mode 100644 data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.teles.toml create mode 100644 game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml index 74bad03152..85df628e4a 100644 --- a/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml @@ -40,3 +40,84 @@ id = 13215 [iwazaru_pollninveach_dungeon_2] id = 13226 + +[monsterous_cave_crawler] +id = 7798 +examine = "It oozes venom from every pore." + +[kurask_overlord] +id = 7797 +hitpoints = 2500 +slayer_level = 70 +slayer_xp = 1000.0 +# Made up stats +att = 220 +str = 220 +def = 200 +categories = ["kurask"] +hunt_mode = "aggressive" +combat_def = "kurask" +max_hit_crush = 300 +examine = "A bulky Kurask." + +[kurask_minion] +id = 7805 +hitpoints = 950 +slayer_level = 70 +slayer_xp = 95.0 +# Made up stats +att = 150 +str = 150 +def = 100 +categories = ["kurask"] +hunt_mode = "aggressive" +combat_def = "kurask_minion" +drop_table = "bones" +examine = "Large, heavy, with sharp things attached to its head." + +[basilisk_boss] +id = 7799 +hitpoints = 2700 +slayer_level = 40 +slayer_xp = 1000.0 +# Made up stats +att = 200 +str = 200 +def = 175 +magic = 210 +categories = ["basilisk"] +hunt_mode = "aggressive" +combat_def = "basilisk_boss" +drop_table = "bones" +examine = "It radiates an unhealthy aura." + +[turoth_mightiest] +id = 7800 +hitpoints = 1750 +slayer_level = 55 +slayer_xp = 1000.0 +# Made up stats +att = 160 +str = 180 +def = 150 +categories = ["turoth"] +# max hit = 165 +immune_poison = true +hunt_mode = "aggressive" +combat_def = "mightiest_turoth" +examine = "Something tells you it has many minions" + +[turoth_swarming] +id = 1611 +hitpoints = 100 +slayer_level = 55 +slayer_xp = 10.0 +# Made up stats +att = 100 +str = 100 +def = 80 +drop_table = "bones" +hunt_mode = "aggressive" +combat_def = "turoth_small" +max_hit_stab = 110 +examine = "A vicious bite on a feeble body." \ No newline at end of file diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.anims.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.anims.toml new file mode 100644 index 0000000000..db66a9399d --- /dev/null +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.anims.toml @@ -0,0 +1,17 @@ +[monstrous_cave_crawler_attack] +id = 9414 + +[monstrous_cave_crawler_defend] +id = 9416 + +[monstrous_cave_crawler_death] +id = 9418 + +[monstrous_cave_crawler_fling] +id = 9419 + +[basilisk_boss_attack] +id = 9533 + +[mightest_turoth_attack] +id = 9413 \ No newline at end of file diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml new file mode 100644 index 0000000000..059ba06729 --- /dev/null +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml @@ -0,0 +1,67 @@ +[monstrous_cave_crawler] +attack_speed = 4 +retreat_range = 8 +defend_anim = "monstrous_cave_crawler_defend" +defend_sound = "cave_crawler_defend" +death_anim = "monstrous_cave_crawler_death" +death_sound = "cave_crawler_death" + +[monstrous_cave_crawler.melee] +range = 1 +anim = "monstrous_cave_crawler_attack" +target_sound = "cave_crawler_attack" +target_hit = { offense = "stab", max = 240 } + +[monstrous_cave_crawler.poison] +range = 8 +anim = "monstrous_cave_crawler_fling" +gfx = "monstrous_cave_crawler_cast" +target_sound = "cave_crawler_attack" +projectile = "monstrous_cave_crawler_travel" +impact_gfx = "monstrous_cave_crawler_impact" +target_hit = { offense = "range", max = 240 } +impact_poison = 80 + +[kurask_minion] +attack_speed = 6 +clone = "kurask" + +[kurask_minion.attack] +clone = "kurask.attack" +target_hit = { offense = "crush", max = 110 } + +[basilisk_boss] +attack_speed = 4 +retreat_range = 8 +defend_anim = "basilisk_defend" +defend_sound = "basilisk_defend" +death_anim = "basilisk_death" +death_sound = "basilisk_death" + +[basilisk_boss.attack] +condition = "mirror_shield" +anim = "basilisk_attack" +target_sound = "basilisk_attack" +target_hit = { offense = "slash", max = 300 } + +[basilisk_boss.piercing_gaze] +clone = "basilisk.piercing_gaze" + +[basilisk_boss.gaze] +condition = "mirror_shield" +anim = "basilisk_boss_attack" +gfx = "basilisk_boss_cast" +projectile = "basilisk_boss_travel" +target_hit = { offense = "magic", max = 300 } +impact_gfx = "basilisk_boss_impact" +impact_drains = [ + { skill = "random", min = 1, max = 3 }, +] + +[mightiest_turoth] +clone = "turoth_large" + +[mightiest_turoth.attack] +anim = "mightest_turoth_attack" +target_sound = "turoth_attack" +target_hit = { offense = "stab", max = 165 } diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml new file mode 100644 index 0000000000..3455ec3936 --- /dev/null +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml @@ -0,0 +1,26 @@ +[pass_barrier_red] +id = 1659 + +[basilisk_boss_cast] +id = 1662 + +[basilisk_boss_travel] +id = 1663 + +[basilisk_boss_impact] +id = 1664 + +[monstrous_cave_crawler_cast] +id = 1653 + +[monstrous_cave_crawler_travel] +id = 1654 + +[monstrous_cave_crawler_impact] +id = 1655 + +[mightiest_turoth_spawn] +id = 1638 + +[turoth_minion_spawn] +id = 1639 diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.objs.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.objs.toml new file mode 100644 index 0000000000..f77c325869 --- /dev/null +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.objs.toml @@ -0,0 +1,17 @@ +[pollnivneach_bucket_rope] +id = 31316 + +[pollnivneach_dungeon_barrier] +id = 31435 + +[pollnivneach_dungeon_barrier_north] +id = 31436 + +[pollnivneach_stairs_down] +id = 31412 + +[pollnivneach_stairs_up] +id = 31417 + +[pollnivneach_markings] +id = 31363 \ No newline at end of file diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.teles.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.teles.toml new file mode 100644 index 0000000000..b8501c3333 --- /dev/null +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.teles.toml @@ -0,0 +1,59 @@ +[pollnivneach_stairs_down] +option = "Climb-down" +tile = { x = 3377, y = 9367 } +to = { x = 3322, y = 4340 } + +[pollnivneach_stairs_up] +option = "Climb-up" +tile = { x = 3318, y = 4339 } +to = { x = 3376, y = 9368 } + +[pollnivneach_stairs_down] +option = "Climb-down" +tile = { x = 3338, y = 9368 } +to = { x = 3270, y = 4340 } + +[pollnivneach_stairs_up] +option = "Climb-up" +tile = { x = 3271, y = 4339 } +to = { x = 3342, y = 9369 } + +[pollnivneach_stairs_down] +option = "Climb-down" +tile = { x = 3340, y = 9426 } +to = { x = 3276, y = 4368 } + +[pollnivneach_stairs_up] +option = "Climb-up" +tile = { x = 3277, y = 4367 } +to = { x = 3344, y = 9427 } + +[pollnivneach_stairs_down] +option = "Climb-down" +tile = { x = 3374, y = 9426 } +to = { x = 3321, y = 4365 } + +[pollnivneach_stairs_up] +option = "Climb-up" +tile = { x = 3317, y = 4364 } +to = { x = 3373, y = 9427 } + +[pollnivneach_markings] +option = "Enter" +tile = { x = 3294, y = 4293 } +to = { x = 2741, y = 10008 } + +[pollnivneach_markings] +option = "Enter" +tile = { x = 3325, y = 4391 } +to = { x = 2800, y = 9998 } + +[pollnivneach_markings] +option = "Enter" +tile = { x = 3295, y = 4407 } +to = { x = 2703, y = 9995 } + +[pollnivneach_markings] +option = "Enter" +tile = { x = 3288, y = 4293 } +to = { x = 2714, y = 10012 } diff --git a/data/area/kharidian_desert/pollnivneach/pollnivneach.objs.toml b/data/area/kharidian_desert/pollnivneach/pollnivneach.objs.toml index b810c29063..323154c6f9 100644 --- a/data/area/kharidian_desert/pollnivneach/pollnivneach.objs.toml +++ b/data/area/kharidian_desert/pollnivneach/pollnivneach.objs.toml @@ -3,3 +3,12 @@ id = 36002 [smoke_dungeon_rope] id = 6439 + +[pollnivneach_well] +id = 31359 + +[dark_stairs] +id = 31390 + +[smoke_dungeon_dark_hole] +id = 31367 \ No newline at end of file diff --git a/data/area/kharidian_desert/pollnivneach/pollnivneach.teles.toml b/data/area/kharidian_desert/pollnivneach/pollnivneach.teles.toml index 0df242809d..9edd990362 100644 --- a/data/area/kharidian_desert/pollnivneach/pollnivneach.teles.toml +++ b/data/area/kharidian_desert/pollnivneach/pollnivneach.teles.toml @@ -7,3 +7,23 @@ to = { x = 3206, y = 9379 } option = "Climb-up" tile = { x = 3205, y = 9379 } to = { x = 3310, y = 2961 } + +[pollnivneach_bucket_rope] +option = "Climb-up" +tile = { x = 3358, y = 9352 } +to = { x = 3359, y = 2970 } + +[pollnivneach_well] +option = "Climb-down" +tile = { x = 3358, y = 2971 } +to = { x = 3358, y = 9354 } + +[dark_stairs] +option = "Enter" +tile = { x = 3337, y = 9350 } +to = { x = 3318, y = 9355 } + +[smoke_dungeon_dark_hole] +option = "Enter" +tile = { x = 3318, y = 9356 } +to = { x = 3338, y = 9350 } diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt new file mode 100644 index 0000000000..6574639bd5 --- /dev/null +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt @@ -0,0 +1,81 @@ +package content.area.kharidian_desert.pollnivneach.dungeon + +import content.entity.combat.killer +import content.entity.player.dialogue.type.choice +import content.entity.player.dialogue.type.statement +import content.quest.instanceOffset +import content.quest.setInstanceLogout +import content.quest.smallInstance +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.entity.character.move.tele +import world.gregs.voidps.engine.entity.character.npc.NPCs +import world.gregs.voidps.engine.map.instance.Instances +import world.gregs.voidps.engine.queue.softQueue +import world.gregs.voidps.type.Region +import world.gregs.voidps.type.Tile + +class PollnivneachDungeon : Script { + init { + // TODO barrier gfx + objectOperate("Pass", "pollnivneach_dungeon_barrier") { (target) -> + statement("This portal leads to the lair of a ferocious creature. Are you sure you want to do battle?") + choice("Do you want to head into the fray?") { + option("Yes, I feel brave.") { + smallInstance(Region(12356)) +// setInstanceLogout() + val offset = instanceOffset() + + tele(offset.add(3127, 4373)) + val boss = NPCs.add("monsterous_cave_crawler", Tile(3121, 4384)) + + message("Your surroundings shift to become familiar, as you face a powerful turoth.") +// tele(offset.add(3089, 4318)) +// val boss = NPCs.add("mightiest_turoth", Tile(3088, 4324)) + + message("Your surroundings shift to become familiar, as you face a powerful basilisk.") +// tele(offset.add(3123, 4333)) +// val boss = NPCs.add("basalisk_boss", Tile(3115, 4322)) + + message("Your surroundings shift to become familiar, as you face a powerful kurask.") +// tele(offset.add(3089, 4322)) +// val boss = NPCs.add("kurask_overlord", Tile(3091, 4323)) + + // 1447 + + } + option("No way!") + } + face(target) + val x = if (tile.x <= target.tile.x) target.tile.x + 1 else target.tile.x - 1 + val y = tile.y.coerceIn(target.tile.y, target.tile.y + 2) + walkOverDelay(tile.copy(y = y)) + message("You pass through the mystic barrier, which feels odd.") + anim("pass_through_barrier") + gfx("pass_barrier_red") + exactMoveDelay(Tile(x, y), delay = 30) + } + + npcDespawn("monsterous_cave_crawler") { + val killer = killer + softQueue("shift_back") { +// statment("You shift back to reality, having defeated this boss. You may now pass this barrier freely.") + } + } + + objectOperate("Pass", "pollnivneach_dungeon_barrier_north") { (target) -> + face(target) + val x = tile.x.coerceIn(target.tile.x, target.tile.x + 2) + val y = if (tile.y <= target.tile.y) target.tile.y + 1 else target.tile.y - 1 + walkOverDelay(tile.copy(x = x)) + anim("pass_through_barrier") + gfx("pass_barrier_red") + exactMoveDelay(Tile(x, y), delay = 30) + } + + objTeleportLand("Climb-down", "pollnivneach_well") { _, _ -> + message("You descend into the somewhat smoky depths of the well, to the accompaniment of eery wails.") + } + + } +} \ No newline at end of file From a77a8382d8bbebcd14f8c28b1ff0cc09921930c3 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 28 Mar 2026 11:39:32 +0000 Subject: [PATCH 2/8] Add support for tile columns --- .../engine/data/config/RowDefinition.kt | 4 ++ .../engine/data/definition/ColumnReader.kt | 20 ++++++++ .../voidps/engine/data/definition/Tables.kt | 8 ++++ .../engine/data/definition/TablesTest.kt | 46 +++++++++++-------- .../engine/data/definition/test-table.toml | 2 + 5 files changed, 61 insertions(+), 19 deletions(-) diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt index 4430c22b50..f68a90713a 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt @@ -23,6 +23,10 @@ data class RowDefinition( fun skillPairOrNull(column: String) = Tables.skillPairOrNull("${stringId}.$column") + fun tile(column: String) = Tables.tile("${stringId}.$column") + + fun tileOrNull(column: String) = Tables.tileOrNull("${stringId}.$column") + fun intList(column: String) = Tables.intList("${stringId}.$column") fun intListOrNull(column: String) = Tables.intListOrNull("${stringId}.$column") diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/ColumnReader.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/ColumnReader.kt index 49eca21a55..1b562087a0 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/ColumnReader.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/ColumnReader.kt @@ -2,6 +2,7 @@ package world.gregs.voidps.engine.data.definition import world.gregs.config.ConfigReader import world.gregs.voidps.engine.entity.character.player.skill.Skill +import world.gregs.voidps.type.Tile sealed interface ColumnReader { val type: ColumnType @@ -20,6 +21,24 @@ sealed interface ColumnReader { override fun read(reader: ConfigReader) = reader.int() } + object ReaderTile : ColumnReader { + override val type = ColumnType.ColumnInt + override fun list() = mutableListOf() + override fun read(reader: ConfigReader): Int { + var x = 0 + var y = 0 + var level = 0 + while (reader.nextEntry()) { + when (reader.key()) { + "x" -> x = reader.int() + "y" -> y = reader.int() + "level" -> level = reader.int() + } + } + return Tile.id(x, y, level) + } + } + object ReaderIntRange : ColumnReader { override val type = ColumnType.ColumnIntRange override fun list() = mutableListOf() @@ -90,6 +109,7 @@ sealed interface ColumnReader { "boolean" -> ReaderBoolean "int" -> ReaderInt "range" -> ReaderIntRange + "tile" -> ReaderTile "string" -> ReaderString "skill" -> ReaderEntity(Skill.map) "npc" -> ReaderEntity(NPCDefinitions.ids) 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 8a528bd50a..2f508b779e 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 @@ -7,6 +7,7 @@ import world.gregs.voidps.engine.data.config.RowDefinition import world.gregs.voidps.engine.data.config.TableDefinition import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.timedLoad +import world.gregs.voidps.type.Tile import kotlin.collections.set import kotlin.math.exp @@ -65,6 +66,13 @@ object Tables { return item.stringId } + fun tile(path: String): Tile = Tile(get(path, ColumnType.ColumnInt)) + + fun tileOrNull(path: String): Tile? { + val id = getOrNull(path, ColumnType.ColumnInt) ?: return null + return Tile(id) + } + fun obj(path: String): String = ObjectDefinitions.get(get(path, ColumnType.ColumnEntity)).stringId fun objOrNull(path: String): String? { diff --git a/engine/src/test/kotlin/world/gregs/voidps/engine/data/definition/TablesTest.kt b/engine/src/test/kotlin/world/gregs/voidps/engine/data/definition/TablesTest.kt index 8b1144f437..2f504be255 100644 --- a/engine/src/test/kotlin/world/gregs/voidps/engine/data/definition/TablesTest.kt +++ b/engine/src/test/kotlin/world/gregs/voidps/engine/data/definition/TablesTest.kt @@ -6,6 +6,7 @@ import world.gregs.voidps.cache.definition.data.ItemDefinition import world.gregs.voidps.cache.definition.data.NPCDefinition import world.gregs.voidps.cache.definition.data.ObjectDefinition import world.gregs.voidps.engine.data.config.TableDefinition +import world.gregs.voidps.type.Tile import kotlin.test.assertContentEquals import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -32,22 +33,23 @@ class TablesTest { assertNotNull(definition) assertColumns( listOf( - Field("int_field", ColumnType.ColumnInt, 0), // int_field - Field("string_field", ColumnType.ColumnString, ""), // string_field - Field("item_field", ColumnType.ColumnEntity, -1), // item_field - Field("obj_field", ColumnType.ColumnEntity, -1), // obj_field - Field("npc_field", ColumnType.ColumnEntity, -1), // npc_field - Field("int_list", ColumnType.ColumnList(ColumnType.ColumnInt), emptyList()), // int_list - Field("str_list", ColumnType.ColumnList(ColumnType.ColumnString), emptyList()), // str_list - Field("item_list", ColumnType.ColumnList(ColumnType.ColumnEntity), emptyList()), // item_list - Field("obj_list", ColumnType.ColumnList(ColumnType.ColumnEntity), emptyList()), // obj_list - Field("npc_list", ColumnType.ColumnList(ColumnType.ColumnEntity), emptyList()), // npc_list - Field("int_int", ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnInt), Pair(0, 0)), // int_int - Field("str_int", ColumnType.ColumnPair(ColumnType.ColumnString, ColumnType.ColumnInt), Pair("", 0)), // str_int - Field("int_str", ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnString), Pair(0, "")), // int_str - Field("int_int_list", ColumnType.ColumnList(ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnInt)), emptyList>()), // int_int_list - Field("str_int_list", ColumnType.ColumnList(ColumnType.ColumnPair(ColumnType.ColumnString, ColumnType.ColumnInt)), emptyList>()), // str_int_list - Field("int_str_list", ColumnType.ColumnList(ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnString)), emptyList>()), // int_str_list + Field("int_field", ColumnType.ColumnInt, 0), + Field("string_field", ColumnType.ColumnString, ""), + Field("item_field", ColumnType.ColumnEntity, -1), + Field("obj_field", ColumnType.ColumnEntity, -1), + Field("npc_field", ColumnType.ColumnEntity, -1), + Field("tile_field", ColumnType.ColumnInt, 0), + Field("int_list", ColumnType.ColumnList(ColumnType.ColumnInt), emptyList()), + Field("str_list", ColumnType.ColumnList(ColumnType.ColumnString), emptyList()), + Field("item_list", ColumnType.ColumnList(ColumnType.ColumnEntity), emptyList()), + Field("obj_list", ColumnType.ColumnList(ColumnType.ColumnEntity), emptyList()), + Field("npc_list", ColumnType.ColumnList(ColumnType.ColumnEntity), emptyList()), + Field("int_int", ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnInt), Pair(0, 0)), + Field("str_int", ColumnType.ColumnPair(ColumnType.ColumnString, ColumnType.ColumnInt), Pair("", 0)), + Field("int_str", ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnString), Pair(0, "")), + Field("int_int_list", ColumnType.ColumnList(ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnInt)), emptyList>()), + Field("str_int_list", ColumnType.ColumnList(ColumnType.ColumnPair(ColumnType.ColumnString, ColumnType.ColumnInt)), emptyList>()), + Field("int_str_list", ColumnType.ColumnList(ColumnType.ColumnPair(ColumnType.ColumnInt, ColumnType.ColumnString)), emptyList>()), ), definition ) assertContentEquals(intArrayOf(0, 1), definition.rows) @@ -58,9 +60,10 @@ class TablesTest { val expected = arrayOf( 1, "text", - 0, - 0, - 0, + 0, // item_field + 0, // obj_field + 0, // npc_field + Tile.id(1, 2, 3), // tile_field listOf(1, 2, 3), // int list listOf("one", "two"), // str list listOf(0), // item list @@ -83,6 +86,8 @@ class TablesTest { assertEquals("text", Tables.string("header.row.string_field")) assertEquals("item_id", Tables.item("header.row.item_field")) assertEquals("obj_id", Tables.obj("header.row.obj_field")) + assertEquals("npc_id", Tables.npc("header.row.npc_field")) + assertEquals(Tile(1, 2, 3), Tables.tile("header.row.tile_field")) assertEquals(listOf(1, 2, 3), Tables.intList("header.row.int_list")) assertEquals(listOf("one", "two"), Tables.stringList("header.row.str_list")) assertEquals(listOf("item_id"), Tables.itemList("header.row.item_list")) @@ -97,6 +102,9 @@ class TablesTest { assertEquals(0, Tables.int("header.row_two.int_field")) assertEquals("", Tables.string("header.row_two.string_field")) assertEquals("", Tables.item("header.row_two.item_field")) + assertEquals("", Tables.obj("header.row_two.obj_field")) + assertEquals("", Tables.npc("header.row_two.npc_field")) + assertEquals(Tile.EMPTY, Tables.tile("header.row_two.tile_field")) assertEquals(emptyList(), Tables.intList("header.row_two.int_list")) assertEquals(emptyList(), Tables.stringList("header.row_two.str_list")) assertEquals(emptyList(), Tables.itemList("header.row_two.item_list")) diff --git a/engine/src/test/resources/world/gregs/voidps/engine/data/definition/test-table.toml b/engine/src/test/resources/world/gregs/voidps/engine/data/definition/test-table.toml index 7a65fa97c3..4551ea88e9 100644 --- a/engine/src/test/resources/world/gregs/voidps/engine/data/definition/test-table.toml +++ b/engine/src/test/resources/world/gregs/voidps/engine/data/definition/test-table.toml @@ -4,6 +4,7 @@ string_field = "string" item_field = "item" obj_field = "obj" npc_field = "npc" +tile_field = "tile" int_list = "list" str_list = "list" item_list = "list" @@ -22,6 +23,7 @@ int_field = 1 item_field = "item_id" obj_field = "obj_id" npc_field = "npc_id" +tile_field = { x = 1, y = 2, level = 3 } int_list = [1, 2, 3] str_list = ["one", "two"] item_list = ["item_id"] From 801de046c1e3b223e6c888dfb4fb535e12f36ca4 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 28 Mar 2026 12:25:51 +0000 Subject: [PATCH 3/8] Tweak how death is handled --- .../engine/data/config/RowDefinition.kt | 4 ++++ .../content/entity/death/CharacterDeath.kt | 22 ------------------- .../kotlin/content/entity/death/NPCDeath.kt | 7 +++++- .../content/entity/death/PlayerDeath.kt | 7 +++++- 4 files changed, 16 insertions(+), 24 deletions(-) delete mode 100644 game/src/main/kotlin/content/entity/death/CharacterDeath.kt diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt index f68a90713a..17c1e83920 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/RowDefinition.kt @@ -27,6 +27,10 @@ data class RowDefinition( fun tileOrNull(column: String) = Tables.tileOrNull("${stringId}.$column") + fun npc(column: String) = Tables.npc("${stringId}.$column") + + fun npcOrNull(column: String) = Tables.npcOrNull("${stringId}.$column") + fun intList(column: String) = Tables.intList("${stringId}.$column") fun intListOrNull(column: String) = Tables.intListOrNull("${stringId}.$column") diff --git a/game/src/main/kotlin/content/entity/death/CharacterDeath.kt b/game/src/main/kotlin/content/entity/death/CharacterDeath.kt deleted file mode 100644 index 629e255281..0000000000 --- a/game/src/main/kotlin/content/entity/death/CharacterDeath.kt +++ /dev/null @@ -1,22 +0,0 @@ -package content.entity.death - -import world.gregs.voidps.engine.Script -import world.gregs.voidps.engine.entity.character.Death -import world.gregs.voidps.engine.entity.character.player.skill.Skill - -class CharacterDeath : Script { - - init { - levelChanged(Skill.Constitution) { _, _, to -> - if (to <= 0 && !queue.contains("death")) { - Death.killed(this) - } - } - - npcLevelChanged(Skill.Constitution) { _, _, to -> - if (to <= 0 && !queue.contains("death") && Death.canDie(this)) { - Death.killed(this) - } - } - } -} diff --git a/game/src/main/kotlin/content/entity/death/NPCDeath.kt b/game/src/main/kotlin/content/entity/death/NPCDeath.kt index d7c23e0348..444533c3d4 100644 --- a/game/src/main/kotlin/content/entity/death/NPCDeath.kt +++ b/game/src/main/kotlin/content/entity/death/NPCDeath.kt @@ -17,6 +17,7 @@ import world.gregs.voidps.engine.data.definition.CombatDefinitions import world.gregs.voidps.engine.entity.Spawn import world.gregs.voidps.engine.entity.World 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.move.tele @@ -50,11 +51,15 @@ class NPCDeath( val logger = InlineLogger() init { - npcDeath { + npcLevelChanged(Skill.Constitution) { _, _, to -> + if (to > 0 || queue.contains("death") || !Death.canDie(this)) { + return@npcLevelChanged + } mode = PauseMode dead = true steps.clear() val npc = this + Death.killed(npc) strongQueue(name = "death", 1) { val killer = killer val tile = if (transformId == "wall_beast") tile.addY(-1) else tile diff --git a/game/src/main/kotlin/content/entity/death/PlayerDeath.kt b/game/src/main/kotlin/content/entity/death/PlayerDeath.kt index 6cfcc96cd0..9858bf1382 100644 --- a/game/src/main/kotlin/content/entity/death/PlayerDeath.kt +++ b/game/src/main/kotlin/content/entity/death/PlayerDeath.kt @@ -18,6 +18,7 @@ import world.gregs.voidps.engine.Script import world.gregs.voidps.engine.client.message import world.gregs.voidps.engine.data.Settings import world.gregs.voidps.engine.entity.character.Character +import world.gregs.voidps.engine.entity.character.Death import world.gregs.voidps.engine.entity.character.jingle import world.gregs.voidps.engine.entity.character.move.tele import world.gregs.voidps.engine.entity.character.npc.NPCs @@ -41,8 +42,12 @@ class PlayerDeath : Script { get() = Tile(Settings["world.home.x", 0], Settings["world.home.y", 0], Settings["world.home.level", 0]) init { - playerDeath { onDeath -> + levelChanged(Skill.Constitution) { _, _, to -> + if (to > 0 || queue.contains("death")) { + return@levelChanged + } dead = true + val onDeath = Death.killed(this@levelChanged) strongQueue("death") { steps.clear() val dealer = damageDealers.maxByOrNull { it.value } From 5798f56dc38eb5fdbc0e8c74ba46efc8723a4a43 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 28 Mar 2026 14:18:16 +0000 Subject: [PATCH 4/8] Fix out-of-bounds viewport causing client crashes --- .../content/entity/world/RegionLoading.kt | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/game/src/main/kotlin/content/entity/world/RegionLoading.kt b/game/src/main/kotlin/content/entity/world/RegionLoading.kt index befadd112b..ce2634ab06 100644 --- a/game/src/main/kotlin/content/entity/world/RegionLoading.kt +++ b/game/src/main/kotlin/content/entity/world/RegionLoading.kt @@ -166,22 +166,31 @@ class RegionLoading(val dynamicZones: DynamicZones) : Script { val view = player.tile.zone.minus(viewport.zoneRadius, viewport.zoneRadius) val zoneSize = viewport.zoneArea var append = 0 - for (origin in view.toCuboid(zoneSize, zoneSize).copy(minLevel = 0, maxLevel = 3).toZones()) { - val target = dynamicZones.dynamicZone(origin) - if (target == null) { - zones.add(null) - continue - } - zones.add(target) - val xtea = blankXtea - if (!xteaList.contains(xtea)) { - xteaList.add(xtea) - } else { - append++ + val xtea = blankXtea + for (lvl in 0..3) { + for (x in view.x..view.x + zoneSize) { + for (y in view.y..view.y + zoneSize) { + if (x !in 0..2048 || y !in 0..2048) { + zones.add(null) + continue + } + val zone = Zone(x, y, lvl) + val target = dynamicZones.dynamicZone(zone) + if (target == null) { + zones.add(null) + continue + } + zones.add(target) + if (!xteaList.contains(xtea)) { + xteaList.add(xtea) + } else { + append++ + } + } } } for (i in 0..append) { - xteaList.add(blankXtea) + xteaList.add(xtea) } viewport.dynamic = true player.client?.dynamicMapRegion( From 7a3f14e1307ebe6a1e3093ae6666642a299d7e0a Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 28 Mar 2026 14:32:24 +0000 Subject: [PATCH 5/8] Add reload tables command --- .../main/kotlin/content/entity/player/command/ServerCommands.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/game/src/main/kotlin/content/entity/player/command/ServerCommands.kt b/game/src/main/kotlin/content/entity/player/command/ServerCommands.kt index c498cdf87c..d96b4f651a 100644 --- a/game/src/main/kotlin/content/entity/player/command/ServerCommands.kt +++ b/game/src/main/kotlin/content/entity/player/command/ServerCommands.kt @@ -36,6 +36,7 @@ import world.gregs.voidps.engine.data.definition.QuestDefinitions import world.gregs.voidps.engine.data.definition.RenderEmoteDefinitions import world.gregs.voidps.engine.data.definition.SoundDefinitions import world.gregs.voidps.engine.data.definition.SpellDefinitions +import world.gregs.voidps.engine.data.definition.Tables import world.gregs.voidps.engine.data.definition.VariableDefinitions import world.gregs.voidps.engine.entity.World import world.gregs.voidps.engine.entity.character.npc.loadNpcSpawns @@ -143,6 +144,7 @@ class ServerCommands(val accountLoader: PlayerAccountLoader) : Script { SettingsReload.now() } "bots" -> get().load(files) + "tables", "rows", "dbs" -> Tables.load(files.list(Settings["definitions.tables"])) } } From ca25efefa728a5137c69edaace694e18e34608fd Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 28 Mar 2026 14:32:35 +0000 Subject: [PATCH 6/8] Fix oob viewport issue --- .../main/kotlin/content/entity/world/RegionLoading.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/game/src/main/kotlin/content/entity/world/RegionLoading.kt b/game/src/main/kotlin/content/entity/world/RegionLoading.kt index ce2634ab06..c8918cade3 100644 --- a/game/src/main/kotlin/content/entity/world/RegionLoading.kt +++ b/game/src/main/kotlin/content/entity/world/RegionLoading.kt @@ -168,13 +168,9 @@ class RegionLoading(val dynamicZones: DynamicZones) : Script { var append = 0 val xtea = blankXtea for (lvl in 0..3) { - for (x in view.x..view.x + zoneSize) { - for (y in view.y..view.y + zoneSize) { - if (x !in 0..2048 || y !in 0..2048) { - zones.add(null) - continue - } - val zone = Zone(x, y, lvl) + for (x in 0 until zoneSize) { + for (y in 0 until zoneSize) { + val zone = Zone(view.x + x, view.y + y, lvl) val target = dynamicZones.dynamicZone(zone) if (target == null) { zones.add(null) From 9f23a96d0b703ca2a7f0b2d209c13252eab6b544 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 28 Mar 2026 14:34:37 +0000 Subject: [PATCH 7/8] Add desert slayer bosses --- .../pollninveach_dungeon.npc-spawns.toml | 44 +++---- .../dungeon/pollninveach_dungeon.npcs.toml | 43 +++++-- .../dungeon/pollnivneach_dungeon.combat.toml | 3 +- .../dungeon/pollnivneach_dungeon.gfx.toml | 2 + .../dungeon/pollnivneach_dungeon.tables.toml | 60 +++++++++ .../dungeon/pollnivneach_dungeon.vars.toml | 15 +++ .../pollnivneach/pollnivneach.areas.toml | 21 +++- .../chaos_tunnels/chaos_tunnels.npcs.toml | 3 +- .../dungeon/DesertSlayerBosses.kt | 25 ++++ .../pollnivneach/dungeon/MightiestTuroth.kt | 32 +++++ .../dungeon/MonstrousCaveCrawler.kt | 22 ++++ .../dungeon/PollnivneachDungeon.kt | 93 +++++++------- .../lumbridge/PlayerDeathSignpost.kt | 1 + .../dungeon/PollnivneachDungeonTest.kt | 114 ++++++++++++++++++ .../kotlin/world/gregs/voidps/type/Delta.kt | 1 + 15 files changed, 400 insertions(+), 79 deletions(-) create mode 100644 data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.tables.toml create mode 100644 data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.vars.toml create mode 100644 game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt create mode 100644 game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt create mode 100644 game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt create mode 100644 game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npc-spawns.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npc-spawns.toml index 0f51dd68c2..d55aeceb00 100644 --- a/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npc-spawns.toml +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npc-spawns.toml @@ -28,13 +28,13 @@ spawns = [ { id = "basilisk", x = 3319, y = 4295 }, { id = "basilisk", x = 3322, y = 4292 }, { id = "basilisk", x = 3324, y = 4302 }, - { id = "basilisk_pollninveach_dungeon", x = 3302, y = 4318 }, - { id = "basilisk_pollninveach_dungeon", x = 3302, y = 4325 }, - { id = "basilisk_pollninveach_dungeon", x = 3306, y = 4329 }, - { id = "basilisk_pollninveach_dungeon", x = 3308, y = 4324 }, - { id = "basilisk_pollninveach_dungeon", x = 3311, y = 4303 }, - { id = "basilisk_pollninveach_dungeon", x = 3311, y = 4314 }, - { id = "basilisk_pollninveach_dungeon", x = 3317, y = 4320 }, + { id = "basilisk_pollninveach", x = 3302, y = 4318 }, + { id = "basilisk_pollninveach", x = 3302, y = 4325 }, + { id = "basilisk_pollninveach", x = 3306, y = 4329 }, + { id = "basilisk_pollninveach", x = 3308, y = 4324 }, + { id = "basilisk_pollninveach", x = 3311, y = 4303 }, + { id = "basilisk_pollninveach", x = 3311, y = 4314 }, + { id = "basilisk_pollninveach", x = 3317, y = 4320 }, { id = "turoth", x = 3271, y = 4295 }, { id = "turoth", x = 3280, y = 4308 }, { id = "turoth", x = 3282, y = 4313 }, @@ -86,19 +86,19 @@ spawns = [ { id = "cave_crawler_pollnivneach", x = 3311, y = 4407, members = true }, { id = "cave_crawler_pollnivneach", x = 3319, y = 4407, members = true }, { id = "cave_crawler_pollnivneach", x = 3323, y = 4402, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon", x = 3283, y = 4346, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon", x = 3308, y = 4349, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon", x = 3293, y = 4375, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon", x = 3303, y = 4363, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_2", x = 3288, y = 4350, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_2", x = 3296, y = 4340, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_2", x = 3288, y = 4361, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_2", x = 3310, y = 4355, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_3", x = 3297, y = 4347, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_3", x = 3315, y = 4346, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_3", x = 3282, y = 4357, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_3", x = 3303, y = 4369, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_4", x = 3279, y = 4350, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_4", x = 3294, y = 4353, members = true }, - { id = "aberrant_spectre_pollninveach_dungeon_4", x = 3294, y = 4366, members = true }, + { id = "aberrant_spectre_pollninveach", x = 3283, y = 4346, members = true }, + { id = "aberrant_spectre_pollninveach", x = 3308, y = 4349, members = true }, + { id = "aberrant_spectre_pollninveach", x = 3293, y = 4375, members = true }, + { id = "aberrant_spectre_pollninveach", x = 3303, y = 4363, members = true }, + { id = "aberrant_spectre_pollninveach_2", x = 3288, y = 4350, members = true }, + { id = "aberrant_spectre_pollninveach_2", x = 3296, y = 4340, members = true }, + { id = "aberrant_spectre_pollninveach_2", x = 3288, y = 4361, members = true }, + { id = "aberrant_spectre_pollninveach_2", x = 3310, y = 4355, members = true }, + { id = "aberrant_spectre_pollninveach_3", x = 3297, y = 4347, members = true }, + { id = "aberrant_spectre_pollninveach_3", x = 3315, y = 4346, members = true }, + { id = "aberrant_spectre_pollninveach_3", x = 3282, y = 4357, members = true }, + { id = "aberrant_spectre_pollninveach_3", x = 3303, y = 4369, members = true }, + { id = "aberrant_spectre_pollninveach_4", x = 3279, y = 4350, members = true }, + { id = "aberrant_spectre_pollninveach_4", x = 3294, y = 4353, members = true }, + { id = "aberrant_spectre_pollninveach_4", x = 3294, y = 4366, members = true }, ] diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml index 85df628e4a..c97a100f54 100644 --- a/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml @@ -4,7 +4,7 @@ id = 13214 [iwazaru_pollninveach_dungeon] id = 13225 -[basilisk_pollninveach_dungeon] +[basilisk_pollninveach] id = 1617 hitpoints = 750 att = 30 @@ -20,17 +20,32 @@ examine = "The eyes of evil." [catolax_pollninveach_dungeon] id = 7783 -[aberrant_spectre_pollninveach_dungeon] +[aberrant_spectre_pollninveach] id = 7801 - -[aberrant_spectre_pollninveach_dungeon_2] +str = 70 +def = 90 +mage = 115 +combat_def = "aberrant_spectre" +hunt_mode = "aggressive" +wander_range = 4 +respawn_delay = 30 +slayer_xp = 110.0 +slayer_level = 60 +drop_table = "aberrant_spectre" +categories = ["aberrant_spectre"] +examine = "A very smelly ghost." + +[aberrant_spectre_pollninveach_2] id = 7802 +clone = "aberrant_spectre_pollninveach" -[aberrant_spectre_pollninveach_dungeon_3] +[aberrant_spectre_pollninveach_3] id = 7803 +clone = "aberrant_spectre_pollninveach" -[aberrant_spectre_pollninveach_dungeon_4] +[aberrant_spectre_pollninveach_4] id = 7804 +clone = "aberrant_spectre_pollninveach" [catolax_pollninveach_dungeon_2] id = 7782 @@ -41,8 +56,16 @@ id = 13215 [iwazaru_pollninveach_dungeon_2] id = 13226 -[monsterous_cave_crawler] +[monstrous_cave_crawler] id = 7798 +hitpoints = 2650 +slayer_level = 10 +slayer_xp = 1000.0 +# Made up stats +range = 200 +categories = ["cave_crawler"] +hunt_mode = "aggressive" +combat_def = "monstrous_cave_crawler" examine = "It oozes venom from every pore." [kurask_overlord] @@ -85,6 +108,7 @@ att = 200 str = 200 def = 175 magic = 210 +height = 10 categories = ["basilisk"] hunt_mode = "aggressive" combat_def = "basilisk_boss" @@ -95,13 +119,12 @@ examine = "It radiates an unhealthy aura." id = 7800 hitpoints = 1750 slayer_level = 55 -slayer_xp = 1000.0 +slayer_xp = 391.0 # Made up stats att = 160 str = 180 def = 150 categories = ["turoth"] -# max hit = 165 immune_poison = true hunt_mode = "aggressive" combat_def = "mightiest_turoth" @@ -120,4 +143,4 @@ drop_table = "bones" hunt_mode = "aggressive" combat_def = "turoth_small" max_hit_stab = 110 -examine = "A vicious bite on a feeble body." \ No newline at end of file +examine = "A vicious bite on a feeble body." diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml index 059ba06729..d8ec199e02 100644 --- a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.combat.toml @@ -10,7 +10,7 @@ death_sound = "cave_crawler_death" range = 1 anim = "monstrous_cave_crawler_attack" target_sound = "cave_crawler_attack" -target_hit = { offense = "stab", max = 240 } +target_hit = { offense = "stab", defence = "range", max = 240 } [monstrous_cave_crawler.poison] range = 8 @@ -48,6 +48,7 @@ target_hit = { offense = "slash", max = 300 } clone = "basilisk.piercing_gaze" [basilisk_boss.gaze] +range = 8 condition = "mirror_shield" anim = "basilisk_boss_attack" gfx = "basilisk_boss_cast" diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml index 3455ec3936..41f84d58e0 100644 --- a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.gfx.toml @@ -6,6 +6,7 @@ id = 1662 [basilisk_boss_travel] id = 1663 +delay = 45 [basilisk_boss_impact] id = 1664 @@ -15,6 +16,7 @@ id = 1653 [monstrous_cave_crawler_travel] id = 1654 +delay = 30 [monstrous_cave_crawler_impact] id = 1655 diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.tables.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.tables.toml new file mode 100644 index 0000000000..9f84e3d277 --- /dev/null +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.tables.toml @@ -0,0 +1,60 @@ +[desert_dungeon_boss] +row_id = "npc" +region = "int" +player_spawn = "tile" +npc_spawn = "tile" +exit = "tile" +type = "string" + +[.monstrous_cave_crawler] +type = "cave_crawler" +region = 12356 +player_spawn = { x = 3123, y = 4381 } +npc_spawn = { x = 3121, y = 4384 } +exit = { x = 3319, y = 4370 } + +[.turoth_mightiest] +type = "turoth" +region = 12355 +player_spawn = { x = 3089, y = 4318 } +npc_spawn = { x = 3088, y = 4324 } +exit = { x = 3275, y = 4335 } + +[.basilisk_boss] +type = "basilisk" +region = 12355 +player_spawn = { x = 3123, y = 4333 } +npc_spawn = { x = 3115, y = 4322 } +exit = { x = 3315, y = 4335 } + +[.kurask_overlord] +type = "kurask" +region = 12356 +player_spawn = { x = 3082, y = 4380 } +npc_spawn = { x = 3084, y = 4381 } +exit = { x = 3277, y = 4371 } + +[dessert_dungeon_barriers] +tile = "tile" +inside = "tile" +boss = "npc" + +[.turoth] +tile = { x = 3274, y = 4334 } +inside = { x = 3082, y = 4334 } +boss = "turoth_mightiest" + +[.basilisk] +tile = { x = 3314, y = 4334 } +inside = { x = 3122, y = 4334 } +boss = "basilisk_boss" + +[.cave_crawler] +tile = { x = 3318, y = 4371 } +inside = { x = 3126, y = 4371 } +boss = "monstrous_cave_crawler" + +[.kurask] +tile = { x = 3276, y = 4372 } +inside = { x = 3084, y = 4372 } +boss = "kurask_overlord" diff --git a/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.vars.toml b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.vars.toml new file mode 100644 index 0000000000..2fe98e46ac --- /dev/null +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollnivneach_dungeon.vars.toml @@ -0,0 +1,15 @@ +[killed_monstrous_cave_crawler] +format = "boolean" +persist = true + +[killed_turoth_mightiest] +format = "boolean" +persist = true + +[killed_basilisk_boss] +format = "boolean" +persist = true + +[killed_kurask_overlord] +format = "boolean" +persist = true diff --git a/data/area/kharidian_desert/pollnivneach/pollnivneach.areas.toml b/data/area/kharidian_desert/pollnivneach/pollnivneach.areas.toml index bb0c249f39..25b1fee091 100644 --- a/data/area/kharidian_desert/pollnivneach/pollnivneach.areas.toml +++ b/data/area/kharidian_desert/pollnivneach/pollnivneach.areas.toml @@ -10,4 +10,23 @@ tags = ["teleport"] [smoke_dungeon] x = [3200, 3327] -y = [9344, 9407] \ No newline at end of file +y = [9344, 9407] + +[pollnivneach_dungeon_boss] +x = [3072, 3135] +y = [4288, 4415] +tags = ["multi_combat"] + +[mightiest_turoth_boss] +x = [3086, 3096] +y = [4318, 4326] + +[pollnivneach_dungeon_lower] +x = [3264, 3327] +y = [4288, 4415] +tags = ["multi_combat"] + +[pollnivneach_dungeon_upper] +x = [3328, 3391] +y = [9344, 9471] +tags = ["multi_combat"] \ No newline at end of file diff --git a/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml b/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml index 176e9327bb..c195b869f9 100644 --- a/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml +++ b/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml @@ -28,8 +28,7 @@ hitpoints = 800 att = 57 str = 87 def = 87 -style = "stab" -max_hit_melee = 100 +combat_def = "turoth_large" slayer_xp = 80.0 categories = ["turoth"] immune_cannon = true diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt new file mode 100644 index 0000000000..586a148ead --- /dev/null +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt @@ -0,0 +1,25 @@ +package content.area.kharidian_desert.pollnivneach.dungeon + +import content.entity.combat.killer +import content.entity.player.dialogue.type.statement +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.data.definition.Tables +import world.gregs.voidps.engine.entity.character.move.tele +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.exp.exp +import world.gregs.voidps.engine.queue.queue + +class DesertSlayerBosses : Script { + init { + npcDespawn("monstrous_cave_crawler,turoth_mightiest,basilisk_boss,kurask_overlord") { + val killer = killer as? Player ?: return@npcDespawn + killer["killed_${id}"] = true + killer.exp(Skill.Slayer, 1000.0) + killer.tele(Tables.tile("desert_dungeon_boss.${id}.exit")) + killer.queue("shift_back") { + killer.statement("You shift back to reality, having defeated this boss. You may now pass this barrier freely.") + } + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt new file mode 100644 index 0000000000..67537794a8 --- /dev/null +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt @@ -0,0 +1,32 @@ +package content.area.kharidian_desert.pollnivneach.dungeon + +import content.entity.gfx.areaGfx +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.instruction.handle.interactPlayer +import world.gregs.voidps.engine.data.definition.Areas +import world.gregs.voidps.engine.entity.character.npc.NPCs +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.map.collision.random +import world.gregs.voidps.type.random + +class MightiestTuroth : Script { + init { + npcCombatDamage("turoth_mightiest") { + if (random.nextInt(5) == 0) { + return@npcCombatDamage + } + val target = it.source as? Player ?: return@npcCombatDamage + for (i in 0 until 3) { + if (contains("swarming_$i")) { + continue + } + val tile = Areas["mightiest_turoth_boss"].random(this) ?: return@npcCombatDamage + areaGfx("turoth_minion_spawn", tile) + val npc = NPCs.add("turoth_swarming", tile) + npc.interactPlayer(target, "Attack") + set("swarming_$i", true) + break + } + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt new file mode 100644 index 0000000000..a5c084a940 --- /dev/null +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt @@ -0,0 +1,22 @@ +package content.area.kharidian_desert.pollnivneach.dungeon + +import content.entity.combat.target +import content.entity.effect.toxin.poisonDamage +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.entity.character.player.Player + +class MonstrousCaveCrawler : Script { + init { + npcAttack("monstrous_cave_crawler", "melee") { + if (inc("hit_count") != 2) { + return@npcAttack + } + clear("hit_count") + val target = target as? Player ?: return@npcAttack + // Reduce anti-poison resistance + target.poisonDamage = (target.poisonDamage + 80).coerceAtMost(80) + target.timers.startIfAbsent("poison") + target["poison_source"] = this + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt index 6574639bd5..5b50b6c818 100644 --- a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt @@ -1,73 +1,70 @@ package content.area.kharidian_desert.pollnivneach.dungeon -import content.entity.combat.killer import content.entity.player.dialogue.type.choice import content.entity.player.dialogue.type.statement +import content.quest.clearInstance import content.quest.instanceOffset import content.quest.setInstanceLogout import content.quest.smallInstance import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.instruction.handle.interactPlayer import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.data.definition.Rows +import world.gregs.voidps.engine.data.definition.Tables import world.gregs.voidps.engine.entity.character.move.tele import world.gregs.voidps.engine.entity.character.npc.NPCs -import world.gregs.voidps.engine.map.instance.Instances -import world.gregs.voidps.engine.queue.softQueue import world.gregs.voidps.type.Region import world.gregs.voidps.type.Tile class PollnivneachDungeon : Script { init { - // TODO barrier gfx - objectOperate("Pass", "pollnivneach_dungeon_barrier") { (target) -> - statement("This portal leads to the lair of a ferocious creature. Are you sure you want to do battle?") - choice("Do you want to head into the fray?") { - option("Yes, I feel brave.") { - smallInstance(Region(12356)) -// setInstanceLogout() - val offset = instanceOffset() - - tele(offset.add(3127, 4373)) - val boss = NPCs.add("monsterous_cave_crawler", Tile(3121, 4384)) - - message("Your surroundings shift to become familiar, as you face a powerful turoth.") -// tele(offset.add(3089, 4318)) -// val boss = NPCs.add("mightiest_turoth", Tile(3088, 4324)) - - message("Your surroundings shift to become familiar, as you face a powerful basilisk.") -// tele(offset.add(3123, 4333)) -// val boss = NPCs.add("basalisk_boss", Tile(3115, 4322)) - - message("Your surroundings shift to become familiar, as you face a powerful kurask.") -// tele(offset.add(3089, 4322)) -// val boss = NPCs.add("kurask_overlord", Tile(3091, 4323)) - - // 1447 - + objectOperate("Pass", "pollnivneach_dungeon_barrier_north") { (target) -> + val offset = instanceOffset() + val boss = boss(target.tile.minus(offset), "tile") ?: return@objectOperate + if (!get("killed_${boss}", false)) { + statement("This portal leads to the lair of a ferocious creature. Are you sure you want to do battle?") + choice("Do you want to head into the fray?") { + option("Yes, I feel brave.") { + val row = Rows.get("desert_dungeon_boss.${boss}") + smallInstance(Region(row.int("region"))) + setInstanceLogout(row.tile("exit")) + delay(3) + val offset = instanceOffset() + tele(offset.tile(row.tile("player_spawn"))) + val boss = NPCs.add(boss, offset.tile(row.tile("npc_spawn"))) + message("Your surroundings shift to become familiar, as you face a powerful ${row.string("type")}.") + boss.interactPlayer(this, "Attack") + } + option("No way!") } - option("No way!") + return@objectOperate } face(target) - val x = if (tile.x <= target.tile.x) target.tile.x + 1 else target.tile.x - 1 - val y = tile.y.coerceIn(target.tile.y, target.tile.y + 2) - walkOverDelay(tile.copy(y = y)) - message("You pass through the mystic barrier, which feels odd.") + val x = tile.x.coerceIn(target.tile.x, target.tile.x + 2) + val y = if (tile.y <= target.tile.y) target.tile.y + 1 else target.tile.y - 1 + walkOverDelay(tile.copy(x = x)) anim("pass_through_barrier") gfx("pass_barrier_red") exactMoveDelay(Tile(x, y), delay = 30) } - npcDespawn("monsterous_cave_crawler") { - val killer = killer - softQueue("shift_back") { -// statment("You shift back to reality, having defeated this boss. You may now pass this barrier freely.") - } + exited("pollnivneach_dungeon_boss") { + clearInstance() } - objectOperate("Pass", "pollnivneach_dungeon_barrier_north") { (target) -> + objectOperate("Pass", "pollnivneach_dungeon_barrier") { (target) -> + val offset = instanceOffset() + val boss = boss(target.tile.minus(offset), "inside") + if (boss != null) { + clearInstance() + tele(Tables.tile("desert_dungeon_boss.$boss.exit")) + return@objectOperate + } face(target) - val x = tile.x.coerceIn(target.tile.x, target.tile.x + 2) - val y = if (tile.y <= target.tile.y) target.tile.y + 1 else target.tile.y - 1 - walkOverDelay(tile.copy(x = x)) + val x = if (tile.x <= target.tile.x) target.tile.x + 1 else target.tile.x - 1 + val y = tile.y.coerceIn(target.tile.y, target.tile.y + 2) + walkOverDelay(tile.copy(y = y)) + message("You pass through the mystic barrier, which feels odd.") anim("pass_through_barrier") gfx("pass_barrier_red") exactMoveDelay(Tile(x, y), delay = 30) @@ -75,7 +72,17 @@ class PollnivneachDungeon : Script { objTeleportLand("Climb-down", "pollnivneach_well") { _, _ -> message("You descend into the somewhat smoky depths of the well, to the accompaniment of eery wails.") + // TODO quest req, smoke interface + damage } } + + private fun boss(tile: Tile, key: String): String? { + for (row in Tables.get("dessert_dungeon_barriers").rows()) { + if (row.tile(key) == tile) { + return row.npc("boss") + } + } + return null + } } \ No newline at end of file diff --git a/game/src/main/kotlin/content/area/misthalin/lumbridge/PlayerDeathSignpost.kt b/game/src/main/kotlin/content/area/misthalin/lumbridge/PlayerDeathSignpost.kt index 41af32e998..7bce78b269 100644 --- a/game/src/main/kotlin/content/area/misthalin/lumbridge/PlayerDeathSignpost.kt +++ b/game/src/main/kotlin/content/area/misthalin/lumbridge/PlayerDeathSignpost.kt @@ -11,6 +11,7 @@ class PlayerDeathSignpost : Script { playerDeath { playerDeathsToday += 1 } + objectOperate("Read", "lumbridge_signpost_death") { if (playerDeathsToday > 0) { statement("So far today, $playerDeathsToday unlucky adventurers have died on ${Settings["server.name"]} and been sent to their respawn location. Be careful out there.") diff --git a/game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt b/game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt new file mode 100644 index 0000000000..afbad02ee7 --- /dev/null +++ b/game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt @@ -0,0 +1,114 @@ +package content.area.kharidian_desert.pollnivneach.dungeon + +import WorldTest +import dialogueContinue +import dialogueOption +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import world.gregs.voidps.engine.client.instruction.handle.interactObject +import world.gregs.voidps.engine.entity.obj.GameObjects +import world.gregs.voidps.engine.inv.equipment +import world.gregs.voidps.network.login.protocol.visual.update.player.EquipSlot +import world.gregs.voidps.type.Tile + +class PollnivneachDungeonTest : WorldTest() { + + @Test + fun `Kill monstrous cave crawler`() { + val player = createPlayer(Tile(3319, 4370, 0)) + player["auto_retaliate"] = true + player["god_mode"] = true + player["insta_kill"] = true + + val barrier = GameObjects.find(Tile(3318, 4371), "pollnivneach_dungeon_barrier_north") + player.interactObject(barrier, "Pass") + tick(2) + + player.dialogueContinue(1) + player.dialogueOption("line1") + + tick(15) + + assertEquals(Tile(3319, 4370), player.tile) + assertEquals(true, player["killed_monstrous_cave_crawler", false]) + + player.interactObject(barrier, "Pass") + tick(2) + assertEquals(Tile(3319, 4372), player.tile) + } + + @Test + fun `Kill kurask overlord`() { + val player = createPlayer(Tile(3277, 4371, 0)) + player["auto_retaliate"] = true + player["god_mode"] = true + player["insta_kill"] = true + + val barrier = GameObjects.find(Tile(3276, 4372), "pollnivneach_dungeon_barrier_north") + player.interactObject(barrier, "Pass") + tick(2) + + player.dialogueContinue(1) + player.dialogueOption("line1") + + tick(15) + + assertEquals(Tile(3277, 4371), player.tile) + assertEquals(true, player["killed_kurask_overlord", false]) + + player.interactObject(barrier, "Pass") + tick(2) + assertEquals(Tile(3277, 4373), player.tile) + } + + @Test + fun `Kill mightiest turoth`() { + val player = createPlayer(Tile(3275, 4335, 0)) + player.equipment.set(EquipSlot.Weapon.index, "leaf_bladed_sword") + player["auto_retaliate"] = true + player["god_mode"] = true + player["insta_kill"] = true + + val barrier = GameObjects.find(Tile(3274, 4334), "pollnivneach_dungeon_barrier_north") + player.interactObject(barrier, "Pass") + tick(2) + + player.dialogueContinue(1) + player.dialogueOption("line1") + + tick(20) + + assertEquals(Tile(3275, 4335), player.tile) + assertEquals(true, player["killed_turoth_mightiest", false]) + + player.interactObject(barrier, "Pass") + tick(2) + assertEquals(Tile(3275, 4333), player.tile) + } + + @Test + fun `Kill basilisk boss`() { + val player = createPlayer(Tile(3315, 4335, 0)) + player.equipment.set(EquipSlot.Shield.index, "mirror_shield") + player["auto_retaliate"] = true + player["god_mode"] = true + player["insta_kill"] = true + + val barrier = GameObjects.find(Tile(3314, 4334), "pollnivneach_dungeon_barrier_north") + player.interactObject(barrier, "Pass") + tick(2) + + player.dialogueContinue(1) + player.dialogueOption("line1") + + tick(20) + + assertEquals(Tile(3315, 4335), player.tile) + assertEquals(true, player["killed_basilisk_boss", false]) + + player.interactObject(barrier, "Pass") + tick(2) + assertEquals(Tile(3315, 4333), player.tile) + } + +} \ No newline at end of file diff --git a/types/src/main/kotlin/world/gregs/voidps/type/Delta.kt b/types/src/main/kotlin/world/gregs/voidps/type/Delta.kt index 2fec2157e7..5e4ca38cfb 100644 --- a/types/src/main/kotlin/world/gregs/voidps/type/Delta.kt +++ b/types/src/main/kotlin/world/gregs/voidps/type/Delta.kt @@ -54,6 +54,7 @@ value class Delta(val id: Long) { fun delta(value: Delta) = delta(value.x, value.y, value.level) fun tile(x: Int = 0, y: Int = 0, level: Int = 0) = Tile(this.x + x, this.y + y, this.level + level) + fun tile(tile: Tile) = Tile(this.x + tile.x, this.y + tile.y, this.level + tile.level) fun add(direction: Direction) = add(direction.delta) fun minus(direction: Direction) = minus(direction.delta) From 93f8344c1843e459a1788c68255f6bb24b684343 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 28 Mar 2026 14:34:59 +0000 Subject: [PATCH 8/8] Formatting --- .../pollnivneach/dungeon/DesertSlayerBosses.kt | 6 +++--- .../pollnivneach/dungeon/MightiestTuroth.kt | 2 +- .../pollnivneach/dungeon/MonstrousCaveCrawler.kt | 2 +- .../pollnivneach/dungeon/PollnivneachDungeon.kt | 7 +++---- .../pollnivneach/dungeon/PollnivneachDungeonTest.kt | 3 +-- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt index 586a148ead..46b21b9e1d 100644 --- a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/DesertSlayerBosses.kt @@ -14,12 +14,12 @@ class DesertSlayerBosses : Script { init { npcDespawn("monstrous_cave_crawler,turoth_mightiest,basilisk_boss,kurask_overlord") { val killer = killer as? Player ?: return@npcDespawn - killer["killed_${id}"] = true + killer["killed_$id"] = true killer.exp(Skill.Slayer, 1000.0) - killer.tele(Tables.tile("desert_dungeon_boss.${id}.exit")) + killer.tele(Tables.tile("desert_dungeon_boss.$id.exit")) killer.queue("shift_back") { killer.statement("You shift back to reality, having defeated this boss. You may now pass this barrier freely.") } } } -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt index 67537794a8..b2dd543f78 100644 --- a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MightiestTuroth.kt @@ -29,4 +29,4 @@ class MightiestTuroth : Script { } } } -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt index a5c084a940..b384e43755 100644 --- a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/MonstrousCaveCrawler.kt @@ -19,4 +19,4 @@ class MonstrousCaveCrawler : Script { target["poison_source"] = this } } -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt index 5b50b6c818..01463f4bc5 100644 --- a/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt +++ b/game/src/main/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeon.kt @@ -21,11 +21,11 @@ class PollnivneachDungeon : Script { objectOperate("Pass", "pollnivneach_dungeon_barrier_north") { (target) -> val offset = instanceOffset() val boss = boss(target.tile.minus(offset), "tile") ?: return@objectOperate - if (!get("killed_${boss}", false)) { + if (!get("killed_$boss", false)) { statement("This portal leads to the lair of a ferocious creature. Are you sure you want to do battle?") choice("Do you want to head into the fray?") { option("Yes, I feel brave.") { - val row = Rows.get("desert_dungeon_boss.${boss}") + val row = Rows.get("desert_dungeon_boss.$boss") smallInstance(Region(row.int("region"))) setInstanceLogout(row.tile("exit")) delay(3) @@ -74,7 +74,6 @@ class PollnivneachDungeon : Script { message("You descend into the somewhat smoky depths of the well, to the accompaniment of eery wails.") // TODO quest req, smoke interface + damage } - } private fun boss(tile: Tile, key: String): String? { @@ -85,4 +84,4 @@ class PollnivneachDungeon : Script { } return null } -} \ No newline at end of file +} diff --git a/game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt b/game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt index afbad02ee7..03de78c3e6 100644 --- a/game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt +++ b/game/src/test/kotlin/content/area/kharidian_desert/pollnivneach/dungeon/PollnivneachDungeonTest.kt @@ -110,5 +110,4 @@ class PollnivneachDungeonTest : WorldTest() { tick(2) assertEquals(Tile(3315, 4333), player.tile) } - -} \ No newline at end of file +}