From 31761531772fa18565eb01c0cd951a5080d3c91c Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 14 Apr 2026 12:40:46 +0100 Subject: [PATCH 1/5] Add corporeal beasts lair --- .../corporeal_beast_lair.anims.toml | 17 +++++++++++ .../corporeal_beast_lair.combat.toml | 12 ++++++++ .../corporeal_beasts_lair.npcs.toml | 10 +++++++ .../corporeal_beasts_lair.objs.toml | 17 +++++++++++ .../corporeal_beasts_lair.teles.toml | 9 ++++++ data/area/wilderness/wilderness.teles.toml | 2 +- .../CorporealBeastsLair.kt | 30 +++++++++++++++++++ 7 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.anims.toml create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.objs.toml create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.teles.toml create mode 100644 game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.anims.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.anims.toml new file mode 100644 index 0000000000..7bcda3705c --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.anims.toml @@ -0,0 +1,17 @@ +[corporeal_beast_stomp] +id = 10496 # gfx 1834 + +[corporeal_beast_slap] +id = 10057 + +[corporeal_beast_swipe] +id = 10058 + +[corporeal_beast_magic] +id = 10410 # gfx 1823+ + +[corporeal_beast_defend] +id = 10386 + +[corporeal_beast_death] +id = 10385 diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml new file mode 100644 index 0000000000..b62c47066b --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml @@ -0,0 +1,12 @@ +[corporeal_beast] +attack_speed = 4 +retreat_range = 4 +defend_anim = "ahrim_staff_defend" +defend_sound = "wight_defend" +death_anim = "human_death" +death_sound = "wight_death" + +[corporeal_beast.melee] +chance = 40 +range = 1 + diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml index 39384f8874..6347249bb7 100644 --- a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml @@ -1,4 +1,14 @@ [corporeal_beast] id = 8133 +hitpoints = 20000 +att = 320 +str = 320 +def = 310 +magic = 350 +range = 150 +attack_bonus = 50 +hunt_mode = "aggressive" examine = "A vision of supernatural horror." +[dark_energy_core] +id = 8127 diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.objs.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.objs.toml new file mode 100644 index 0000000000..b1701fd6f5 --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.objs.toml @@ -0,0 +1,17 @@ +[corporeal_beast_lair_entrance] +id = 38815 + +[corporeal_beast_lair_entrance_open] +id = 37749 + +[corporeal_beast_lair_entrance_collapsed] +id = 37750 + +[corporeal_beast_lair_exit] +id = 37928 + +[corporeal_beast_lair_passage] +id = 37929 + +[corporeal_beast_lair_door] +id = 38811 diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.teles.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.teles.toml new file mode 100644 index 0000000000..dab0d9a322 --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.teles.toml @@ -0,0 +1,9 @@ +[corporeal_beast_lair_entrance_open] +option = "Go-through" +tile = { x = 3209, y = 3780 } +to = { x = 2885, y = 4372, level = 2 } + +[corporeal_beast_lair_exit] +option = "Go-through" +tile = { x = 2883, y = 4370, level = 2 } +to = { x = 3214, y = 3782 } diff --git a/data/area/wilderness/wilderness.teles.toml b/data/area/wilderness/wilderness.teles.toml index abb6cdd11c..0a1d2ce3ee 100644 --- a/data/area/wilderness/wilderness.teles.toml +++ b/data/area/wilderness/wilderness.teles.toml @@ -88,4 +88,4 @@ to = { x = 3282, y = 3936, level = 3 } [lever_kbd_lair] option = "Pull" tile = { x = 2273, y = 4680 } -to = { x = 3067, y = 10254 } \ No newline at end of file +to = { x = 3067, y = 10254 } diff --git a/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt new file mode 100644 index 0000000000..e06552c3d3 --- /dev/null +++ b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt @@ -0,0 +1,30 @@ +package content.area.realm.corporeal_beasts_lair + +import content.entity.player.dialogue.type.warning +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.entity.character.move.tele + +class CorporealBeastsLair : Script { + init { + objectOperate("Go-through", "corporeal_beast_lair_passage") { (target) -> + if (tile.x <= target.tile.x) { + tele(target.tile.add(3, 2)) + } else { + tele(target.tile.add(-1, 2)) + } + } + + objectOperate("Go-through", "corporeal_beast_lair_door") { (target) -> + if (tile.x <= target.tile.x) { + if (warning("corporeal_beast")) + tele(target.tile.add(3, 2)) + } else { + tele(target.tile.add(-1, 2)) + } + } + + objectOperate("Peek-in", "corporeal_beast_lair_door") { (target) -> + // TODO message + } + } +} \ No newline at end of file From 986730434ca93211a970bbe784ce6bb566b5aa29 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 14 Apr 2026 15:30:12 +0100 Subject: [PATCH 2/5] Add support for combat multi-targets within a radius --- .../engine/data/config/CombatDefinition.kt | 4 +++ .../data/definition/CombatDefinitions.kt | 8 +++++ .../content/entity/npc/combat/Attack.kt | 30 +++++++++++++++---- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/CombatDefinition.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/CombatDefinition.kt index e79d387941..e896b4d543 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/CombatDefinition.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/CombatDefinition.kt @@ -55,6 +55,8 @@ data class CombatDefinition( * @param targetSounds sounds played on the target when the swing is executed. * @param targetHits damage hit queued when the swing is executed. * @param multiTargetArea The area to find multiple targets within. + * @param multiTargetRadius The radius within the target to find multiple targets. + * @param multiRadius The radius within the attack to find multiple targets within. * == Impact == * @param impactAnim animation played on the target when the [targetHits] impacts. * @param impactGfx gfx played on the target [targetHits] after the hit's delay. @@ -90,6 +92,8 @@ data class CombatDefinition( val targetSounds: List = emptyList(), val targetHits: List = emptyList(), val multiTargetArea: String = "", + val multiTargetRadius: Int = 0, + val multiRadius: Int = 0, // Impact val impactAnim: String = "", val impactGfx: List = emptyList(), diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/CombatDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/CombatDefinitions.kt index 917529fa86..11948d97fb 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/CombatDefinitions.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/CombatDefinitions.kt @@ -116,6 +116,8 @@ class CombatDefinitions { val drainSkills = mutableListOf() val targetHits = mutableListOf() var targetArea = "" + var targetRadius = 0 + var radius = 0 var impactRegardless = false var freeze = 0 var poison = 0 @@ -151,6 +153,8 @@ class CombatDefinitions { "target_sound" -> sound(targetSounds) "target_sounds" -> sounds(targetSounds) "multi_target_area" -> targetArea = string() + "multi_target_radius" -> targetRadius = int() + "multi_radius" -> radius = int() // Damage "projectile" -> projectile(projectiles) "projectiles" -> projectiles(projectiles) @@ -205,6 +209,8 @@ class CombatDefinitions { targetSounds = targetSounds, targetHits = targetHits, multiTargetArea = targetArea, + multiTargetRadius = targetRadius, + multiRadius = radius, impactAnim = impactAnim, missGfx = missGraphics, impactGfx = impactGraphics, @@ -436,6 +442,8 @@ class CombatDefinitions { targetSounds = original.targetSounds.ifEmpty { clone.targetSounds }, targetHits = original.targetHits.ifEmpty { clone.targetHits }, multiTargetArea = if (original.multiTargetArea != CombatAttack.EMPTY.multiTargetArea) original.multiTargetArea else clone.multiTargetArea, + multiTargetRadius = if (original.multiTargetRadius != CombatAttack.EMPTY.multiTargetRadius) original.multiTargetRadius else clone.multiTargetRadius, + multiRadius = if (original.multiRadius != CombatAttack.EMPTY.multiRadius) original.multiRadius else clone.multiRadius, impactAnim = if (original.impactAnim != CombatAttack.EMPTY.impactAnim) original.impactAnim else clone.impactAnim, impactGfx = original.impactGfx.ifEmpty { clone.impactGfx }, impactSounds = original.impactSounds.ifEmpty { clone.impactSounds }, 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 d51dd7c093..68c893de44 100644 --- a/game/src/main/kotlin/content/entity/npc/combat/Attack.kt +++ b/game/src/main/kotlin/content/entity/npc/combat/Attack.kt @@ -25,12 +25,15 @@ import world.gregs.voidps.engine.entity.character.mode.combat.CombatMovement import world.gregs.voidps.engine.entity.character.mode.move.hasLineOfSight import world.gregs.voidps.engine.entity.character.mode.move.target.TargetStrategy import world.gregs.voidps.engine.entity.character.npc.NPC +import world.gregs.voidps.engine.entity.character.npc.NPCs import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.Players import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.entity.character.sound import world.gregs.voidps.engine.entity.item.Item import world.gregs.voidps.engine.map.Overlap +import world.gregs.voidps.engine.map.spiral +import world.gregs.voidps.type.Tile import world.gregs.voidps.type.random class Attack( @@ -69,7 +72,7 @@ class Attack( } else { clear("attack_range") } - val targets = targets(primaryTarget, attack.multiTargetArea) + val targets = targets(primaryTarget, attack.multiTargetArea, attack.multiTargetRadius, attack.multiRadius) // Target(s) for (target in targets) { target.play(attack.targetAnim) @@ -130,7 +133,7 @@ class Attack( val source = if (target is Player) def(target).stringId else id val definition = definitions.getOrNull(def["combat_def", source]) ?: return@npcCombatAttack val attack = definition.attacks[attackName] ?: return@npcCombatAttack - val targets = targets(target, attack.multiTargetArea) + val targets = targets(target, attack.multiTargetArea, attack.multiTargetRadius, attack.multiRadius) for (target in targets) { if (!CombatApi.impact(this, target, "${definition.npc}:${attack.id}")) { continue @@ -220,16 +223,31 @@ class Attack( } @Suppress("UNCHECKED_CAST") - private fun NPC.targets(target: Character, area: String): Set { + private fun NPC.targets(target: Character, area: String, targetRadius: Int, radius: Int): Set { if (area == "") { + if (targetRadius != 0) { + return targets(target.tile, radius) + } else if (radius != 0) { + return targets(tile, radius) + } return setOf(target) } val area = Areas.getOrNull(area)?.area ?: return setOf(target) - val list = mutableSetOf(target) + val set = mutableSetOf(target) for (zone in area.toZones(tile.level)) { - list.addAll(Players.at(zone)) + set.addAll(Players.at(zone)) + } + return set + } + + private fun NPC.targets(tile: Tile, radius: Int): Set { + val set = mutableSetOf() + for (tile in tile.spiral(radius)) { + set.addAll(NPCs.at(tile)) + set.addAll(Players.at(tile)) } - return list + set.remove(this) // Not including the attacker + return set } private fun Character.play(anim: String) { From 73e2160cb51818bb9d6a3b00cad2dface39da0b7 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 14 Apr 2026 16:59:51 +0100 Subject: [PATCH 3/5] Fix broken npc magic combat stats --- .../main/kotlin/world/gregs/voidps/cache/definition/Params.kt | 2 -- .../ice_strykewyrm_cave/ice_strykewyrm_cave.npcs.toml | 2 +- data/area/kandarin/feldip_hills/feldip_hills.npcs.toml | 2 +- .../al_kharid/desert_strykewyrm/desert_strykewyrm.npcs.toml | 2 +- .../pollnivneach/dungeon/pollninveach_dungeon.npcs.toml | 2 +- .../chasm_of_tears/guthix_temple/guthix_temple.npcs.toml | 2 +- data/area/morytania/mort_myre_swamp/mort_myre_swamp.npcs.toml | 2 +- data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml | 4 ++-- data/entity/npc/animal/crab/crab.npcs.toml | 2 +- .../npc/monster/rock/rock_lobster/rock_lobster.npcs.toml | 2 +- data/entity/npc/monster/wallasalki/wallasalki.npcs.toml | 2 +- 11 files changed, 11 insertions(+), 13 deletions(-) diff --git a/cache/src/main/kotlin/world/gregs/voidps/cache/definition/Params.kt b/cache/src/main/kotlin/world/gregs/voidps/cache/definition/Params.kt index 595ec75333..e790b70493 100644 --- a/cache/src/main/kotlin/world/gregs/voidps/cache/definition/Params.kt +++ b/cache/src/main/kotlin/world/gregs/voidps/cache/definition/Params.kt @@ -105,7 +105,6 @@ object Params { const val LOCATIONS = 5104 const val LOWER = 5105 const val MAGE = 5106 - const val MAGIC = 5107 const val MATERIAL = 5108 const val MAX_HEAL = 5109 const val MAX_HIT_CRUSH = 5110 @@ -435,7 +434,6 @@ object Params { "locations" -> LOCATIONS "lower" -> LOWER "mage" -> MAGE - "magic" -> MAGIC "material" -> MATERIAL "max_heal" -> MAX_HEAL "max_hit_crush" -> MAX_HIT_CRUSH diff --git a/data/area/fremennik_province/rellekka/ice_strykewyrm_cave/ice_strykewyrm_cave.npcs.toml b/data/area/fremennik_province/rellekka/ice_strykewyrm_cave/ice_strykewyrm_cave.npcs.toml index 16d3b7ab48..dda40b9418 100644 --- a/data/area/fremennik_province/rellekka/ice_strykewyrm_cave/ice_strykewyrm_cave.npcs.toml +++ b/data/area/fremennik_province/rellekka/ice_strykewyrm_cave/ice_strykewyrm_cave.npcs.toml @@ -7,7 +7,7 @@ allowed_under = true att = 225 str = 225 def = 175 -magic = 250 +mage = 250 attack_bonus = 100 slayer_level = 93 slayer_xp = 300.0 diff --git a/data/area/kandarin/feldip_hills/feldip_hills.npcs.toml b/data/area/kandarin/feldip_hills/feldip_hills.npcs.toml index 4e4b2c6679..cb1a0a4ad2 100644 --- a/data/area/kandarin/feldip_hills/feldip_hills.npcs.toml +++ b/data/area/kandarin/feldip_hills/feldip_hills.npcs.toml @@ -90,7 +90,7 @@ allowed_under = true att = 150 str = 150 def = 100 -magic = 150 +mage = 150 attack_bonus = 60 slayer_level = 73 slayer_xp = 110.0 diff --git a/data/area/kharidian_desert/al_kharid/desert_strykewyrm/desert_strykewyrm.npcs.toml b/data/area/kharidian_desert/al_kharid/desert_strykewyrm/desert_strykewyrm.npcs.toml index f7d6f65efb..be1cf6e809 100644 --- a/data/area/kharidian_desert/al_kharid/desert_strykewyrm/desert_strykewyrm.npcs.toml +++ b/data/area/kharidian_desert/al_kharid/desert_strykewyrm/desert_strykewyrm.npcs.toml @@ -8,7 +8,7 @@ att = 175 str = 175 def = 125 range = 200 -magic = 150 +mage = 150 attack_bonus = 80 slayer_level = 77 slayer_xp = 120.0 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 c97a100f54..cec27f9083 100644 --- a/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml +++ b/data/area/kharidian_desert/pollnivneach/dungeon/pollninveach_dungeon.npcs.toml @@ -107,7 +107,7 @@ slayer_xp = 1000.0 att = 200 str = 200 def = 175 -magic = 210 +mage = 210 height = 10 categories = ["basilisk"] hunt_mode = "aggressive" diff --git a/data/area/misthalin/lumbridge/swamp/chasm_of_tears/guthix_temple/guthix_temple.npcs.toml b/data/area/misthalin/lumbridge/swamp/chasm_of_tears/guthix_temple/guthix_temple.npcs.toml index 43a8e6d088..503a2fb418 100644 --- a/data/area/misthalin/lumbridge/swamp/chasm_of_tears/guthix_temple/guthix_temple.npcs.toml +++ b/data/area/misthalin/lumbridge/swamp/chasm_of_tears/guthix_temple/guthix_temple.npcs.toml @@ -21,7 +21,7 @@ hitpoints = 3260 att = 255 str = 255 def = 150 -magic = 255 +mage = 255 range = 255 slayer_xp = 1065.0 height = 60 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 9e7f529203..9b099fb83f 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 @@ -165,7 +165,7 @@ hitpoints = 400 att = 55 str = 60 def = 55 -magic = 40 +mage = 40 range = 1 slayer_xp = 40.0 combat_def = "vampyre" diff --git a/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml b/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml index f203839ff4..429ad18538 100644 --- a/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml +++ b/data/area/wilderness/chaos_tunnels/chaos_tunnels.npcs.toml @@ -103,7 +103,7 @@ att = 40 str = 55 def = 40 range = 1 -magic = 1 +mage = 1 combat_def = "possessed_pickaxe" respawn_delay = 30 drop_table = "possessed_pickaxe" @@ -120,7 +120,7 @@ drop_table = "animated_spade" id = 7138 hitpoints = 880 # Made up stats -magic = 100 +mage = 100 def = 80 combat_def = "dagonhai_monk" drop_table = "dagonhai_monk" diff --git a/data/entity/npc/animal/crab/crab.npcs.toml b/data/entity/npc/animal/crab/crab.npcs.toml index 9f6a30b05b..3de2a81e45 100644 --- a/data/entity/npc/animal/crab/crab.npcs.toml +++ b/data/entity/npc/animal/crab/crab.npcs.toml @@ -21,7 +21,7 @@ hitpoints = 500 att = 1 str = 1 def = 1 -magic = 1 +mage = 1 combat_def = "rock_crab" slayer_xp = 50.0 hunt_mode = "aggressive" diff --git a/data/entity/npc/monster/rock/rock_lobster/rock_lobster.npcs.toml b/data/entity/npc/monster/rock/rock_lobster/rock_lobster.npcs.toml index b3100f3508..9dca87a459 100644 --- a/data/entity/npc/monster/rock/rock_lobster/rock_lobster.npcs.toml +++ b/data/entity/npc/monster/rock/rock_lobster/rock_lobster.npcs.toml @@ -11,7 +11,7 @@ id = 2890 att = 100 str = 100 def = 100 -magic = 1 +mage = 1 hitpoints = 1500 combat_def = "rock_lobster" wander_range = 5 diff --git a/data/entity/npc/monster/wallasalki/wallasalki.npcs.toml b/data/entity/npc/monster/wallasalki/wallasalki.npcs.toml index cc308c16cc..b7b488bc79 100644 --- a/data/entity/npc/monster/wallasalki/wallasalki.npcs.toml +++ b/data/entity/npc/monster/wallasalki/wallasalki.npcs.toml @@ -4,7 +4,7 @@ hitpoints = 1200 att = 10 str = 10 def = 80 -magic = 100 +mage = 100 combat_def = "wallasalki" slayer_xp = 120.0 wander_range = 5 From 7084610c82744b35822a452884ac6d3be09c7ec7 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 14 Apr 2026 18:17:35 +0100 Subject: [PATCH 4/5] Add aggressive retarget hunt mode --- data/entity/npc/hunt_modes.toml | 10 ++++++++++ .../kotlin/content/entity/npc/combat/Aggression.kt | 9 +++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/data/entity/npc/hunt_modes.toml b/data/entity/npc/hunt_modes.toml index c2addaf517..58f38fc6ab 100644 --- a/data/entity/npc/hunt_modes.toml +++ b/data/entity/npc/hunt_modes.toml @@ -109,3 +109,13 @@ check_not_too_strong = false check_not_combat = false check_not_combat_self = false check_not_busy = false + +# Aggressive and continue hunting +[aggressive_retarget] +type = "player" +check_visual = "line_of_sight" +check_not_too_strong = false +check_not_combat = false +check_not_combat_self = false +check_not_busy = false +find_keep_hunting = true \ No newline at end of file diff --git a/game/src/main/kotlin/content/entity/npc/combat/Aggression.kt b/game/src/main/kotlin/content/entity/npc/combat/Aggression.kt index a87f5aa23c..25a1119f2e 100644 --- a/game/src/main/kotlin/content/entity/npc/combat/Aggression.kt +++ b/game/src/main/kotlin/content/entity/npc/combat/Aggression.kt @@ -15,8 +15,10 @@ class Aggression : Script { init { huntPlayer(mode = "aggressive", handler = ::playerHandler) - huntPlayer(mode = "aggressive_intolerant", handler = ::playerHandler) + huntPlayer(mode = "aggressive_retarget") { + playerHandler(this, it, switch = true) + } huntPlayer(mode = "cowardly") { target -> if (!Settings["world.npcs.aggression", true] || attacking(this, target)) { @@ -30,7 +32,6 @@ class Aggression : Script { huntNPC(mode = "aggressive", handler = ::npcHandler) huntNPC(mode = "aggressive_intolerant", handler = ::npcHandler) - huntNPC(mode = "cowardly") { target -> if (attacking(this, target)) { return@huntNPC @@ -39,8 +40,8 @@ class Aggression : Script { } } - fun playerHandler(npc: NPC, target: Player) { - if (!Settings["world.npcs.aggression", true] || attacking(npc, target)) { + fun playerHandler(npc: NPC, target: Player, switch: Boolean = false) { + if (!Settings["world.npcs.aggression", true] || !switch && attacking(npc, target)) { return } if (Settings["world.npcs.safeZone", false] && npc.tile in Areas["lumbridge"]) { From 2f953118005f30e03ee0fe781f834036963a034d Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 14 Apr 2026 18:37:48 +0100 Subject: [PATCH 5/5] Add corporeal beast --- .../corporeal_beast_lair.combat.toml | 12 -- ....toml => corporeal_beasts_lair.anims.toml} | 10 +- .../corporeal_beasts_lair.areas.toml | 4 + .../corporeal_beasts_lair.combat.toml | 53 +++++++++ .../corporeal_beasts_lair.drops.toml | 73 ++++++++++++ .../corporeal_beasts_lair.gfx.toml | 31 +++++ .../corporeal_beasts_lair.npcs.toml | 18 ++- .../modal/chat_box/warnings.ifaces.toml | 15 +++ .../corporeal_beasts_lair/CorporealBeast.kt | 111 ++++++++++++++++++ .../CorporealBeastsLair.kt | 18 ++- .../corporeal_beasts_lair/DarkEnergyCore.kt | 35 ++++++ .../kotlin/content/entity/combat/Target.kt | 22 ++-- .../content/entity/combat/hit/Damage.kt | 4 +- .../content/entity/death/PlayerDeath.kt | 9 +- .../content/entity/player/equip/Equipment.kt | 2 + .../content/entity/proj/ShootProjectile.kt | 28 ++++- .../kotlin/content/skill/prayer/Prayer.kt | 5 + 17 files changed, 418 insertions(+), 32 deletions(-) delete mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml rename data/area/realm/corporeal_beasts_lair/{corporeal_beast_lair.anims.toml => corporeal_beasts_lair.anims.toml} (69%) create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.areas.toml create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.combat.toml create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.drops.toml create mode 100644 data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.gfx.toml create mode 100644 game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeast.kt create mode 100644 game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/DarkEnergyCore.kt diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml deleted file mode 100644 index b62c47066b..0000000000 --- a/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.combat.toml +++ /dev/null @@ -1,12 +0,0 @@ -[corporeal_beast] -attack_speed = 4 -retreat_range = 4 -defend_anim = "ahrim_staff_defend" -defend_sound = "wight_defend" -death_anim = "human_death" -death_sound = "wight_death" - -[corporeal_beast.melee] -chance = 40 -range = 1 - diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.anims.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.anims.toml similarity index 69% rename from data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.anims.toml rename to data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.anims.toml index 7bcda3705c..349529288d 100644 --- a/data/area/realm/corporeal_beasts_lair/corporeal_beast_lair.anims.toml +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.anims.toml @@ -1,5 +1,5 @@ [corporeal_beast_stomp] -id = 10496 # gfx 1834 +id = 10496 [corporeal_beast_slap] id = 10057 @@ -8,10 +8,16 @@ id = 10057 id = 10058 [corporeal_beast_magic] -id = 10410 # gfx 1823+ +id = 10410 [corporeal_beast_defend] id = 10386 [corporeal_beast_death] id = 10385 + +[dark_core_take_off] +id = 10393 + +[dark_core_death] +id = 10391 \ No newline at end of file diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.areas.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.areas.toml new file mode 100644 index 0000000000..3c3924a2a0 --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.areas.toml @@ -0,0 +1,4 @@ +[corporeal_beasts_lair] +x = [2972, 3001] +y = [4370, 4397] +level = 2 \ No newline at end of file diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.combat.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.combat.toml new file mode 100644 index 0000000000..60820feaf2 --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.combat.toml @@ -0,0 +1,53 @@ +[corporeal_beast] +attack_speed = 4 +retreat_range = 16 +defend_anim = "corporeal_beast_defend" +defend_sound = "corporeal_beast_defend" +death_anim = "corporeal_beast_death" +death_sound = "corporeal_beast_death" + +[corporeal_beast.melee] +chance = 40 +range = 1 +anim = "corporeal_beast_swipe" +target_hit = { offense = "crush", max = 330 } + +[corporeal_beast.magic] +chance = 20 +range = 10 +anim = "corporeal_beast_magic" +projectile_origin = "centre" +projectile = "corporeal_beast_magic_travel" +target_hit = { offense = "magic", max = 650 } + +[corporeal_beast.prayer_drain] +chance = 10 +range = 10 +anim = "corporeal_beast_magic" +projectile_origin = "centre" +projectile = "corporeal_beast_stat_travel" +target_hit = { offense = "magic", max = 550 } +impact_drain = { skill = "prayer", min = 1, max = 2 } + +[corporeal_beast.magic_drain] +clone = "corporeal_beast.prayer_drain" +impact_drain = { skill = "magic", min = 1, max = 2 } + +[corporeal_beast.magic_area] +chance = 20 +range = 10 +anim = "corporeal_beast_magic" + +[dark_energy_core] +attack_speed = 2 +death_anim = "dark_core_death" + +[dark_energy_core.attack] +chance = 10 +range = 3 +multi_radius = 3 +target_hit = { offense = "damage", min = 10, max = 130 } +impact_message = "The dark core creature steals some life from you for its master." + +[dark_energy_core.hop] +range = 20 \ No newline at end of file diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.drops.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.drops.toml new file mode 100644 index 0000000000..bb759c2747 --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.drops.toml @@ -0,0 +1,73 @@ +[corporeal_beast_drop_table] +type = "all" +drops = [ + { table = "corporeal_beast_secondary" }, + { table = "corporeal_beast_tertiary" }, + { table = "corporeal_beast_charms" }, +] + +[corporeal_beast_secondary] +roll = 512 +drops = [ + { id = "mystic_air_staff", chance = 10 }, + { id = "mystic_water_staff", chance = 10 }, + { id = "mystic_earth_staff", chance = 10 }, + { id = "mystic_fire_staff", chance = 10 }, + { id = "spirit_shield", chance = 8 }, + { id = "holy_elixir", chance = 3 }, + { id = "adamant_arrow", amount = 750, chance = 16 }, + { id = "runite_bolts", amount = 250, chance = 25 }, + { id = "cannonball", amount = 2000, chance = 17 }, + { id = "mystic_robe_top_blue", chance = 18 }, + { id = "mystic_robe_bottom_blue", min = 1, max = 2, chance = 18 }, + { id = "regen_bracelet", chance = 19 }, + { id = "onyx_bolts_e", amount = 175, chance = 20 }, + { id = "pure_essence_noted", amount = 2500, chance = 21 }, + { id = "law_rune", amount = 250, chance = 17 }, + { id = "cosmic_rune", amount = 500, chance = 17 }, + { id = "death_rune", amount = 300, chance = 17 }, + { id = "soul_rune", amount = 250, chance = 32 }, + { id = "adamantite_ore_noted", amount = 125, chance = 17 }, + { id = "runite_ore_noted", amount = 20, chance = 12 }, + { id = "adamant_bar_noted", amount = 35, chance = 18 }, + { id = "teak_plank_noted", amount = 100, chance = 10 }, + { id = "mahogany_logs_noted", amount = 150, chance = 12 }, + { id = "magic_logs_noted", amount = 75, chance = 12 }, + { id = "raw_shark_noted", amount = 70, chance = 21 }, + { id = "white_berries_noted", amount = 120, chance = 15 }, + { id = "desert_goat_horn_noted", amount = 120, chance = 15 }, + { id = "watermelon_seed", amount = 24, chance = 15 }, + { id = "ranarr_seed", min = 10, max = 15, chance = 5 }, + { id = "tuna_potato", amount = 30, chance = 21 }, + { id = "green_dragonhide_noted", amount = 100, chance = 18 }, + { id = "antipoison++_4_noted", amount = 40, chance = 10 }, + { id = "coins", min = 20000, max = 50000, chance = 10 }, + { id = "crystal_key" }, + { table = "corporeal_beast_sigils" }, + { table = "gem_drop_table", chance = 12 }, +] + +[corporeal_beast_sigils] +roll = 5 +drops = [ + { id = "spectral_sigil", chance = 2 }, + { id = "arcane_sigil" }, + { id = "elysian_sigil" }, + { id = "divine_sigil" }, +] + +[corporeal_beast_tertiary] +roll = 512 +drops = [ + { table = "hard_clue_scroll", chance = 2 }, + { table = "elite_clue_scroll", chance = 2 }, +] + +[corporeal_beast_charms] +roll = 1000 +drops = [ + { id = "gold_charm", amount = 13, chance = 239 }, + { id = "green_charm", amount = 13, chance = 119 }, + { id = "crimson_charm", amount = 13, chance = 239 }, + { id = "blue_charm", amount = 13, chance = 382 }, +] \ No newline at end of file diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.gfx.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.gfx.toml new file mode 100644 index 0000000000..41e381644b --- /dev/null +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.gfx.toml @@ -0,0 +1,31 @@ +[corporeal_beast_stomp] +id = 1834 + +[corporeal_beast_stat_travel] +id = 1823 +curve = 16 +time_offset = 10 +multiplier = 15 + +[corporeal_beast_area_travel] +id = 1824 +curve = 16 +end_height = 0 +time_offset = 10 +multiplier = 15 + +[corporeal_beast_magic_travel] +id = 1825 +curve = 16 +time_offset = 10 +multiplier = 15 + +[dark_energy_core_travel] +id = 1828 +height = 40 +time_offset = 10 +multiplier = 15 + +[corporeal_beast_magic_impact] +id = 1806 +height = 0 diff --git a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml index 6347249bb7..0c0f6f6aec 100644 --- a/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml +++ b/data/area/realm/corporeal_beasts_lair/corporeal_beasts_lair.npcs.toml @@ -4,11 +4,25 @@ hitpoints = 20000 att = 320 str = 320 def = 310 -magic = 350 +mage = 350 range = 150 attack_bonus = 50 -hunt_mode = "aggressive" +hunt_mode = "aggressive_retarget" +allowed_under = true +combat_def = "corporeal_beast" +respawn_delay = 50 +immune_poison = true examine = "A vision of supernatural horror." [dark_energy_core] id = 8127 +hitpoints = 250 +att = 1 +str = 1 +def = 20 +mage = 1 +range = 1 +combat_def = "dark_energy_core" +hunt_mode = "aggressive_retarget" +drop_table = "ashes" +examine = "A small being of dark energy." diff --git a/data/entity/player/modal/chat_box/warnings.ifaces.toml b/data/entity/player/modal/chat_box/warnings.ifaces.toml index 3c2aefaa52..f58c4ab087 100644 --- a/data/entity/player/modal/chat_box/warnings.ifaces.toml +++ b/data/entity/player/modal/chat_box/warnings.ifaces.toml @@ -524,3 +524,18 @@ id = 21 [.dont_ask] id = 20 +[warning_corporeal_beast] +id = 650 +type = "main_screen" + +[.yes] +id = 17 + +[.no] +id = 18 + +[.ask_again] +id = 21 + +[.dont_ask] +id = 20 diff --git a/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeast.kt b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeast.kt new file mode 100644 index 0000000000..e5657887d3 --- /dev/null +++ b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeast.kt @@ -0,0 +1,111 @@ +package content.area.realm.corporeal_beasts_lair + +import content.entity.combat.hit.Damage +import content.entity.combat.hit.hit +import content.entity.gfx.areaGfx +import content.entity.proj.shoot +import content.entity.proj.shootNearest +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.data.definition.Areas +import world.gregs.voidps.engine.entity.character.Character +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.Players +import world.gregs.voidps.engine.entity.character.player.skill.Skill +import world.gregs.voidps.engine.queue.softQueue +import world.gregs.voidps.engine.timer.CLIENT_TICKS +import world.gregs.voidps.engine.timer.Timer +import world.gregs.voidps.type.Direction +import world.gregs.voidps.type.Tile +import world.gregs.voidps.type.random + +class CorporealBeast : Script { + init { + npcSpawn("corporeal_beast") { + softTimers.start("corp_stomp") + } + + npcTimerStart("corp_stomp") { 7 } + + npcTimerTick("corp_stomp") { + var found = false + for (tile in tile.toCuboid(size, size)) { + for (player in Players.at(tile)) { + found = true + hit(player, offensiveType = "damage", damage = Damage.roll(this, player, offensiveType = "damage", range = 300..510)) + } + } + if (found) { + anim("corporeal_beast_stomp") + gfx("corporeal_beast_stomp") + } + + val lair = Areas["corporeal_beasts_lair"] + val count = Players.count { it.tile in lair } + if (count >= 8) { + levels.restore(Skill.Constitution, 250 + (count * 50)) + } else if (count == 0) { + levels.restore(Skill.Constitution, 250) + } + Timer.CONTINUE + } + + // TODO stat regen every 20t + + npcCombatDamage("corporeal_beast") { + if (it.damage < 320) { + return@npcCombatDamage + } + spawnDarkCore(this, it.source) + } + + npcCombatAttack("corporeal_beast") { + if (levels.get(Skill.Constitution) >= 10000) { + return@npcCombatAttack + } + spawnDarkCore(this, it.target) + } + + npcAttack("corporeal_beast", "magic_area") { target -> + val tile = target.tile + val time = shootNearest("corporeal_beast_area_travel", target.tile) + areaGfx("corporeal_beast_magic_impact", tile.add(1, -1), delay = time) + val cuboid = tile.toCuboid(3) + for (i in 1..6) { + val target = cuboid.random() + val delay = tile.shoot("corporeal_beast_area_travel", target, delay = time) + areaGfx("corporeal_beast_magic_impact", target.add(1, -1), delay = time + delay) + areaOfEffect(this, i, target, delay, 300) + } + areaOfEffect(this, 0, tile, time, 400) + } + } + + fun areaOfEffect(source: NPC, i: Int, tile: Tile, time: Int, damage: Int) { + source.softQueue("area_of_effect_$i", CLIENT_TICKS.toTicks(time)) { + for (player in Players.at(tile)) { + source.hit(player, delay = 0, offensiveType = "magic", damage = Damage.roll(source, player, offensiveType = "magic", range = 0..damage)) + } + for (dir in Direction.all) { + for (player in Players.at(tile.add(dir))) { + source.hit(player, delay = 0, offensiveType = "magic", damage = Damage.roll(source, player, offensiveType = "magic", range = 0..(damage - 100))) + } + } + } + } + + fun spawnDarkCore(source: NPC, target: Character) { + if (random.nextInt(8) != 0) { + return + } + val core = NPCs.findOrNull(source.tile.regionLevel, "dark_energy_core") + if (core != null) { + return + } + val tile = target.tile + val delay = source.shoot("dark_energy_core_travel", target) + source.softQueue("core_spawn", CLIENT_TICKS.toTicks(delay)) { + NPCs.add("dark_energy_core", tile) + } + } +} diff --git a/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt index e06552c3d3..1103aa708f 100644 --- a/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt +++ b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/CorporealBeastsLair.kt @@ -2,7 +2,10 @@ package content.area.realm.corporeal_beasts_lair import content.entity.player.dialogue.type.warning 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.character.move.tele +import world.gregs.voidps.engine.entity.character.player.Players class CorporealBeastsLair : Script { init { @@ -16,15 +19,22 @@ class CorporealBeastsLair : Script { objectOperate("Go-through", "corporeal_beast_lair_door") { (target) -> if (tile.x <= target.tile.x) { - if (warning("corporeal_beast")) - tele(target.tile.add(3, 2)) + if (warning("corporeal_beast")) { + tele(target.tile.add(3, 2)) + } } else { tele(target.tile.add(-1, 2)) } } objectOperate("Peek-in", "corporeal_beast_lair_door") { (target) -> - // TODO message + // TODO proper message + val lair = Areas["corporeal_beasts_lair"] + if (Players.count { it.tile in lair } > 0) { + message("The lair is occupied with foes trying to defeat the beast.") + } else { + message("The lair is empty.") + } } } -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/DarkEnergyCore.kt b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/DarkEnergyCore.kt new file mode 100644 index 0000000000..4ada81c14f --- /dev/null +++ b/game/src/main/kotlin/content/area/realm/corporeal_beasts_lair/DarkEnergyCore.kt @@ -0,0 +1,35 @@ +package content.area.realm.corporeal_beasts_lair + +import content.entity.proj.shoot +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.entity.character.move.tele +import world.gregs.voidps.engine.entity.character.npc.NPCs +import world.gregs.voidps.engine.entity.character.player.skill.Skill +import world.gregs.voidps.engine.queue.strongQueue +import world.gregs.voidps.engine.timer.CLIENT_TICKS + +class DarkEnergyCore : Script { + init { + npcCombatAttack("dark_energy_core") { + val corp = NPCs.findOrNull(tile.regionLevel, "corporeal_beast") ?: return@npcCombatAttack + corp.levels.restore(Skill.Constitution, it.damage) + } + + npcAttack("dark_energy_core", "hop") { target -> + val tile = target.tile + face(target) + anim("dark_core_take_off") + strongQueue("hop", 1) { + hide = true + val time = this@npcAttack.tile.shoot("dark_energy_core_travel", tile) + delay(CLIENT_TICKS.toTicks(time)) + tele(tile) + hide = false + } + } + + npcVariableSet("poison", "dark_energy_core") { _, _, to -> + set("attack_speed", if (to == 0) 2 else 12) + } + } +} diff --git a/game/src/main/kotlin/content/entity/combat/Target.kt b/game/src/main/kotlin/content/entity/combat/Target.kt index 93985f4bf6..cd411d97f7 100644 --- a/game/src/main/kotlin/content/entity/combat/Target.kt +++ b/game/src/main/kotlin/content/entity/combat/Target.kt @@ -8,6 +8,7 @@ import content.entity.combat.hit.Hit import content.entity.combat.hit.directHit import content.entity.effect.transform import content.entity.player.equip.Equipment +import content.skill.melee.weapon.combatStyle import content.skill.ranged.ammo import content.skill.slayer.categories import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap @@ -126,14 +127,21 @@ object Target { * Damage caps which Guthans doesn't work on * E.g. Kurask & Turoth */ - fun damageModifiers(source: Character, target: Character, damage: Int): Int { - if (source is NPC && target is Player) { - val hat = target.equipped(EquipSlot.Hat).id - if (source.id == "banshee" && !Equipment.isEarmuffs(hat)) { - return 80 + fun damageModifiers(source: Character, target: Character, type: String, weapon: Item, damage: Int): Int { + if (source is NPC) { + if (target is Player) { + val hat = target.equipped(EquipSlot.Hat).id + if (source.id == "banshee" && !Equipment.isEarmuffs(hat)) { + return 80 + } else if (source.id == "aberrant_spectre" && !Equipment.isNosePeg(hat)) { + return 160 + } } - if (source.id == "aberrant_spectre" && !Equipment.isNosePeg(hat)) { - return 160 + if (source.id == "corporeal_beast" && (Hit.meleeType(type) || type == "magic")) { + if (target is Player && Equipment.isCorpbaneWeapon(weapon.id) && target.combatStyle == "stab") { + return damage + } + return damage / 2 } } return damage diff --git a/game/src/main/kotlin/content/entity/combat/hit/Damage.kt b/game/src/main/kotlin/content/entity/combat/hit/Damage.kt index 9628305d05..eb87e74ee1 100644 --- a/game/src/main/kotlin/content/entity/combat/hit/Damage.kt +++ b/game/src/main/kotlin/content/entity/combat/hit/Damage.kt @@ -130,7 +130,7 @@ object Damage { damage = Bonus.slayerModifier(source, target, type, damage, damage = true) - damage = Weapon.weaponDamageModifiers(source, target, type, weapon, special, damage) + damage = Weapon.weaponDamageModifiers(source, target, type, weapon, special, damage) // after here damage = Equipment.damageModifiers(source, target, type, damage) @@ -138,7 +138,7 @@ object Damage { damage = Prayer.damageModifiers(source, target, type, weapon, special, damage) - damage = Target.damageModifiers(source, target, damage) + damage = Target.damageModifiers(source, target, type, weapon, damage) damage = BarrowsArmour.damageModifiers(source, target, weapon, damage) diff --git a/game/src/main/kotlin/content/entity/death/PlayerDeath.kt b/game/src/main/kotlin/content/entity/death/PlayerDeath.kt index 9858bf1382..b09b73c6c6 100644 --- a/game/src/main/kotlin/content/entity/death/PlayerDeath.kt +++ b/game/src/main/kotlin/content/entity/death/PlayerDeath.kt @@ -17,6 +17,7 @@ import content.skill.summoning.dismissFamiliar 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.data.definition.Areas import world.gregs.voidps.engine.entity.character.Character import world.gregs.voidps.engine.entity.character.Death import world.gregs.voidps.engine.entity.character.jingle @@ -32,9 +33,11 @@ import world.gregs.voidps.engine.event.AuditLog import world.gregs.voidps.engine.inv.* import world.gregs.voidps.engine.map.Spiral import world.gregs.voidps.engine.queue.strongQueue +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 PlayerDeath : Script { @@ -103,7 +106,11 @@ class PlayerDeath : Script { } // Spawn grave - val time = if (!inWilderness || killer !is Player) Gravestone.spawn(player, tile) else 0 + val time = when { + inWilderness && killer is Player -> 0 + tile in Areas["corporeal_beasts_lair"] -> TimeUnit.SECONDS.toTicks(210) + else -> Gravestone.spawn(player, tile) + } // Drop everything drop(player, Item("bones"), tile, inWilderness, killer, time) drop(player, player.inventory, tile, inWilderness, killer, time) diff --git a/game/src/main/kotlin/content/entity/player/equip/Equipment.kt b/game/src/main/kotlin/content/entity/player/equip/Equipment.kt index 21fae213cd..d4791f0833 100644 --- a/game/src/main/kotlin/content/entity/player/equip/Equipment.kt +++ b/game/src/main/kotlin/content/entity/player/equip/Equipment.kt @@ -111,6 +111,8 @@ object Equipment { return damage } + fun isCorpbaneWeapon(weapon: String) = weapon.contains("_spear") || weapon.contains("_halberd") + fun isTzhaarWeapon(weapon: String) = weapon == "toktz_xil_ak" || weapon == "tzhaar_ket_om" || weapon == "tzhaar_ket_em" || weapon == "toktz_xil_ek" fun isEarmuffs(hat: String) = hat == "masked_earmuffs" || hat == "earmuffs" || hat.startsWith("slayer_helmet") || hat.startsWith("full_slayer_helmet") diff --git a/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt b/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt index 5dda04214c..15cac6bea6 100644 --- a/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt +++ b/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt @@ -91,6 +91,30 @@ fun Character.shootNearest( sourceHeight = this.height, targetHeight = target.height, targetTile = target.tile, + sourceTile = nearestTile(this, target.tile), +) + +fun Character.shootNearest( + id: String, + target: Tile, + delay: Int? = null, + flightTime: Int? = null, + height: Int? = null, + endHeight: Int? = null, + curve: Int? = null, + offset: Int? = null, + size: Int = 1, +) = projectile( + id = id, + flightTime = flightTime, + delay = delay, + startHeight = height, + endHeight = endHeight, + curve = curve, + offset = offset, + sourceHeight = this.height, + targetHeight = size, + targetTile = target, sourceTile = nearestTile(this, target), ) @@ -126,10 +150,10 @@ fun Character.shoot( * Tile dragon breath originates from. * Looks weird imo, but it's the same as OSRS. */ -private fun nearestTile(source: Character, target: Character): Tile { +private fun nearestTile(source: Character, target: Tile): Tile { val half = source.size / 2 val centre = source.tile.add(half, half) - val direction = target.tile.delta(centre).toDirection() + val direction = target.delta(centre).toDirection() return centre.add(direction).add(direction) } diff --git a/game/src/main/kotlin/content/skill/prayer/Prayer.kt b/game/src/main/kotlin/content/skill/prayer/Prayer.kt index 6e7b76389c..d2436fd500 100644 --- a/game/src/main/kotlin/content/skill/prayer/Prayer.kt +++ b/game/src/main/kotlin/content/skill/prayer/Prayer.kt @@ -67,6 +67,11 @@ object Prayer { } when (source) { is NPC if usingProtectionPrayer(source, target, type) -> { + if (source.id == "corporeal_beast" && type == "magic") { + val reduced = damage / 3 + target["protected_damage"] = reduced + return damage - reduced + } target["protected_damage"] = damage return 0 }