diff --git a/data/definitions/animations.yml b/data/definitions/animations.yml index 8425c0cb9..8dc3b7d31 100644 --- a/data/definitions/animations.yml +++ b/data/definitions/animations.yml @@ -1836,4 +1836,9 @@ rope_walk_fall_right: 771 fall_off_log_left: 2581 fall_off_log_right: 2582 fall_on_floor: 767 -stepping_stone: 769 +stepping_stone_step: 769 +stepping_stone_jump: 741 +skeleton_hit: 5489 +skeleton_death: 5491 +skeleton_crush: 5485 +skeleton_slash: 5487 diff --git a/data/definitions/hunt-modes.yml b/data/definitions/hunt-modes.yml index 0b91e3b79..7764fee74 100644 --- a/data/definitions/hunt-modes.yml +++ b/data/definitions/hunt-modes.yml @@ -9,6 +9,9 @@ aggressive: aggressive_npcs: <<: *aggressive type: npc +aggressive_intolerant: + <<: *aggressive + check_afk: false not_busy: <<: *aggressive check_not_busy: true diff --git a/data/definitions/npcs.yml b/data/definitions/npcs.yml index a5c3b12ec..9d11a260e 100644 --- a/data/definitions/npcs.yml +++ b/data/definitions/npcs.yml @@ -824,7 +824,7 @@ banker_canifis: dororan: id: 1168 race: dwarf - examine: "A dwarf in anguish." + examine: "A dwarf in anguish." yrsa: id: 1301 race: human @@ -963,7 +963,7 @@ ellis: examine: "Manufacturer of fine leathers." dororan_cutscene: id: 2863 - examine: "A dwarf in suspense." + examine: "A dwarf in suspense." gudrun: &gudrun id: 2864 @@ -978,7 +978,7 @@ gudrun_after_cutscene: id: 2866 gudrun_after_cutscene2: <<: *gudrun - id: 2867 + id: 2867 gudrun_after_quest: <<: *gudrun id: 2869 @@ -1379,7 +1379,7 @@ fishing_spot_small_net_bait_lumbridge: lil_lamb: <<: *sheep id: 5146 - examine: "How cute!" + examine: "How cute!" sheep_light: <<: *sheep id: 5157 @@ -1527,7 +1527,7 @@ jeffery2: bob_barter_herbs: id: 6524 race: human - examine: "He's probably seen better days." + examine: "He's probably seen better days." pikkupstix: id: 6970 race: human @@ -1710,29 +1710,29 @@ bat_swept_away: rat_swept_away: id: 8209 examine: "Cheese-eater." -Lizard_swept_away: +lizard_swept_away: id: 8210 examine: "Desert-dweller." -Blackbird_swept_away: +blackbird_swept_away: id: 8211 examine: "Bleak and beaky." -Spider_swept_away: +spider_swept_away: id: 8212 examine: "Isn't eight legs rather excessive?" -Snail_swept_away: +snail_swept_away: id: 8213 examine: "Rather quick, considering." holding_pen_swept_away: id: 8219 bat_pen_swept_away: id: 8220 -Blackbird_pen_swept_away: +blackbird_pen_swept_away: id: 8221 rat_pen_swept_away: id: 8222 -Snail_pen_swept_away: +snail_pen_swept_away: id: 8223 -Spider_pen_swept_away: +spider_pen_swept_away: id: 8224 reptile_pen_swept_away: id: 8225 @@ -2042,7 +2042,7 @@ leela: id: 13172 race: human wander_radius: 4 - examine: "She comes from Al Kharid." + examine: "She comes from Al Kharid." seal: id: 13255 wander_radius: 2 @@ -2109,7 +2109,7 @@ al_the_camel: race: camel large_head: true wander_radius: 4 - examine: "A camel who has the soul of a poet." + examine: "A camel who has the soul of a poet." dark_mage: id: 2262 faces: false @@ -2211,7 +2211,8 @@ zamorak_warrior_square: <<: *zamorak_warrior id: 6364 style: crush -zamorak_mage_fancy: &zamorak_mage +zamorak_mage_fancy: + &zamorak_mage id: 6367 hitpoints: 500 att: 75 @@ -2231,7 +2232,8 @@ zamorak_mage_fancy: &zamorak_mage zamorak_mage: <<: *zamorak_mage id: 6368 -zamorak_ranger: &zamorak_ranger +zamorak_ranger: + &zamorak_ranger id: 6365 hitpoints: 500 att: 75 @@ -2504,3 +2506,81 @@ bartender_foresters_arms: race: human wander_radius: 5 examine: "I could get a beer from him." +skeleton_mace_shield: + &skeleton_25 + id: 92 + hitpoints: 170 + att: 24 + str: 24 + def: 24 + wander_radius: 8 + attack_radius: 4 + max_hit_melee: 40 + hunt_mode: aggressive_intolerant + style: slash + height: 30 + respawn_delay: 60 + race: skeleton + examine: "Could do with gaining a few pounds." +skeleton_flail: + <<: *skeleton_25 + id: 5340 +skeleton_sword_shield: + <<: *skeleton_25 + id: 5338 +skeleton_helmet: + <<: *skeleton_25 + id: 5332 +skeleton_unarmed: + &skeleton_22 + id: 5333 + hitpoints: 290 + att: 15 + str: 18 + def: 17 + wander_radius: 8 + attack_radius: 4 + max_hit_melee: 30 + hunt_mode: aggressive + style: crush + height: 30 + respawn_delay: 70 + race: skeleton + examine: "Could do with gaining a few pounds." +skeleton_shield_helmet: + <<: *skeleton_22 + id: 90 +skeleton_shield: + <<: *skeleton_22 + id: 5334 +skeleton_builder: + <<: *skeleton_22 + id: 3291 +skeleton_axe_shield: + <<: *skeleton_25 + id: 5337 +skeleton_longsword: + <<: *skeleton_25 + id: 5339 +skeleton_axe_shield_85: + &skeleton_85 + id: 5367 + hitpoints: 590 + att: 32 + str: 35 + def: 36 + wander_radius: 8 + attack_radius: 4 + max_hit_melee: 50 + hunt_mode: aggressive + style: slash + height: 30 + respawn_delay: 60 + race: skeleton + examine: "Could do with gaining a few pounds." +skeleton_sword_shield_85: + <<: *skeleton_85 + id: 5368 +skeleton_hammer_shield: + <<: *skeleton_85 + id: 4386 diff --git a/data/definitions/objects.yml b/data/definitions/objects.yml index cb4431b0d..55fa92eea 100644 --- a/data/definitions/objects.yml +++ b/data/definitions/objects.yml @@ -851,10 +851,10 @@ gate_33_opened: gate_33_closed: id: 1991 examine: "Solid bars of iron." -door_44_opened: +wilderness_agility_door_opened: id: 1543 examine: "Solid bars of iron." -door_44_closed: +wilderness_agility_door_closed: id: 2309 door_68_opened: id: 1543 @@ -1077,10 +1077,11 @@ metal_gate_opened: metal_gate_closed: id: 2259 examine: "The gate is closed." -gate_45_opened: +wilderness_agility_gate_east_opened: id: 2040 -gate_45_closed: +wilderness_agility_gate_east_closed: id: 2307 + gate: false gate_53_opened: id: 2040 gate_53_closed: @@ -1133,10 +1134,11 @@ metal_gate_2_opened: metal_gate_2_closed: id: 2260 examine: "The gate is closed." -gate_46_opened: +wilderness_agility_gate_west_opened: id: 2042 -gate_46_closed: +wilderness_agility_gate_west_closed: id: 2308 + gate: false gate_65_opened: id: 2042 gate_65_closed: @@ -11990,3 +11992,24 @@ basic_ladder_second: basic_ladder_top: id: 1746 examine: "I can climb down this." +basic_ladder_up: + id: 32015 + examine: "I can climb this." +wilderness_obstacle_pipe: + id: 2288 + examine: "A pipe I can squeeze through." +wilderness_rope_swing: + id: 2283 + examine: "Use this to swing over crevices." +wilderness_agility_ladder_down: + id: 14758 + examine: "I can climb down this." +wilderness_stepping_stone: + id: 37704 + examine: "Hop, hop, hoppity hop, and then you fall in molten lava." +wilderness_log_balance: + id: 2297 + examine: "A slippery log I can walk across." +wilderness_agility_rocks: + id: 2328 + examine: "A rocky outcrop." diff --git a/data/definitions/render-emotes.yml b/data/definitions/render-emotes.yml index 2a1ecf757..44f72a1f8 100644 --- a/data/definitions/render-emotes.yml +++ b/data/definitions/render-emotes.yml @@ -1,3 +1,4 @@ +climbing: 0 human_stand: 1426 dororan_stand: 1880 rope_balance: 155 diff --git a/data/definitions/sounds.yml b/data/definitions/sounds.yml index 551835712..54579a7b2 100644 --- a/data/definitions/sounds.yml +++ b/data/definitions/sounds.yml @@ -211,4 +211,6 @@ wolves_hit: 912 wolves_attack: 909 wolves_death: 911 bigghost_appear: 1595 -rg_ghost_approach: 1743 \ No newline at end of file +rg_ghost_approach: 1743 +jump: 2461 +2h_stab: 2504 \ No newline at end of file diff --git a/data/definitions/variables-custom.yml b/data/definitions/variables-custom.yml index f19f0a124..8eda162c5 100644 --- a/data/definitions/variables-custom.yml +++ b/data/definitions/variables-custom.yml @@ -493,7 +493,7 @@ agility_course_rewards_claimed: agility_course: format: list persist: true - values: [ gnome, barbarian ] + values: [ gnome, barbarian, wilderness ] barbarian_course_stage: persist: true format: int @@ -507,6 +507,12 @@ alfred_grimhands_barcrawl: persist: true format: list values: [ unstarted, signatures, completed ] +wilderness_course_stage: + persist: true + format: int +wilderness_course_laps: + persist: true + format: int barcrawl_signatures: persist: true format: bitwise diff --git a/data/map/teleports.yml b/data/map/teleports.yml index 6cf09fe16..2a24f31a5 100644 --- a/data/map/teleports.yml +++ b/data/map/teleports.yml @@ -508,7 +508,7 @@ y: 3551 delta: y: 6400 -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 2547 @@ -1015,7 +1015,7 @@ x: 2901 y: 9867 ######## 11599 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 2895 @@ -1024,14 +1024,14 @@ x: 3268 y: 3400 ######## 11670 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 2924 y: 9650 delta: y: -6400 -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 2939 @@ -1046,7 +1046,7 @@ delta: y: -6400 ######## 11673 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 2884 @@ -1536,7 +1536,7 @@ x: 2955 y: 3497 ######## 11837 ######## -- id: 14758 +- id: wilderness_agility_ladder_down option: Climb-down tile: x: 3005 @@ -1544,7 +1544,7 @@ delta: y: 6400 ######## 11926 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 2962 @@ -1562,7 +1562,7 @@ y: -6393 x: 2 ######## 11937 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 3005 @@ -2600,7 +2600,7 @@ x: 2269 y: 4840 ######## 12181 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 3008 @@ -2661,7 +2661,7 @@ to: x: 2271 y: 4680 -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 3017 @@ -2669,7 +2669,7 @@ delta: x: 52 y: -6392 -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 3069 @@ -3108,7 +3108,7 @@ delta: y: -6400 ######## 12437 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 3103 @@ -3124,7 +3124,7 @@ delta: y: -6400 ######## 12439 ######## -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 3084 @@ -3140,7 +3140,7 @@ delta: x: 35 y: -6421 -- id: 32015 +- id: basic_ladder_up option: Climb-up tile: x: 3117 diff --git a/data/spawns/drops.yml b/data/spawns/drops.yml index 6175018a3..225629a1c 100644 --- a/data/spawns/drops.yml +++ b/data/spawns/drops.yml @@ -1701,3 +1701,7 @@ human_pickpocket: drops: - id: coins amount: 3 +skeleton_drop_table: + type: all + drops: + - id: bones diff --git a/data/spawns/npc-spawns.yml b/data/spawns/npc-spawns.yml index b6e9ef5c7..1ff241bdf 100644 --- a/data/spawns/npc-spawns.yml +++ b/data/spawns/npc-spawns.yml @@ -1433,6 +1433,8 @@ - { id: giant_rat_dark_injured, x: 2971, y: 3690 } # 11834 - { id: drunken_musician, x: 3003, y: 3739, direction: SOUTH } +- { id: skeleton_mace_shield, x: 2977, y: 3753 } +- { id: skeleton_mace_shield, x: 2980, y: 3763 } # 11837 - { id: white_wolf_2, x: 2991, y: 3924, members: true } - { id: white_wolf_2, x: 2988, y: 3921, members: true } @@ -1442,6 +1444,9 @@ - { id: white_wolf_2, x: 3002, y: 3924, members: true } - { id: white_wolf_2, x: 3006, y: 3921, members: true } - { id: white_wolf_2, x: 3004, y: 3917, members: true } +- { id: skeleton_flail, x: 2982, y: 3947 } +- { id: skeleton_sword_shield, x: 2989, y: 3944 } +- { id: skeleton_mace_shield, x: 2992, y: 3942 } # 11842 - { id: rat, x: 2960, y: 4280, members: true } - { id: rat, x: 2963, y: 4279, members: true } @@ -1450,6 +1455,15 @@ - { id: rat, x: 2961, y: 9647, members: true } - { id: rat, x: 2976, y: 9634, members: true } - { id: rat, x: 2989, y: 9653, members: true } +# 11937 +- { id: skeleton_axe_shield, x: 2994, y: 10346 } +- { id: skeleton_mace_shield, x: 2998, y: 10342 } +- { id: skeleton_longsword, x: 2998, y: 10350 } +- { id: skeleton_mace_shield, x: 3002, y: 10356 } +- { id: skeleton_sword_shield, x: 3003, y: 10347 } +- { id: skeleton_sword_shield, x: 3004, y: 10362 } +- { id: skeleton_flail, x: 3005, y: 10352 } +- { id: skeleton_axe_shield, x: 3006, y: 10357 } # 12081 - { id: rat, x: 3013, y: 3194 } - { id: rat, x: 3013, y: 3190 } @@ -1484,6 +1498,19 @@ - { id: banker_falador, x: 3015, y: 3353, direction: NORTH } # 12086 - { id: musician_edgeville, x: 3057, y: 3472, direction: SOUTH } +# 12088 +- { id: skeleton_helmet, x: 3008, y: 3595 } +- { id: skeleton_unarmed, x: 3010, y: 3597 } +- { id: skeleton_shield_helmet, x: 3011, y: 3590 } +- { id: skeleton_shield, x: 3012, y: 3592 } +- { id: skeleton_shield, x: 3012, y: 3597 } +- { id: skeleton_unarmed, x: 3013, y: 3602 } +- { id: skeleton_helmet, x: 3016, y: 3589 } +- { id: skeleton_shield_helmet, x: 3016, y: 3596 } +- { id: skeleton_shield, x: 3018, y: 3592 } +- { id: skeleton_shield, x: 3018, y: 3599 } +- { id: skeleton_helmet, x: 3019, y: 3590 } +- { id: skeleton_shield_helmet, x: 3021, y: 3593 } # 12089 - { id: giant_rat, x: 3049, y: 3691 } - { id: giant_rat_dark_injured, x: 3049, y: 3695 } @@ -1633,6 +1660,7 @@ - { id: giant_spider, x: 3135, y: 3340 } - { id: rat, x: 3099, y: 3366 } - { id: rat, x: 3102, y: 3355 } +- { id: skeleton_builder, x: 3110, y: 3367 } # 12341 - { id: goblin_orange_hat_spear, x: 3126, y: 3450 } - { id: goblin_orange_hat_spear, x: 3121, y: 3422 } @@ -1667,6 +1695,31 @@ - { id: jeffery, x: 3108, y: 3500 } # 12343 - { id: mage_of_zamorak_wilderness, x: 3107, y: 3555, members: true } +- { id: skeleton_shield_helmet, x: 3072, y: 3531 } +- { id: skeleton_shield, x: 3074, y: 3532 } +- { id: skeleton_mace_shield, x: 3081, y: 3551 } +- { id: skeleton_helmet, x: 3096, y: 3559 } +- { id: skeleton_axe_shield, x: 3102, y: 3569 } +- { id: skeleton_sword_shield, x: 3103, y: 3567 } +- { id: skeleton_longsword, x: 3104, y: 3566 } +- { id: skeleton_unarmed, x: 3106, y: 3548 } +- { id: skeleton_flail, x: 3106, y: 3567 } +- { id: skeleton_mace_shield, x: 3106, y: 3570 } +- { id: skeleton_shield, x: 3107, y: 3528 } +- { id: skeleton_shield_helmet, x: 3112, y: 3538 } +- { id: skeleton_unarmed, x: 3116, y: 3524 } +- { id: skeleton_helmet, x: 3117, y: 3532 } +# 12346 +- { id: skeleton_axe_shield_85, x: 3092, y: 3717 } +- { id: skeleton_sword_shield_85, x: 3096, y: 3738 } +- { id: skeleton_hammer_shield, x: 3097, y: 3728 } +- { id: skeleton_sword_shield_85, x: 3102, y: 3716 } +- { id: skeleton_axe_shield_85, x: 3105, y: 3721 } +- { id: skeleton_axe_shield_85, x: 3113, y: 3740 } +- { id: skeleton_sword_shield_85, x: 3118, y: 3733 } +- { id: skeleton_hammer_shield, x: 3128, y: 3719 } +- { id: skeleton_sword_shield_85, x: 3128, y: 3741 } +- { id: skeleton_hammer_shield, x: 3130, y: 3754 } # 12436 - { id: combat_instructor, x: 3106, y: 9509 } - { id: mining_instructor, x: 3081, y: 9504 } @@ -1941,6 +1994,10 @@ - { id: rat, x: 3160, y: 3639 } - { id: rat, x: 3156, y: 3634 } - { id: rat, x: 3159, y: 3635 } +# 12603 +- { id: skeleton_mace_shield, x: 3143, y: 3802 } +- { id: skeleton_mace_shield, x: 3145, y: 3779 } +- { id: skeleton_axe_shield, x: 3179, y: 3786 } # 12604 - { id: giant_spider_2, x: 3165, y: 3895 } - { id: giant_spider_2, x: 3171, y: 3894 } @@ -2213,10 +2270,10 @@ # 12870 - { id: holding_pen_swept_away, x: 3231, y: 4523 } - { id: bat_pen_swept_away, x: 3222, y: 4513 } -- { id: Blackbird_pen_swept_away, x: 3231, y: 4513 } +- { id: blackbird_pen_swept_away, x: 3231, y: 4513 } - { id: rat_pen_swept_away, x: 3240, y: 4513 } -- { id: Snail_pen_swept_away, x: 3222, y: 4504 } -- { id: Spider_pen_swept_away, x: 3231, y: 4504 } +- { id: snail_pen_swept_away, x: 3222, y: 4504 } +- { id: spider_pen_swept_away, x: 3231, y: 4504 } - { id: reptile_pen_swept_away, x: 3240, y: 4503 } # 12954 - { id: giant_spider_2, x: 3217, y: 9889 } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Visuals.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Visuals.kt index 3d97ce737..afe526101 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Visuals.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/Visuals.kt @@ -7,6 +7,7 @@ import world.gregs.voidps.engine.entity.character.move.tele import world.gregs.voidps.engine.entity.character.npc.NPC import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.appearance +import world.gregs.voidps.engine.entity.character.player.movementType import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.entity.obj.GameObject import world.gregs.voidps.engine.entity.obj.ObjectShape @@ -15,6 +16,7 @@ import world.gregs.voidps.network.login.protocol.visual.VisualMask import world.gregs.voidps.network.login.protocol.visual.Visuals import world.gregs.voidps.network.login.protocol.visual.update.Hitsplat import world.gregs.voidps.network.login.protocol.visual.update.Turn +import world.gregs.voidps.network.login.protocol.visual.update.player.MoveType import world.gregs.voidps.type.Delta import world.gregs.voidps.type.Direction import world.gregs.voidps.type.Distance @@ -194,10 +196,13 @@ fun Character.exactMove(delta: Delta, delay: Int = tile.distanceTo(tile.add(delt setExactMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction) } -fun Character.exactMove(target: Tile, delay: Int = tile.distanceTo(target) * 30, direction: Direction = Direction.NONE) { +fun Character.exactMove(target: Tile, delay: Int = tile.distanceTo(target) * 30, direction: Direction = Direction.NONE, startDelay: Int = 0) { val start = tile tele(target) - setExactMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction) + if (this is Player) { + movementType = MoveType.Walk + } + setExactMovement(Delta.EMPTY, delay, start.delta(tile), startDelay, direction = direction) } val Character.turn: Delta diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/agility/course/BarbarianOutpost.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/agility/course/BarbarianOutpost.kts index 251b48a93..99c505777 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/agility/course/BarbarianOutpost.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/agility/course/BarbarianOutpost.kts @@ -68,7 +68,7 @@ objectOperate("Swing-on", "barbarian_outpost_rope_swing") { player.damage(50) pause(3) player.walkTo(player.tile.copy(y = 9949), noCollision = true, noRun = true) -// player.message("", ChatType.Filter) TODO + player.message("You slip and fall to the pit below.", ChatType.Filter) } if (success || Settings["agility.disableFailLapSkip", false]) { player.agilityStage(1) diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/agility/course/WildernessCourse.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/agility/course/WildernessCourse.kts new file mode 100644 index 000000000..8b141c00a --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/agility/course/WildernessCourse.kts @@ -0,0 +1,272 @@ +package world.gregs.voidps.world.activity.skill.agility.course + +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.client.variable.start +import world.gregs.voidps.engine.data.Settings +import world.gregs.voidps.engine.entity.character.exactMove +import world.gregs.voidps.engine.entity.character.face +import world.gregs.voidps.engine.entity.character.move.tele +import world.gregs.voidps.engine.entity.character.move.walkTo +import world.gregs.voidps.engine.entity.character.player.chat.ChatType +import world.gregs.voidps.engine.entity.character.player.clearRenderEmote +import world.gregs.voidps.engine.entity.character.player.renderEmote +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 +import world.gregs.voidps.engine.entity.character.player.skill.level.Level.has +import world.gregs.voidps.engine.entity.character.setAnimation +import world.gregs.voidps.engine.entity.obj.GameObjects +import world.gregs.voidps.engine.entity.obj.objectOperate +import world.gregs.voidps.engine.inject +import world.gregs.voidps.engine.queue.Action +import world.gregs.voidps.engine.queue.strongQueue +import world.gregs.voidps.type.Direction +import world.gregs.voidps.type.Tile +import world.gregs.voidps.type.equals +import world.gregs.voidps.world.interact.entity.combat.hit.damage +import world.gregs.voidps.world.interact.entity.obj.door.Door +import world.gregs.voidps.world.interact.entity.sound.playSound + +val objects: GameObjects by inject() + +objectOperate("Open", "wilderness_agility_door_closed") { + if (!player.has(Skill.Agility, 52, message = true)) { + // TODO proper message + return@objectOperate + } + if (player.tile.y > 3916) { + Door.enter(player, target) + return@objectOperate + } + // Not sure if you can fail going up +// val disable = Settings["agility.disableCourseFailure", false] + val success = true//disable || Level.success(player.levels.get(Skill.Agility), 200..250) + player.strongQueue("course_enter") { + onCancel = { + player.tele(target.tile.addY(-1)) + } + player.start("input_delay", if (success) 16 else 8) + player.message("You go through the gate and try to edge over the ridge...", ChatType.Filter) + Door.enter(player, target) + pause() + player.renderEmote = "beam_balance" +// if (!success) { +// fallIntoPit() +// return@strongQueue +// } + player.walkTo(Tile(2998, 3930), noCollision = true, noRun = true) + pause(13) + player.clearRenderEmote() + val gateTile = Tile(2998, 3931) + val gate = objects[gateTile, "wilderness_agility_gate_east_closed"] + if (gate != null) { + Door.enter(player, gate) + } else { + player.walkTo(gateTile, noCollision = true, noRun = true) + } + player.message("You skillfully balance across the ridge...", ChatType.Filter) + player.exp(Skill.Agility, 15.0) + player.agilityCourse("wilderness") + } +} + +objectOperate("Open", "wilderness_agility_gate_east_closed", "wilderness_agility_gate_west_closed") { + if (player.tile.y < 3931) { + Door.enter(player, target) + return@objectOperate + } + val disable = Settings["agility.disableCourseFailure", false] + val success = disable || Level.success(player.levels.get(Skill.Agility), 200..250) + player.strongQueue("course_exit") { + onCancel = { + player.tele(target.tile.addY(1)) + } + player.start("input_delay", if (success) 16 else 10) + player.message("You go through the gate and try to edge over the ridge...", ChatType.Filter) + Door.enter(player, target) + pause(if (target.id.endsWith("west_closed")) 2 else 1) + player.renderEmote = "beam_balance" + if (!success) { + fallIntoPit() + return@strongQueue + } + player.walkTo(Tile(2998, 3917), noCollision = true, noRun = true) + pause(13) + player.clearRenderEmote() + val door = objects[Tile(2998, 3917), "wilderness_agility_door_closed"] + if (door != null) { + Door.enter(player, door) + } else { + player.walkTo(Tile(2998, 3916), noCollision = true, noRun = true) + } + player.message("You skillfully balance across the ridge...", ChatType.Filter) + player.exp(Skill.Agility, 15.0) + } +} + +suspend fun Action.fallIntoPit() { + player.walkTo(Tile(2998, 3924), noCollision = true, noRun = true) + pause(7) + player.clearRenderEmote() + player.face(Direction.NORTH) + player.setAnimation("rope_walk_fall_down") + player.message("You lose your footing and fall into the wolf pit.", ChatType.Filter) + pause() + player.exactMove(Tile(3001, 3923), 25, Direction.SOUTH) +} + +objectOperate("Squeeze-through", "wilderness_obstacle_pipe") { + if (!target.tile.equals(3004, 3938)) { + player.message("You can't enter the pipe from this side.") + return@objectOperate + } + player.strongQueue("wilderness_pipe") { + onCancel = { + player.tele(target.tile.addY(-1)) + } + if (player.tile.y == 3938) { + player.start("input_delay", 2) + player.walkTo(target.tile.addY(-1)) + pause(2) + } + player.start("input_delay", 8) + player.setAnimation("climb_through_pipe", delay = 30) + player.exactMove(Tile(3004, 3940), startDelay = 30, delay = 96, direction = Direction.NORTH) + pause(4) + player.tele(3004, 3947) + pause() + player.setAnimation("climb_through_pipe", delay = 30) + player.exactMove(Tile(3004, 3950), startDelay = 30, delay = 96, direction = Direction.NORTH) + pause(3) + player.exp(Skill.Agility, 12.5) + player.agilityStage(1) + } +} + +objectOperate("Swing-on", "wilderness_rope_swing") { + player.walkTo(target.tile.copy(y = 3953)) + player.clear("face_entity") + player.face(Direction.NORTH) + val disable = Settings["agility.disableCourseFailure", false] + val success = disable || Level.success(player.levels.get(Skill.Agility), 200..250) + player.start("input_delay", if (success) 5 else 8) + player.strongQueue("wilderness_rope_swing", 2) { + player.setAnimation("rope_swing") + target.animate("swing_rope") + pause() + if (success) { + player.exactMove(player.tile.copy(y = 3958), 60, Direction.NORTH) + pause() + player.exp(Skill.Agility, 20.0) + player.message("You skillfully swing across.", ChatType.Filter) + } else { + player.exactMove(player.tile.copy(y = 3957), 50, Direction.NORTH) + pause(2) + player.tele(3004, 10357) + player.damage((player.levels.get(Skill.Constitution) * 0.15).toInt() + 10) + player.message("You slip and fall to the pit below.", ChatType.Filter) + } + if (success || Settings["agility.disableFailLapSkip", false]) { + player.agilityStage(2) + } + } +} + +objectOperate("Cross", "wilderness_stepping_stone") { + player.message("You carefully start crossing the stepping stones...", ChatType.Filter) + player.start("input_delay", 12) + player.strongQueue("agility_stepping_stones") { + onCancel = { + player.tele(3002, 3960) + } + for (i in 0..5) { + player.setAnimation("stepping_stone_jump") + player.playSound("jump") + player.exactMove(target.tile.addX(-i), delay = 30, direction = Direction.WEST, startDelay = 15) + pause(2) + if (i == 2 && !Settings["agility.disableCourseFailure", false] && !Level.success(player.levels.get(Skill.Agility), 180..250)) { + player.start("input_delay", 3) + player.setAnimation("rope_walk_fall_down") + player.face(Direction.WEST) + player.clearRenderEmote() + player.message("...You lose your footing and fall into the lava.", ChatType.Filter) + pause(2) + player.damage(player.levels.get(Skill.Constitution) / 5 + 10) + player.tele(3002, 3963) + if (Settings["agility.disableFailLapSkip", false]) { + player.agilityStage(3) + } + return@strongQueue + } + } + player.message("...You safely cross to the other side.", ChatType.Filter) + player.exp(Skill.Agility, 20.0) + player.agilityStage(3) + } +} + +objectOperate("Walk-across", "wilderness_log_balance") { + player.strongQueue("agility_log") { + onCancel = { + player.tele(3001, 3946) + } + player.message("You walk carefully across the slippery log...", ChatType.Filter) + val disable = Settings["agility.disableCourseFailure", false] + val success = disable || Level.success(player.levels.get(Skill.Agility), 200..250) + if (success) { + player.start("input_delay", 10) + player.walkTo(target.tile, noCollision = true, noRun = true) + pause() + player.renderEmote = "beam_balance" + player.walkTo(Tile(2994, 3945), noCollision = true, noRun = true) + pause(7) + player.message("You skillfully edge across the gap.", type = ChatType.Filter) + player.clearRenderEmote() + pause() + player.exp(Skill.Agility, 20.0) + player.agilityStage(4) + } else { + player.start("input_delay", 9) + player.walkTo(target.tile, noCollision = true, noRun = true) + pause() + player.renderEmote = "beam_balance" + player.walkTo(Tile(2998, 3945), noCollision = true, noRun = true) + pause(4) + player.message("You slip and fall onto the spikes below.", type = ChatType.Filter) + player.setAnimation("rope_walk_fall_down") + player.face(Direction.NORTH) + pause() + player.tele(2998, 10346) + player.clearRenderEmote() + player.playSound("2h_stab") + pause() + player.walkTo(Tile(2998, 10345)) + pause() + player.damage((player.levels.get(Skill.Constitution) * 0.15).toInt() + 10) + player.playSound("male_hit_1", delay = 20) + } + if (success || Settings["agility.disableFailLapSkip", false]) { + player.agilityStage(4) + } + } +} + +objectOperate("Climb", "wilderness_agility_rocks") { + player.start("input_delay", 5) + player.strongQueue("agility_rocks") { + onCancel = { + player.tele(2993, 3937) + } + player.message("You walk carefully across the slippery log...", ChatType.Filter) + player.renderEmote = "climbing" + player.walkTo(player.tile.copy(y = 3933), noCollision = true, noRun = true) + pause(4) + player.clearRenderEmote() + player.message("You reach the top.", type = ChatType.Filter) + if (player.agilityStage == 4) { + player.agilityStage = 0 + player.exp(Skill.Agility, 499.0) + player.inc("wilderness_course_laps") + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Combat.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Combat.kts index 33592a464..4a5c21bf6 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Combat.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Combat.kts @@ -88,6 +88,7 @@ characterDespawn { character -> characterCombatStart { character -> if (target.inSingleCombat) { target.attackers.clear() + target.attacker = character } target.attackers.add(character) retaliate(target, character) diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Target.kt b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Target.kt index 177081643..484d82eba 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Target.kt +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Target.kt @@ -49,7 +49,8 @@ object Target { } } } - if (target.inSingleCombat && target.inCombat && !target.attackers.contains(source) && source.target != target) { + // If the target I'm trying to attack is already in combat and I am not the attacker + if (target.inSingleCombat && target.inCombat && target.attacker != source) { if (target is NPC) { (source as? Player)?.message("Someone else is fighting that.") } else { @@ -57,7 +58,8 @@ object Target { } return false } - if (source.inSingleCombat && source.inCombat && !source.attackers.contains(target) && source.target != target) { + // If I am already in combat and my attempted target is not my attacker + if (source.inSingleCombat && source.inCombat && source.attacker != target) { (source as? Player)?.message("You are already in combat.") return false } @@ -122,6 +124,16 @@ internal var Character.target: Character? val Character.inCombat: Boolean get() = hasClock("in_combat") +var Character.attacker: Character? + get() = get("attacker") + set(value) { + if (value == null) { + clear("attacker") + } else { + set("attacker", value) + } + } + var Character.attackers: MutableList get() = getOrPut("attackers") { ObjectArrayList() } set(value) = set("attackers", value) diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/Aggression.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/Aggression.kts index c1e40b95d..419a02bc8 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/Aggression.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/Aggression.kts @@ -1,6 +1,7 @@ package world.gregs.voidps.world.interact.entity.npc.combat import world.gregs.voidps.engine.data.Settings +import world.gregs.voidps.engine.data.definition.AreaDefinitions import world.gregs.voidps.engine.entity.character.Character import world.gregs.voidps.engine.entity.character.mode.combat.CombatMovement import world.gregs.voidps.engine.entity.character.mode.interact.Interact @@ -9,44 +10,50 @@ import world.gregs.voidps.engine.entity.character.npc.NPCOption import world.gregs.voidps.engine.entity.character.npc.hunt.huntNPC import world.gregs.voidps.engine.entity.character.npc.hunt.huntPlayer import world.gregs.voidps.engine.entity.character.player.PlayerOption +import world.gregs.voidps.engine.inject -huntPlayer(mode = "aggressive") { npc -> - if (!Settings["world.npcs.aggression", true] || attacking(npc, target)) { - return@huntPlayer - } - if (Settings["world.npcs.safeZone", false] && npc.tile.region.id == 12850) { - return@huntPlayer - } - npc.mode = Interact(npc, target, PlayerOption(npc, target, "Attack")) +val areas: AreaDefinitions by inject() + +huntPlayer(mode = "aggressive*") { npc -> + if (!Settings["world.npcs.aggression", true] || attacking(npc, target)) { + return@huntPlayer + } + if (Settings["world.npcs.safeZone", false] && npc.tile in areas["lumbridge"]) { + return@huntPlayer + } + npc.mode = Interact(npc, target, PlayerOption(npc, target, "Attack")) } huntPlayer(mode = "cowardly") { npc -> - if (!Settings["world.npcs.aggression", true] || attacking(npc, target)) { - return@huntPlayer - } - npc.mode = Interact(npc, target, PlayerOption(npc, target, "Attack")) + if (!Settings["world.npcs.aggression", true] || attacking(npc, target)) { + return@huntPlayer + } + if (Settings["world.npcs.safeZone", false] && npc.tile in areas["lumbridge"]) { + return@huntPlayer + } + npc.mode = Interact(npc, target, PlayerOption(npc, target, "Attack")) } -huntNPC(mode = "aggressive") { npc -> - if (attacking(npc, target)) { - return@huntNPC - } - npc.mode = Interact(npc, target, NPCOption(npc, target, target.def, "Attack")) +huntNPC(mode = "aggressive*") { npc -> + if (attacking(npc, target)) { + return@huntNPC + } + npc.mode = Interact(npc, target, NPCOption(npc, target, target.def, "Attack")) } huntNPC(mode = "cowardly") { npc -> - if (attacking(npc, target)) { - return@huntNPC - } - npc.mode = Interact(npc, target, NPCOption(npc, target, target.def, "Attack")) + if (attacking(npc, target)) { + return@huntNPC + } + npc.mode = Interact(npc, target, NPCOption(npc, target, target.def, "Attack")) } fun attacking(npc: NPC, target: Character): Boolean { - val current = npc.mode - if (current is Interact && current.target == target) { - return true - } else if (current is CombatMovement && current.target == target) { - return true - } - return false + val current = npc.mode + if (current is Interact && current.target == target) { + return true + } else if (current is CombatMovement && current.target == target) { + return true + } + return false } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/NPCAttack.kt b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/NPCAttack.kt index 55efa428b..0528c5c67 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/NPCAttack.kt +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/combat/NPCAttack.kt @@ -17,6 +17,10 @@ object NPCAttack { } } if (npc.race.isNotEmpty()) { + animation = "${npc.race}_${npc.def["style", "unarmed"]}" + if (animationDefinitions.contains(animation)) { + return animation + } animation = "${npc.race}_attack" if (animationDefinitions.contains(animation)) { return animation diff --git a/game/src/main/resources/game.properties b/game/src/main/resources/game.properties index 809a4c761..1f8487d8c 100644 --- a/game/src/main/resources/game.properties +++ b/game/src/main/resources/game.properties @@ -115,11 +115,11 @@ combat.showSoak=true #------- Agility ------- -# Disable players failing obstacles on advanced agility courses +# Disable players failing obstacles on agility courses agility.disableCourseFailure=false -# Disable skipping laps towards Agile when failing advanced courses -agility.disableFailLapSkip=true +# Disable skipping laps when failing agility courses +agility.disableFailLapSkip=false #------- Runecrafting ------- @@ -146,7 +146,7 @@ events.shootingStars.maxRespawnTimeMinutes=120 #=================================== # The number of AI-controlled bots spawned on startup -bots.count=0 +bots.count=10 # What tasks to give AI-controlled bots with no tasks (options: nothing, randomWalk) bots.idle=randomWalk diff --git a/game/src/test/kotlin/world/gregs/voidps/world/activity/skill/agility/course/WildernessCourseTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/activity/skill/agility/course/WildernessCourseTest.kt new file mode 100644 index 000000000..6bda358ac --- /dev/null +++ b/game/src/test/kotlin/world/gregs/voidps/world/activity/skill/agility/course/WildernessCourseTest.kt @@ -0,0 +1,200 @@ +package world.gregs.voidps.world.activity.skill.agility.course + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import world.gregs.voidps.FakeRandom +import world.gregs.voidps.engine.entity.character.player.skill.Skill +import world.gregs.voidps.type.Tile +import world.gregs.voidps.type.setRandom +import world.gregs.voidps.world.script.* + +internal class WildernessCourseTest : WorldTest() { + + @Test + fun `Enter course`() { + val player = createPlayer("agile", Tile(2998, 3916)) + player.levels.set(Skill.Agility, 52) + val door = objects[Tile(2998, 3917), "wilderness_agility_door_closed"]!! + + player.objectOption(door, "Open") + tick(16) + + assertEquals(Tile(2998, 3931), player.tile) + assertEquals(15.0, player.experience.get(Skill.Agility)) + } + + @Test + fun `Enter course without level`() { + val player = createPlayer("agile", Tile(2998, 3916)) + val door = objects[Tile(2998, 3917), "wilderness_agility_door_closed"]!! + + player.objectOption(door, "Open") + tick(3) + + assertEquals(Tile(2998, 3916), player.tile) + } + + @Test + fun `Exit course`() { + val player = createPlayer("agile", Tile(2998, 3931)) + val door = objects[Tile(2998, 3931), "wilderness_agility_gate_east_closed"]!! + + player.objectOption(door, "Open") + tick(16) + + assertEquals(Tile(2998, 3916), player.tile) + assertEquals(15.0, player.experience.get(Skill.Agility)) + } + + @Test + fun `Exit course failure`() { + setRandom(object : FakeRandom() { + override fun nextInt(until: Int) = until + }) + val player = createPlayer("agile", Tile(2998, 3931)) + val door = objects[Tile(2998, 3931), "wilderness_agility_gate_east_closed"]!! + + player.objectOption(door, "Open") + tick(12) + + assertEquals(Tile(3001, 3923), player.tile) + assertEquals(0.0, player.experience.get(Skill.Agility)) + } + + @Test + fun `Climb through pipe`() { + val player = createPlayer("agile", Tile(3004, 3937)) + val pipe = objects[Tile(3004, 3938), "wilderness_obstacle_pipe"]!! + + player.objectOption(pipe, "Squeeze-through") + tick(10) + + assertEquals(Tile(3004, 3950), player.tile) + assertEquals(12.5, player.experience.get(Skill.Agility)) + } + + @Test + fun `Climb through pipe reversed`() { + val player = createPlayer("agile", Tile(3004, 3950)) + val pipe = objects[Tile(3004, 3948), "wilderness_obstacle_pipe"]!! + + player.objectOption(pipe, "Squeeze-through") + tick(2) + + assertEquals(Tile(3004, 3950), player.tile) + } + + @Test + fun `Swing on rope swing`() { + val player = createPlayer("agile", Tile(3005, 3953)) + val rope = objects[Tile(3005, 3952), "wilderness_rope_swing"]!! + + player.objectOption(rope, "Swing-on") + tick(6) + + assertEquals(Tile(3005, 3958), player.tile) + assertEquals(20.0, player.experience.get(Skill.Agility)) + } + + @Test + fun `Fall off rope swing`() { + setRandom(object : FakeRandom() { + override fun nextInt(until: Int) = until + }) + val player = createPlayer("agile", Tile(3005, 3953)) + val rope = objects[Tile(3005, 3952), "wilderness_rope_swing"]!! + + player.objectOption(rope, "Swing-on") + tick(7) + + assertEquals(Tile(3004, 10357), player.tile) + assertEquals(0.0, player.experience.get(Skill.Agility)) + assertEquals(75, player.levels.get(Skill.Constitution)) + } + + @Test + fun `Cross stepping stones`() { + val player = createPlayer("agile", Tile(3002, 3960)) + val stones = objects[Tile(3001, 3960), "wilderness_stepping_stone"]!! + + player.objectOption(stones, "Cross") + tick(14) + + assertEquals(Tile(2996, 3960), player.tile) + assertEquals(20.0, player.experience.get(Skill.Agility)) + } + + @Test + fun `Fall off stepping stones`() { + setRandom(object : FakeRandom() { + override fun nextInt(until: Int) = until + }) + val player = createPlayer("agile", Tile(3002, 3960)) + val stones = objects[Tile(3001, 3960), "wilderness_stepping_stone"]!! + + player.objectOption(stones, "Cross") + tick(14) + + assertEquals(Tile(3002, 3963), player.tile) + assertEquals(0.0, player.experience.get(Skill.Agility)) + assertEquals(70, player.levels.get(Skill.Constitution)) + } + + @Test + fun `Cross log balance`() { + val player = createPlayer("agile", Tile(3001, 3946)) + val stones = objects[Tile(3001, 3945), "wilderness_log_balance"]!! + + player.objectOption(stones, "Walk-across") + tick(11) + + assertEquals(Tile(2994, 3945), player.tile) + assertEquals(20.0, player.experience.get(Skill.Agility)) + } + + @Test + fun `Fall off log balance`() { + setRandom(object : FakeRandom() { + override fun nextInt(until: Int) = until + }) + val player = createPlayer("agile", Tile(3001, 3946)) + val stones = objects[Tile(3001, 3945), "wilderness_log_balance"]!! + + player.objectOption(stones, "Walk-across") + tick(11) + + assertEquals(Tile(2998, 10345), player.tile) + assertEquals(0.0, player.experience.get(Skill.Agility)) + assertEquals(75, player.levels.get(Skill.Constitution)) + } + + @Test + fun `Climb rocks`() { + val player = createPlayer("agile", Tile(2994, 3937)) + val rocks = objects[Tile(2994, 3936), "wilderness_agility_rocks"]!! + + player.objectOption(rocks, "Climb") + tick(6) + + assertEquals(Tile(2994, 3933), player.tile) + assertEquals(0.0, player.experience.get(Skill.Agility)) + assertEquals(0, player["wilderness_course_laps", 0]) + } + + @Test + fun `Climb through pipe with bonus reward`() { + val player = createPlayer("agile", Tile(2995, 3937)) + val rocks = objects[Tile(2995, 3936), "wilderness_agility_rocks"]!! + player.agilityCourse("wilderness") + player.agilityStage = 4 + + player.objectOption(rocks, "Climb") + tick(6) + + assertEquals(Tile(2995, 3933), player.tile) + assertEquals(499.0, player.experience.get(Skill.Agility)) + assertEquals(0, player.agilityStage) + assertEquals(1, player["wilderness_course_laps", 0]) + } + +} \ No newline at end of file