diff --git a/cache/src/main/kotlin/world/gregs/voidps/cache/definition/decoder/GraphicDecoder.kt b/cache/src/main/kotlin/world/gregs/voidps/cache/definition/decoder/GraphicDecoder.kt index 4a70ae9422..ee0f6a0506 100644 --- a/cache/src/main/kotlin/world/gregs/voidps/cache/definition/decoder/GraphicDecoder.kt +++ b/cache/src/main/kotlin/world/gregs/voidps/cache/definition/decoder/GraphicDecoder.kt @@ -15,7 +15,7 @@ class GraphicDecoder : DefinitionDecoder(GRAPHICS) { override fun GraphicDefinition.read(opcode: Int, buffer: Reader) { when (opcode) { - 1 -> modelId = buffer.readShort() + 1 -> modelId = buffer.readUnsignedShort() 2 -> animationId = buffer.readShort() 4 -> sizeXY = buffer.readShort() 5 -> sizeZ = buffer.readShort() diff --git a/data/area/asgarnia/mudskipper_point/asgarnian_ice_dungeon/resource_dungeon/asgarnian_ice_resource_dungeon.npcs.toml b/data/area/asgarnia/mudskipper_point/asgarnian_ice_dungeon/resource_dungeon/asgarnian_ice_resource_dungeon.npcs.toml index cd9cb2afec..370a893ab4 100644 --- a/data/area/asgarnia/mudskipper_point/asgarnian_ice_dungeon/resource_dungeon/asgarnian_ice_resource_dungeon.npcs.toml +++ b/data/area/asgarnia/mudskipper_point/asgarnian_ice_dungeon/resource_dungeon/asgarnian_ice_resource_dungeon.npcs.toml @@ -1,17 +1,33 @@ [frost_dragon] id = 11633 +hitpoints = 230 +att = 180 +str = 150 +def = 150 +mage = 150 +height = 25 +combat_def = "frost_dragon" +drop_table = "frost_dragon" +wander_range = 4 +hunt_mode = "aggressive" +allowed_under = true +slayer_xp = 235.5 +categories = ["dragons", "frost_dragons"] +respawn_delay = 30 +examine = "A dragon covered in frost and ice." [frost_dragon_2] id = 11634 +clone = "frost_dragon" [frost_dragon_3] id = 11635 +clone = "frost_dragon" [frost_dragon_4] id = 11636 +clone = "frost_dragon" [frost_dragon_5] id = 51 -categories = ["dragons"] -examine = "A dragon covered in frost and ice." - +clone = "frost_dragon" \ No newline at end of file diff --git a/data/entity/npc/monster/draconic/dragon.anims.toml b/data/entity/npc/monster/draconic/dragon.anims.toml index a0240a7d64..64a76e1bcc 100644 --- a/data/entity/npc/monster/draconic/dragon.anims.toml +++ b/data/entity/npc/monster/draconic/dragon.anims.toml @@ -60,3 +60,18 @@ id = 14249 [metal_dragon_shoot] id = 14252 + +[frost_dragon_attack] +id = 13151 + +[frost_dragon_breath_close] +id = 13152 + +[frost_dragon_death] +id = 13153 + +[frost_dragon_block] +id = 13154 + +[frost_dragon_shoot] +id = 13155 \ No newline at end of file diff --git a/data/entity/npc/monster/draconic/dragon.drops.toml b/data/entity/npc/monster/draconic/dragon.drops.toml index 65b7e61b7a..e857b20fcf 100644 --- a/data/entity/npc/monster/draconic/dragon.drops.toml +++ b/data/entity/npc/monster/draconic/dragon.drops.toml @@ -319,4 +319,65 @@ drops = [ type = "all" drops = [ { id = "babydragon_bones" } -] \ No newline at end of file +] + +[frost_dragon_drop_table] +type = "all" +drops = [ + { id = "frost_dragon_bones" }, + { table = "frost_dragon_secondary" }, + { table = "frost_dragon_tertiary" }, + { table = "hard_clue_scroll", chance = 128 }, +] +[frost_dragon_secondary] +roll = 512 +drops = [ + { id = "adamant_kiteshield", chance = 8 }, + { id = "adamant_platebody", chance = 8 }, + { id = "rune_dagger", chance = 2 }, + { id = "rune_longsword", chance = 8 }, + { id = "rune_spear" }, + { id = "rune_arrow", amount = 12, chance = 32 }, + { id = "rune_javelin", amount = 5, chance = 2 }, + { id = "water_rune", amount = 14, chance = 2 }, + { id = "law_rune", amount = 10, chance = 8 }, + { id = "blood_rune", amount = 10, chance = 8 }, + { id = "death_rune", min = 10, max = 15, chance = 32 }, + { id = "water_talisman_noted", amount = 2, chance = 32 }, + { id = "air_talisman_noted", amount = 2, chance = 32 }, + { id = "pure_essence_noted", amount = 50, chance = 8 }, + { id = "nature_talisman", chance = 8 }, + { id = "uncut_sapphire", chance = 8 }, + { id = "uncut_emerald", chance = 8 }, + { id = "uncut_ruby", chance = 8 }, + { id = "uncut_diamond", chance = 2 }, + { id = "uncut_dragonstone"}, + { id = "silver_ore_noted", amount = 100 }, + { id = "adamant_bar_noted", amount = 3, chance = 2 }, + { id = "grimy_guam_noted", chance = 32 }, + { id = "grimy_marrentill_noted", chance = 32 }, + { id = "grimy_tarromin_noted", chance = 32 }, + { id = "grimy_harralander_noted", chance = 32 }, + { id = "grimy_ranarr_noted", chance = 32 }, + { id = "grimy_irit_noted", chance = 32 }, + { id = "grimy_avantoe_noted", chance = 32 }, + { id = "grimy_kwuarm_noted", chance = 32 }, + { id = "grimy_cadantine_noted", chance = 32 }, + { id = "grimy_lantadyme_noted", chance = 32 }, + { id = "grimy_dwarf_weed_noted", chance = 32 }, +] + +[frost_dragon_tertiary] +roll = 10000 +drops = [ + { id = "coins", min = 200, max = 1337, chance = 32 }, + { id = "draconic_visage" }, + { id = "limpwurt_root_noted", chance = 8 }, + { id = "mahogany_logs_noted", amount = 3, chance = 8 }, + { id = "shark", min = 1, max = 2, chance = 32 }, + { id = "shield_left_half" }, + { id = "water_orb_noted", amount = 2, chance = 8 }, + { id = "tooth_half_of_a_key" }, + { id = "loop_half_of_a_key" }, + { id = "starved_ancient_effigy", chance = 2 }, +] diff --git a/data/entity/npc/monster/draconic/dragon.gfx.toml b/data/entity/npc/monster/draconic/dragon.gfx.toml index 7f19a1fb08..10b930b347 100644 --- a/data/entity/npc/monster/draconic/dragon.gfx.toml +++ b/data/entity/npc/monster/draconic/dragon.gfx.toml @@ -31,4 +31,11 @@ time_offset = 20 multiplier = 0 [dragon_breath_shoot] -id = 2465 \ No newline at end of file +id = 2465 + +[frost_dragon_breath_ranged] +id = 2464 +delay = 40 + +[frost_dragon_orb] +id = 2875 \ No newline at end of file diff --git a/data/entity/npc/monster/draconic/frost_dragon.combat.toml b/data/entity/npc/monster/draconic/frost_dragon.combat.toml new file mode 100644 index 0000000000..16fab50da3 --- /dev/null +++ b/data/entity/npc/monster/draconic/frost_dragon.combat.toml @@ -0,0 +1,60 @@ +[frost_dragon] +retreat_range = 8 +defend_anim = "frost_dragon_block" +defend_sound = "dragon_defend" +death_anim = "frost_dragon_death" +death_sound = "dragon_death" + +[frost_dragon.melee] +chance = 75 +range = 1 +anim = "frost_dragon_attack" +target_hit = { offense = "slash", max = 650 } +target_sound = "dragon_attack" + +[frost_dragon.breath_swipe] +chance = 25 +range = 1 +anim = "frost_dragon_breath_close" +gfx = "dragon_breath_shoot" +target_hit = { offense = "dragonfire", special = true, max = 650 } +target_sound = "dragon_breath" + +[frost_dragon.dragonfire_ranged] +chance = 25 +range = 10 +anim = "frost_dragon_shoot" +projectile = "frost_dragon_breath_ranged" +projectile_origin_y = 1 +projectile_origin_x = 1 +target_hit = { offense = "dragonfire", special = true, max = 650 } +target_sound = "dragon_breath" + +[frost_dragon.ice_arrows] +condition = "frost_range" +chance = 25 +range = 10 +anim = "frost_dragon_shoot" +projectile = "ice_arrow" +projectile_origin_y = 1 +projectile_origin_x = 1 +target_hit = { offense = "range", max = 250 } +target_sound = "dragon_attack" + +[frost_dragon.magic] +condition = "frost_magic" +chance = 25 +range = 10 +anim = "frost_dragon_shoot" +projectile = "water_blast" +projectile_origin_y = 1 +projectile_origin_x = 1 +target_hit = { offense = "magic", max = 250 } +target_sound = "dragon_breath" +impact_gfx = "water_blast_impact" + +[frost_dragon.orb] +condition = "no_frost_orb" +chance = 100 +range = 10 +impact_regardless = true \ No newline at end of file diff --git a/game/src/main/kotlin/content/area/asgarnia/asgarnian_ice_dungeon/FrostDragons.kt b/game/src/main/kotlin/content/area/asgarnia/asgarnian_ice_dungeon/FrostDragons.kt new file mode 100644 index 0000000000..4cece6ccf7 --- /dev/null +++ b/game/src/main/kotlin/content/area/asgarnia/asgarnian_ice_dungeon/FrostDragons.kt @@ -0,0 +1,52 @@ +package content.area.asgarnia.asgarnian_ice_dungeon + +import content.entity.proj.shoot +import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.variable.hasClock +import world.gregs.voidps.engine.client.variable.start +import world.gregs.voidps.type.Delta + +class FrostDragons : Script { + + init { + npcAttack("frost_dragon*", "orb") { + start("orb_protection", 8) + start("movement_delay", 8) + val list = listOf(Delta(1, 0), Delta(0, 1), Delta(0, 2), Delta(1, 3), Delta(2, 3), Delta(3, 2), Delta(3, 1), Delta(2, 0), Delta(1, 0)) + var step = 20 + var delay = 0 + for (loop in 0 until 3) { + for (i in 0 until list.lastIndex) { + tile.add(list[i]).shoot( + "frost_dragon_orb", + tile.add(list[i + 1]), + delay = delay, + flightTime = step, + height = 0, + endHeight = 0, + width = 0, + ) + delay += step + } + } + } + + npcCondition("frost_magic") { get("frost_style", "magic") == "magic" } + + npcCondition("frost_range") { get("frost_style", "range") == "range" } + + npcCondition("no_frost_orb") { hasClock("orb_protection") } + + npcAttack("frost_dragon", "ice_arrows") { + set("frost_style", "range") + } + + npcAttack("frost_dragon", "magic") { + set("frost_style", "magic") + } + + npcDeath("frost_dragon*") { + clear("frost_style") + } + } +} diff --git a/game/src/main/kotlin/content/entity/combat/Target.kt b/game/src/main/kotlin/content/entity/combat/Target.kt index fb14ac6177..77f755811d 100644 --- a/game/src/main/kotlin/content/entity/combat/Target.kt +++ b/game/src/main/kotlin/content/entity/combat/Target.kt @@ -5,6 +5,7 @@ import content.area.wilderness.inPvp import content.area.wilderness.inSingleCombat import content.area.wilderness.inWilderness 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.fightStyle @@ -167,6 +168,10 @@ object Target { Hit.meleeType(type) && !weapon.id.startsWith("leaf_bladed") -> 0 else -> damage } + is NPC if target.id.startsWith("frost_dragon") && target.hasClock("orb_protection") -> { + source.directHit(damage, "deflect", source = target) + 0 + } is NPC if target.id == "harpie_bug_swarm" && source is Player && source.equipped(EquipSlot.Shield).id != "lit_bug_lantern" -> 0 is NPC if target.def.contains("damage_cap") -> damage.coerceAtMost(target.def["damage_cap"]) is NPC if target.def.contains("immune_death") -> damage.coerceAtMost(target.levels.get(Skill.Constitution) - 10) diff --git a/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt b/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt index ee99528f31..5dda04214c 100644 --- a/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt +++ b/game/src/main/kotlin/content/entity/proj/ShootProjectile.kt @@ -56,6 +56,7 @@ fun Tile.shoot( endHeight: Int? = null, curve: Int? = null, offset: Int? = null, + width: Int? = null, ) = projectile( id = id, flightTime = flightTime, @@ -66,6 +67,7 @@ fun Tile.shoot( offset = offset, targetTile = tile, sourceTile = this, + width = width ?: 1, ) fun Character.shootNearest(