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