From 92fcaef338c8303fd75c950364f0885c4a422a2a Mon Sep 17 00:00:00 2001 From: Greg Date: Fri, 28 Jun 2024 16:16:00 +0100 Subject: [PATCH] Add achievement tasks and world map controls (#544) * Fix zamorak monk robe drop ids * Start adding main and tab interfaces * Add string scripts to command * Fix sending interface visibility component ids * Change sprite dump directory * Add task pinning * Add struct configs * Add quest configs * Add manual server side fix for #540 * More manual server side fixes for #540 * Add all quest varbits from cs2 3227 * Add combat summoning level support * Add boolean support to var command * Filter task tab by task requirements * Fix struct ids * Add all task varbits * Add first task * Add task popup, display completed/total tasks, wipe pinned task on ok * Add task complete messages, explorer jack and ring reward * Extract task looping * Add message wrap around * Rename bot variables * Add boolean support to script command * Add initial explorer jack task * Add task set filtering * Fix quest complete checks * Check overall progress dynamically * Start adding lumbridge beginner tasks * Add remaining lumbridge beginner tasks * Add experience lamp dialogue and antique lamp * Start adding task unit tests * Fix using spells on magic dummy * Add more integration tests, fix ellis tanning * Add shop buy and sell events * Add tests for remaining tasks * Fix area's not including all levels * Fix wizards tower top floor level * Add world map functionality * Add task hint world map marking and fix tab pinning * Show no tasks when run out * Fix invalid inject code * Fix missing font defs * Fix hitpoint test * Fix npcs messing with tests * Add explorer jack item rewards --- .../cache/config/data/QuestDefinition.kt | 4 + .../cache/config/decoder/StructDecoder.kt | 39 + data/definitions/animations.yml | 4 +- data/definitions/enums.yml | 16 +- data/definitions/graphics.yml | 3 +- data/definitions/interface-types.yml | 6 +- data/definitions/interfaces.yml | 74 +- data/definitions/jingles.yml | 3 +- data/definitions/midis.yml | 3 +- data/definitions/npcs.yml | 7 +- data/definitions/objects.yml | 15 + data/definitions/parameters.yml | 100 +- data/definitions/quests.yml | 171 ++ data/definitions/scripts.yml | 12 +- data/definitions/structs.yml | 509 ++++ data/definitions/variables-client-string.yml | 7 +- data/definitions/variables-client.yml | 58 +- data/definitions/variables-custom.yml | 138 +- data/definitions/variables-player-bit.yml | 2066 ++++++++++++++++- data/definitions/variables-player.yml | 280 ++- data/map/areas.yml | 28 +- data/map/teleports.yml | 6 +- data/spawns/drops.yml | 4 +- data/spawns/npc-spawns.yml | 1 + .../gregs/voidps/engine/EngineModules.kt | 1 + .../voidps/engine/client/EncodeExtensions.kt | 6 +- .../client/instruction/InstructionHandlers.kt | 2 + .../client/instruction/handle/WalkHandler.kt | 3 + .../handle/WorldMapClickHandler.kt | 19 + .../voidps/engine/client/ui/Interfaces.kt | 5 +- .../engine/client/variable/VariableSet.kt | 2 + .../engine/data/definition/AreaDefinitions.kt | 2 +- .../engine/data/definition/EnumDefinitions.kt | 6 + .../data/definition/QuestDefinitions.kt | 25 + .../data/definition/StructDefinitions.kt | 11 +- .../gregs/voidps/engine/inv/ItemChanged.kt | 8 + .../world/gregs/voidps/bot/BotSpawns.kts | 2 +- .../world/gregs/voidps/bot/DecisionMaking.kts | 18 +- .../activity/achievement/AntiqueLamp.kts | 16 + .../activity/achievement/ExplorerJack.kts | 145 ++ .../activity/achievement/ExplorersRing.kts | 29 + .../achievement/LumbridgeBeginnerTasks.kts | 370 +++ .../world/activity/achievement/TaskList.kts | 153 ++ .../world/activity/achievement/TaskSystem.kts | 221 ++ .../world/activity/achievement/Tasks.kt | 296 +++ .../voidps/world/activity/quest/Quests.kts | 1 + .../world/activity/skill/ItemOnItems.kts | 6 + .../world/activity/skill/cooking/Cooking.kts | 1 + .../world/activity/skill/crafting/Pottery.kts | 5 + .../activity/skill/prayer/BoneBurying.kts | 1 + .../activity/skill/prayer/PrayerAltars.kts | 1 + .../skill/runecrafting/Runecrafting.kts | 2 + .../transport/teleport/HomeTeleport.kts | 1 + .../world/command/admin/AdminCommands.kts | 6 +- .../world/command/debug/InterfaceCommands.kts | 12 +- .../voidps/world/community/trade/lend/Loan.kt | 3 +- .../interact/dialogue/ExperienceLamp.kts | 15 + .../interact/dialogue/type/ExpSkillLamp.kt | 17 + .../world/interact/dialogue/type/LevelUp.kts | 2 +- .../world/interact/entity/combat/Target.kt | 3 + .../world/interact/entity/death/NPCDeath.kts | 8 +- .../world/interact/entity/npc/Banker.kts | 11 +- .../interact/entity/npc/shop/BoughtItem.kt | 23 + .../interact/entity/npc/shop/OpenShop.kt | 10 +- .../interact/entity/npc/shop/ShopBuy.kts | 6 +- .../interact/entity/npc/shop/ShopOpen.kts | 5 +- .../interact/entity/npc/shop/ShopSell.kts | 5 +- .../interact/entity/npc/shop/SoldItem.kt | 23 + .../entity/player/combat/CombatLevel.kts | 11 +- .../entity/player/combat/consume/Eating.kts | 4 +- .../player/combat/consume/drink/Ale.kts | 1 + .../entity/player/display/GameFrame.kts | 1 + .../entity/player/display/map/WorldMap.kts | 42 +- .../entity/player/display/tab/Emotes.kts | 13 +- .../voidps/world/map/al_kharid/Ellis.kts | 4 +- .../voidps/world/map/al_kharid/Tollgate.kts | 3 +- .../world/map/lumbridge/DukeHoracio.kts | 1 + .../world/map/lumbridge/LumbridgeChurch.kts | 19 + .../world/map/lumbridge/LumbridgeFlag.kts | 1 + .../map/lumbridge/combat_hall/CombatDummy.kts | 3 +- .../world/map/wizards_tower/Sedridor.kts | 2 + game/src/main/resources/game.properties | 2 + .../achievement/LumbridgeBeginnerTasksTest.kt | 808 +++++++ .../voidps/world/activity/skill/MiningTest.kt | 1 - .../combat/magic/spell/MagicSpellTest.kt | 9 +- .../player/effect/HitpointRestorationTest.kt | 4 +- .../gregs/voidps/world/script/WorldTest.kt | 30 +- game/src/test/resources/test.properties | 2 + .../voidps/network/client/instruction/Walk.kt | 2 +- .../client/instruction/WorldMapClick.kt | 5 + .../voidps/network/login/protocol/Decoders.kt | 2 +- .../protocol/decode/WalkMiniMapDecoder.kt | 2 +- .../protocol/decode/WorldMapClickDecoder.kt | 11 + .../protocol/decode/WorldMapCloseDecoder.kt | 14 - .../network/login/protocol/DecoderTest.kt | 4 +- .../gregs/voidps/tools/cache/DumpSprites.kt | 5 +- 96 files changed, 5862 insertions(+), 205 deletions(-) create mode 100644 data/definitions/quests.yml create mode 100644 data/definitions/structs.yml create mode 100644 engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WorldMapClickHandler.kt create mode 100644 engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/QuestDefinitions.kt create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/AntiqueLamp.kts create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorerJack.kts create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorersRing.kts create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasks.kts create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskList.kts create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/Tasks.kt create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/ExperienceLamp.kts create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/ExpSkillLamp.kt create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/BoughtItem.kt create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/SoldItem.kt create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeChurch.kts create mode 100644 game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt create mode 100644 network/src/main/kotlin/world/gregs/voidps/network/client/instruction/WorldMapClick.kt create mode 100644 network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapClickDecoder.kt delete mode 100644 network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapCloseDecoder.kt diff --git a/cache/src/main/kotlin/world/gregs/voidps/cache/config/data/QuestDefinition.kt b/cache/src/main/kotlin/world/gregs/voidps/cache/config/data/QuestDefinition.kt index 3555f8e70d..38d48ddfae 100644 --- a/cache/src/main/kotlin/world/gregs/voidps/cache/config/data/QuestDefinition.kt +++ b/cache/src/main/kotlin/world/gregs/voidps/cache/config/data/QuestDefinition.kt @@ -114,4 +114,8 @@ data class QuestDefinition( result = 31 * result + (extras?.hashCode() ?: 0) return result } + + companion object { + val EMPTY = QuestDefinition() + } } \ No newline at end of file diff --git a/cache/src/main/kotlin/world/gregs/voidps/cache/config/decoder/StructDecoder.kt b/cache/src/main/kotlin/world/gregs/voidps/cache/config/decoder/StructDecoder.kt index b272e02747..79aff29604 100644 --- a/cache/src/main/kotlin/world/gregs/voidps/cache/config/decoder/StructDecoder.kt +++ b/cache/src/main/kotlin/world/gregs/voidps/cache/config/decoder/StructDecoder.kt @@ -1,6 +1,7 @@ package world.gregs.voidps.cache.config.decoder import world.gregs.voidps.buffer.read.Reader +import world.gregs.voidps.cache.Cache import world.gregs.voidps.cache.Config.STRUCTS import world.gregs.voidps.cache.config.ConfigDecoder import world.gregs.voidps.cache.config.data.StructDefinition @@ -12,6 +13,44 @@ class StructDecoder( override fun create(size: Int) = Array(size) { StructDefinition(it) } + + override fun load(cache: Cache): Array { + val definitions = super.load(cache) + // Manually fix values see https://github.com/GregHib/void/issues/540 + var extras = definitions[1330].extras as MutableMap + extras["1296"] = 3 + extras["1297"] = 19 + extras["1298"] = 2 + extras["1299"] = 37 + extras = definitions[1337].extras as MutableMap + extras["1294"] = 62 + extras["1295"] = 8 + extras["1296"] = 14 + extras["1297"] = 13 + extras["1298"] = 13 + extras["1299"] = 10 + extras = definitions[1342].extras as MutableMap + extras["1294"] = 62 + extras["1295"] = 13 + extras["1296"] = 12 + extras["1297"] = 56 + extras = definitions[1450].extras as MutableMap + extras["1298"] = 2 + extras["1299"] = 75 + extras["1300"] = 20 + extras["1301"] = 65 + extras = definitions[1346].extras as MutableMap + extras["1294"] = 13 + extras["1295"] = 60 + extras = definitions[1649].extras as MutableMap + extras["1296"] = 10 + extras["1297"] = 17 + extras = definitions[1658].extras as MutableMap + extras["1296"] = 12 + extras["1297"] = 50 + return definitions + } + override fun StructDefinition.read(opcode: Int, buffer: Reader) { if (opcode == 249) { readParameters(buffer, parameters) diff --git a/data/definitions/animations.yml b/data/definitions/animations.yml index 9ac40d1f90..799f6e603b 100644 --- a/data/definitions/animations.yml +++ b/data/definitions/animations.yml @@ -1696,4 +1696,6 @@ gecko_attack: 7207 gecko_death: 7205 wolves_hit: 6557 wolves_attack: 6559 -wolves_death: 6558 \ No newline at end of file +wolves_death: 6558 +run_replenish: 9988 +play_organ: 3675 diff --git a/data/definitions/enums.yml b/data/definitions/enums.yml index 751c33d2e8..50022717de 100644 --- a/data/definitions/enums.yml +++ b/data/definitions/enums.yml @@ -134,6 +134,18 @@ npc_contact_structs: 869 dungeoneering_rewards: 3016 dungeoneering_rewards_members: 3015 ring_of_kingship_classes: 3088 -achievements_structs: 3483 -achievement_sprites: 3492 +task_area_start_indices: 3482 +task_structs: 3483 +task_area_first_ids: 3484 +task_distraction_and_diversions: 3485 +task_area_names: 3487 +task_difficulties: 3488 +task_set_dropdown_interfaces: 3489 +task_set_dropdown_sprite_interfaces: 3490 +task_set_dropdown_sprites: 3491 +task_difficulty_sprites: 3492 +task_summary_interfaces: 3493 +task_set_structs: 3494 +task_set_sprites: 3495 +task_sprites: 3492 clan_wars_arenas: 1604 diff --git a/data/definitions/graphics.yml b/data/definitions/graphics.yml index 32c062e008..ffd541a391 100644 --- a/data/definitions/graphics.yml +++ b/data/definitions/graphics.yml @@ -1485,4 +1485,5 @@ burrow_dust: 571 tele_other: 343 tele_other_receive: id: 342 - height: 52 \ No newline at end of file + height: 52 +run_replenish: 1733 diff --git a/data/definitions/interface-types.yml b/data/definitions/interface-types.yml index 494822436f..55f15e88ca 100644 --- a/data/definitions/interface-types.yml +++ b/data/definitions/interface-types.yml @@ -142,4 +142,8 @@ full_screen: skill_creation: parent: dialogue_skill_creation - index: 4 \ No newline at end of file + index: 4 + +task_overlay: + fixedIndex: 20 + resizeIndex: 79 \ No newline at end of file diff --git a/data/definitions/interfaces.yml b/data/definitions/interfaces.yml index e5a05c3253..966f1e6633 100644 --- a/data/definitions/interfaces.yml +++ b/data/definitions/interfaces.yml @@ -187,7 +187,37 @@ dialogue_double_obj_box: dialogue_garden_quiz: id: 133 type: dialogue_box -skill_stat_advance: 134 +skill_stat_advance: + id: 134 + type: main_screen + components: + confirm: 2 + close: 29 + attack: 30 + strength: 31 + defence: 32 + ranged: 33 + prayer: 34 + constitution: 35 + magic: 36 + agility: 37 + herblore: 38 + thieving: 39 + crafting: 40 + fletching: 41 + mining: 42 + smithing: 43 + fishing: 44 + firemaking: 45 + cooking: 46 + woodcutting: 47 + runecrafting: 48 + slayer: 49 + hunter: 50 + farming: 51 + construction: 52 + summoning: 53 + dungeoneering: 54 dialogue_chat_both: id: 136 type: dialogue_box @@ -2156,6 +2186,12 @@ world_map: type: full_screen components: close: 44 + order: 54 + marker: 42 + key_list: + id: 49 + options: + Select: 0 chat_model_text: 757 canoe_travel: id: 758 @@ -2319,6 +2355,29 @@ skill_creation_amount: task_list: id: 917 type: main_screen + components: + area_lumbridge_draynor: 119 + area_varrock: 121 + area_falador: 123 + area_seers_village: 125 + area_ardougne: 127 + area_karamja: 129 + area_fremennik: 131 + area_dnd_activities: 147 + filter_sets: 110 + filter_done: 102 + toggle_popups: 136 + pin: 40 + hint_1: 2 + hint_2: 4 + hint_3: 6 + hint_4: 8 + hint_5: 10 + tasks: + id: 94 + options: + Summary: 0 + Pin: 1 dialogue_make_amount: id: 944 type: dialogue_box @@ -2528,6 +2587,11 @@ character_creation: Select: 0 choose_colour: 102 confirm: 117 +task_popup: + id: 1055 + type: task_overlay + components: + details: 2 task_system: id: 1056 type: task_system_tab @@ -2540,9 +2604,15 @@ task_system: task_5: 157 task_6: 162 task_list: 102 - dont_show: 172 + dont_show: 173 close_hint: 174 hints: 36 + summary_overlay: 122 + message_overlay: 171 + ok: 130 + hint_1: 77 + hint_2: 79 + hint_3: 81 warriors_guild: 1057 fade_out: id: 120 diff --git a/data/definitions/jingles.yml b/data/definitions/jingles.yml index 92ef26998f..e6857f6e36 100644 --- a/data/definitions/jingles.yml +++ b/data/definitions/jingles.yml @@ -176,4 +176,5 @@ soul_wars_loss: 379 soul_wars_win: 380 level_up_dungeoneering: 416 level_up_dungeoneering_unlock: 417 -pyramid_plunder_snake_charming: 417 \ No newline at end of file +pyramid_plunder_snake_charming: 417 +ambient_church_happy: 72 diff --git a/data/definitions/midis.yml b/data/definitions/midis.yml index b2683f474b..e79058c706 100644 --- a/data/definitions/midis.yml +++ b/data/definitions/midis.yml @@ -21,4 +21,5 @@ nex_fumus_dont_fail: 3321 nex_embrace_darkness: 3322 nex_taste_wrath: 3323 nex_fumus: 3325 -nex_glacies_dont_fail: 3327 \ No newline at end of file +nex_glacies_dont_fail: 3327 +church_organ: 147 diff --git a/data/definitions/npcs.yml b/data/definitions/npcs.yml index 3bc5d9d721..84bcc9f53c 100644 --- a/data/definitions/npcs.yml +++ b/data/definitions/npcs.yml @@ -2169,4 +2169,9 @@ monk_of_zamorak_ourania: hunt_mode: aggressive drop_table: monk_of_zamorak respawn_delay: 50 - examine: "An evil human cleric." \ No newline at end of file + examine: "An evil human cleric." +explorer_jack: + id: 13295 + wander_radius: 5 + race: human + examine: "He looks like a professional explorer." \ No newline at end of file diff --git a/data/definitions/objects.yml b/data/definitions/objects.yml index 6c12488b02..5889911a52 100644 --- a/data/definitions/objects.yml +++ b/data/definitions/objects.yml @@ -11836,3 +11836,18 @@ ourania_crack_exit: ourania_altar: id: 26847 examine: "An altar upon which to craft runes." +lumbridge_castle_ladder: + id: 36771 + examine: "I can climb up this." +lumbridge_organ: + id: 36978 + examine: "A church organ." +lumbridge_church_bell: + id: 36976 + examine: "I can ring this." +fire_barbarian_village: + id: 5499 + examine: "Hot!" +wizards_tower_staircase: + id: 12537 + examine: "I can climb these stairs." \ No newline at end of file diff --git a/data/definitions/parameters.yml b/data/definitions/parameters.yml index 95a999ccc2..a403f08ffe 100644 --- a/data/definitions/parameters.yml +++ b/data/definitions/parameters.yml @@ -14,10 +14,10 @@ ammo_group: 21 secondary_use_level: 23 unbankable: 59 quest_list_enum: 61 -world_sprite_1: 130 -world_sprite_2: 131 -world_sprite_3: 134 -world_sprite_4: 135 +world_map_marker_sprite_icon: 130 +world_map_marker_sprite: 131 +world_map_marker_sprite_horizontal: 134 +world_map_marker_sprite_diagonal: 135 quest_list_interface: 152 quest_list_scroll: 153 construction_required_item_id_1: 211 @@ -239,7 +239,7 @@ quest_journal_hint_text: 948 quest_item_requirement_text: 949 quest_level_requirement_text: 950 quest_reward_text_0: 951 -achievement_quest_sprite: 952 +task_quest_sprite: 952 barbarian_assault_reward: 954 barbarian_assault_ticket_wave: 955 familiarisation_familiar_1: 956 @@ -355,51 +355,51 @@ conquest_unit_param_15: 1229 conquest_unit_param_16: 1230 dynamic_inventory_option_original: 1264 dynamic_inventory_option_replacement: 1265 -achievement_name: 1266 -achievement_area: 1267 -achievement_index: 1268 -achievement_nextIndex: 1269 -achievement_quest_id: 1270 -achievement_sprite: 1271 -achievement_difficulty: 1272 -achievement_description: 1273 -achievement_hint_1: 1274 -achievement_hint_2: 1275 -achievement_hint_3: 1276 -achievement_hint_4: 1277 -achievement_hint_5: 1278 -achievement_hint_6: 1279 -achievement_text_rol: 1280 -achievement_selectable_1: 1282 -achievement_selectable_2: 1283 -achievement_selectable_3: 1284 -achievement_selectable_4: 1285 -achievement_selectable_5: 1286 -achievement_selectable_6: 1287 -achievement_members: 1290 -achievement_group: 1292 -achievement_sprite_offset: 1293 -achievement_skill_1: 1294 -achievement_level_1: 1295 -achievement_skill_2: 1296 -achievement_level_2: 1297 -achievement_skill_3: 1298 -achievement_level_3: 1299 -achievement_skill_4: 1300 -achievement_level_4: 1301 -achievement_skill_5: 1302 -achievement_level_5: 1303 -achievement_skill_6: 1304 -achievement_level_6: 1305 -achievement_skill_7: 1306 -achievement_level_7: 1307 -achievement_skill_8: 1308 -achievement_level_8: 1309 -achievement_skill_9: 1310 -achievement_level_9: 1311 -achievement_skill_10: 1312 -achievement_level_10: 1313 -achievement_is_tutorial: 1322 +task_name: 1266 +task_area: 1267 +task_index: 1268 +task_next_index: 1269 +task_quest_id: 1270 +task_sprite: 1271 +task_difficulty: 1272 +task_description: 1273 +task_hint_1: 1274 +task_hint_2: 1275 +task_hint_3: 1276 +task_hint_4: 1277 +task_hint_5: 1278 +task_hint_6: 1279 +task_text_rol: 1280 +task_hint_tile_1: 1282 +task_hint_tile_2: 1283 +task_hint_tile_3: 1284 +task_hint_tile_4: 1285 +task_hint_tile_5: 1286 +task_hint_tile_6: 1287 +task_members: 1290 +task_set: 1292 +task_sprite_offset: 1293 +task_skill_1: 1294 +task_level_1: 1295 +task_skill_2: 1296 +task_level_2: 1297 +task_skill_3: 1298 +task_level_3: 1299 +task_skill_4: 1300 +task_level_4: 1301 +task_skill_5: 1302 +task_level_5: 1303 +task_skill_6: 1304 +task_level_6: 1305 +task_skill_7: 1306 +task_level_7: 1307 +task_skill_8: 1308 +task_level_8: 1309 +task_skill_9: 1310 +task_level_9: 1311 +task_skill_10: 1312 +task_level_10: 1313 +task_is_tutorial: 1322 summoning_beast_of_burden: 1323 required_chompy_kills: 1366 chompy_hat_name: 1367 diff --git a/data/definitions/quests.yml b/data/definitions/quests.yml new file mode 100644 index 0000000000..7ec81fc0a0 --- /dev/null +++ b/data/definitions/quests.yml @@ -0,0 +1,171 @@ +all_fired_up: 142 +animal_magnetism: 18 +another_slice_of_ham: 123 +as_a_first_resort: 132 +back_to_my_roots: 128 +between_a_rock: 19 +big_chompy_bird_hunting: 20 +biohazard: 21 +black_knights_fortress: 159 +cabin_fever: 22 +catapult_construction: 133 +clock_tower: 23 +cold_war: 117 +contact: 24 +cooks_assistant: 1 +creature_of_fenkenstrain: 26 +darkness_of_hallowvale: 27 +dealing_with_scabaras: 130 +death_plateau: 29 +death_to_the_dorgeshuun: 28 +defender_of_varrock: 144 +demon_slayer: 2 +desert_treasure: 30 +devious_minds: 31 +dig_site: 32 +dorics_quest: 3 +dragon_slayer: 4 +dream_mentor: 124 +druidic_ritual: 33 +dwarf_cannon: 34 +eadgars_ruse: 35 +eagles_peak: 36 +elemental_workshop_i: 37 +elemental_workshop_ii: 38 +enakhras_lament: 39 +enlightened_journey: 40 +ernest_the_chicken: 5 +eyes_of_glouphrie: 41 +fairy_tale_i: 42 +fairy_tale_ii: 43 +family_crest: 44 +the_feud: 45 +fight_arena: 46 +fishing_contest: 47 +forgettable_tale: 48 +fremennik_isles: 118 +fremennik_trials: 49 +garden_of_tranquillity: 51 +gertrudes_cat: 52 +ghosts_ahoy: 53 +the_giant_dwarf: 54 +goblin_diplomacy: 6 +the_golem: 55 +grand_tree: 56 +great_brain_robbery: 120 +grim_tales: 125 +hand_in_the_sand: 57 +haunted_mine: 58 +hazeel_cult: 59 +heroes_quest: 60 +holy_grail: 61 +horror_from_the_deep: 62 +icthlarins_little_helper: 63 +imp_catcher: 7 +in_aid_of_the_myreque: 64 +in_pyre_need: 146 +in_search_of_the_myreque: 65 +jungle_potion: 66 +kenniths_concerns: 134 +kings_ransom: 126 +knights_sword: 8 +land_of_the_goblins: 129 +legacy_of_seergaze: 135 +legends_quest: 67 +lost_city: 68 +lost_tribe: 69 +lunar_diplomacy: 70 +making_history: 71 +meeting_history: 141 +merlins_crystal: 72 +monks_friend: 74 +monkey_madness: 73 +mountain_daughter: 75 +mournings_ends_i: 76 +mournings_ends_ii: 77 +murder_mystery: 78 +my_arms_big_adventure: 79 +myths_of_the_white_lands: 148 +nature_spirit: 80 +observatory_quest: 81 +olafs_quest: 122 +one_small_favour: 82 +path_of_glouphrie: 127 +perils_of_ice_mountain: 136 +pirates_treasure: 9 +plague_city: 83 +priest_in_peril: 84 +prince_ali_rescue: 10 +rag_and_bone_man: 85 +rat_catchers: 86 +recipe_for_disaster: 87 +recruitment_drive: 88 +regicide: 89 +restless_ghost: 11 +rocking_out: 139 +roving_elves: 90 +royal_trouble: 91 +rum_deal: 92 +rune_mysteries: 13 +scorpion_catcher: 93 +sea_slug: 94 +shades_of_mortton: 96 +shadow_of_the_storm: 97 +sheep_herder: 98 +shield_of_arrav: 15 +shilo_village: 99 +slug_menace: 95 +smoking_kills: 138 +souls_bane: 100 +spirit_of_summer: 140 +spirits_of_the_elid: 101 +summers_end: 143 +swan_song: 102 +swept_away: 153 +tai_bwo_wannai_trio: 103 +tail_of_two_cats: 104 +tears_of_guthix: 105 +temple_of_ikov: 106 +throne_of_miscellania: 107 +toktz_ket_dill: 137 +the_tourist_trap: 108 +tower_of_life: 119 +tree_gnome_village: 110 +tribal_totem: 111 +troll_romance: 112 +troll_stronghold: 113 +underground_pass: 114 +vampire_slayer: 16 +wanted: 115 +watchtower: 116 +waterfall_quest: 50 +what_lies_below: 121 +while_guthix_sleeps: 145 +witchs_house: 109 +wolf_whistle: 131 +zogre_flesh_eaters: 25 +chosen_commander: 152 +glorious_memories: 149 +tale_of_the_muspah: 150 +missing_my_mummy: 155 +hunt_for_red_raktuber: 151 +curse_of_arrav: 156 +fur_n_seek: 154 +forgiveness_of_a_chaos_dwarf: 160 +within_the_light: 161 +temple_at_senntisten: 157 +blood_runs_deep: 163 +nomads_requiem: 162 +rune_mechanics: 165 +blood_pact: 170 +#egg_streme_management +fairy_tale_iii: 158 +buyers_and_cellars: 167 +elemental_workshop_iii: 172 +quiet_before_the_swarm: 171 +love_story: 168 +void_dance: 173 +gunnars_ground: 17 +void_stares_back: 174 +do_no_evil: 179 +king_of_the_dwarves: 14 \ No newline at end of file diff --git a/data/definitions/scripts.yml b/data/definitions/scripts.yml index d3eaddd3ee..7d9ef3771e 100644 --- a/data/definitions/scripts.yml +++ b/data/definitions/scripts.yml @@ -6,8 +6,8 @@ interface_quest_complete: 2155 quest_complete: 2193 quest_progress: 2194 activate_prayer: 2295 -achievement_has_requirements: 3224 -achievement_complete: 3994 +task_has_requirements: 3224 +task_complete: 3994 clear_dialogues: 571 primary_options: 150 secondary_options: 695 @@ -21,4 +21,10 @@ dialogue_item_zoom: 3449 items_kept_on_death: 118 message_scroll_max: 677 inv_total_available: 1 -magic_rune_count: 19 \ No newline at end of file +magic_rune_count: 19 +task_main_list_populate: 3983 +task_main_list_filter_done: 3985 +task_main_list_filter_set: 3986 +task_summary_accordion: 4000 +task_summary_close: 4001 +task_list_button_hide: 4101 diff --git a/data/definitions/structs.yml b/data/definitions/structs.yml new file mode 100644 index 0000000000..4c0dc14899 --- /dev/null +++ b/data/definitions/structs.yml @@ -0,0 +1,509 @@ +# D&Ds / Activities None +penguin_hunting_task: 1646 +evil_tree_task: 1647 +shooting_star_task: 1648 +impetuous_impulses_task: 1649 +vinesweeper_task: 1650 +balthazars_big_top_bonanza_task: 1651 +tears_of_guthix_task: 1652 +conquest_task: 1653 +defeat_bork_task: 1654 +all_fired_up_task: 1655 +skeletal_horror_task: 1656 +great_orb_project_task: 1658 +pest_control_task: 1659 +castle_wars_task: 1660 +court_cases_task: 1661 +tai_bwo_wannai_cleanup_task: 1662 +fight_caves_task: 1663 +fight_pits_task: 1664 +brimhaven_agility_arena_task: 1665 +barbarian_assault_task: 1666 +blast_furnace_task: 1667 +shades_of_mortton_task: 1668 +barrows_task: 1669 +pyramid_plunder_task: 1670 +sorceress_garden_task: 1671 +mage_training_arena_task: 1672 +duel_arena_task: 1673 +fist_of_guthix_task: 1674 +stealing_creation_task: 1675 +soul_wars_task: 1676 +clan_wars_task: 1677 +gnome_restaurant_task: 1678 +mobilising_armies_task: 1679 +warriors_guild_task: 1680 +rotate_your_camera_task: 1702 +talk_to_sir_vant_task: 1703 +assist_sir_vant_task: 1704 +gather_the_squires_gear_task: 1705 +equip_yourself_task: 1706 +kill_the_goblin_task: 1707 +find_out_sir_vants_plan_task: 1708 +check_your_quest_journal_task: 1709 +check_your_world_map_task: 1710 +realign_your_minimap_task: 1711 +climb_the_wall_task: 1712 +make_a_ramp_task: 1713 +put_the_dragon_to_sleep_task: 1714 +talk_to_sir_vant_again_task: 1715 +sabotage_task: 1716 +return_the_squires_gear_task: 1717 +discover_an_exit_task: 1718 +cutting_a_path_task: 1719 +breaking_through_task: 1720 +skill_in_woodcutting_task: 1721 +skill_in_mining_task: 1722 +to_freedom_task: 1723 +introducing_explorer_jack_task: 1724 +the_journey_begins_task: 1725 +# Varrock Easy +strike_a_pose_task: 1477 +essential_facilitator_task: 1478 +doing_the_ironing_task: 1479 +plank_you_very_much_task: 1480 +making_learning_fun_task: 1481 +jumping_off_point_task: 1482 +lumbering_around_task: 1483 +read_all_about_it_task: 1484 +dog_and_bone_task: 1485 +pot_stop_task: 1486 +on_the_ragged_edge_task: 1487 +relocation_relocation_relocation_task: 1488 +it_belongs_in_a_museum_task: 1489 +journey_to_the_centre_of_the_earth_altar_task: 1490 +jackanory_task: 1491 +limey_task: 1492 +sherpas_delight_task: 1493 +king_of_the_castle_task: 1494 +stick_the_knife_in_task: 1495 +# Varrock Medium +double_strength_weaksauce_task: 1496 +champion_task: 1497 +what_lies_below_task: 1498 +with_a_ten_foot_pole_task: 1499 +cant_make_an_omelette_task: 1500 +point_of_en_tree_task: 1501 +unlocking_your_emotions_task: 1502 +a_lick_of_paint_task: 1503 +for_fast_transactions_task: 1504 +you_wouldnt_like_me_when_im_angry_task: 1505 +return_to_senntisten_task: 1506 +promised_the_earth_task: 1507 +royale_with_thieve_task: 1508 +like_a_varrocket_task: 1509 +challenge_vannaka_task: 1510 +flatpack_backpack_task: 1511 +master_scrumper_task: 1512 +engage_task: 1513 +faster_pussycat_kill_kill_task: 1514 +dial_v_for_varrock_task: 1515 +the_body_shop_task: 1516 +# Varrock Hard +burning_bush_task: 1460 +but_it_wont_warp_you_anywhere_task: 1461 +lighten_up_task: 1462 +put_your_smithing_hat_on_task: 1463 +kudos_on_the_kudos_task: 1464 +who_ate_all_the_pie_task: 1465 +battle_of_the_elements_task: 1466 +changing_rooms_task: 1467 +keeping_tabs_on_varrock_task: 1468 +hand_me_downs_task: 1469 +waka_waka_waka_task: 1470 +living_on_the_edge_task: 1471 +intersceptre_task: 1472 +# Varrock Elite +stick_a_bork_in_him_hes_done_task: 1451 +nomadness_task: 1452 +double_jointed_task: 1453 +it_all_adze_up_task: 1454 +mind_your_back_task: 1455 +red_red_pies_of_summer_task: 1456 +splitting_headache_task: 1457 +a_bolt_from_the_blue_task: 1458 +a_ton_of_earth_task: 1459 +# Karamja Easy +five_a_day_task: 1357 +im_lichen_this_task: 1358 +golden_shores_task: 1359 +put_to_port_in_port_sarim_task: 1360 +avast_ardougne_task: 1361 +show_that_you_cairn_task: 1362 +fruity_catch_task: 1363 +beachcomber_task: 1364 +tzhaar_wars_task: 1365 +its_a_jungle_ogre_task: 1366 +# Karamja Medium +just_the_ticket_task: 1379 +back_cran_door_task: 1380 +dungeons_and_dragons_task: 1381 +horseless_carriage_task: 1382 +they_like_me_they_really_like_me_task: 1383 +arachnophagia_task: 1384 +romancing_the_stone_task: 1385 +im_a_lumberjack_and_im_okay_task: 1386 +i_sleep_all_night_and_i_work_all_day_task: 1387 +to_catch_a_karambwan_task: 1388 +thats_not_a_knife_task: 1389 +falling_with_style_task: 1390 +scourge_of_scurvy_task: 1391 +hunters_of_the_horned_graahk_task: 1392 +the_roots_of_all_evil_task: 1393 +hotfooting_it_task: 1394 +stairway_to_haven_task: 1395 +thank_you_madam_task: 1396 +shipping_out_from_the_shipyard_task: 1397 +# Karamja Hard +flawless_victory_task: 1398 +play_dead_doggy_task: 1399 +id_be_kharazi_to_eat_this_task: 1400 +at_one_with_nature_task: 1401 +drop_it_like_its_hot_task: 1402 +deadwing_task: 1403 +quick_as_a_shot_task: 1404 +a_palm_for_each_finger_task: 1405 +yes_my_master_task: 1406 +can_opener_task: 1407 +# Karamja Elite +at_one_plus_fifty_five_with_nature_task: 1371 +the_power_of_lava_task: 1372 +boxing_clever_task: 1373 +its_a_snap_task: 1374 +crunchy_coating_task: 1375 +walkies_task: 1376 +tread_carefully_task: 1377 +ten_in_a_row_task: 1378 +# Seers' Village Easy +reflax_actions_task: 1276 +why_task: 1277 +stir_galahad_task: 1278 +la_morte_darthur_task: 1279 +another_string_to_your_bow_task: 1280 +bunch_of_flours_task: 1281 +happy_hour_task: 1282 +jute_alors_task: 1283 +sinclair_swirling_task: 1284 +grand_candle_task: 1285 +a_seer_ing_light_task: 1286 +mack_rolled_task: 1287 +# Seers' Village Medium +fleeing_the_scene_task: 1293 +its_a_slightly_magical_stick_task: 1294 +king_coal_task: 1295 +i_can_seer_my_house_from_here_task: 1296 +mastering_the_elements_task: 1297 +its_only_a_model_task: 1298 +sniper_training_task: 1299 +arch_archer_task: 1300 +what_no_cuddly_toy_task: 1301 +familiar_fire_familiarity_task: 1302 +at_least_it_doesnt_need_walking_task: 1303 +all_your_bass_task: 1304 +# Seers' Village Hard +at_home_on_the_range_task: 1265 +see_yew_at_five_task: 1266 +the_short_of_it_task: 1267 +prayer_of_attorney_task: 1268 +beware_of_the_dog_task: 1269 +twisted_fire_starter_task: 1270 +alch_aholic_task: 1271 +gonna_need_a_bigger_boat_task: 1272 +gonna_need_a_bigger_range_task: 1273 +water_palaver_task: 1274 +island_hopper_task: 1275 +# Seers' Village Elite +its_a_trap_no_wait_its_a_pie_task: 1288 +make_a_bolt_for_it_task: 1289 +the_long_of_it_task: 1290 +plentypotionentiary_task: 1291 +moon_raker_task: 1292 +# Lumbridge/Draynor Beginner +the_blood_pact_task: 1248 +on_the_run_task: 1518 +a_world_in_microcosm_task: 1519 +master_of_all_i_survey_task: 1153 +raise_the_roof_task: 1196 +take_your_pick_task: 1211 +adventurers_log_task: 1520 +arent_they_supposed_to_be_twins_task: 1521 +log_a_rhythm_task: 1522 +shellfish_roasting_on_an_open_fire_task: 1523 +heavy_metal_task: 1524 +bar_one_task: 1525 +cutting_edge_technology_task: 1526 +armed_and_dangerous_task: 1527 +on_your_way_task: 1528 +you_can_bank_on_us_task: 1529 +hang_on_to_something_task: 1530 +bovine_intervention_task: 1561 +tan_your_hide_task: 1562 +handicrafts_task: 1563 +handy_dandy_task: 1531 +just_cant_get_the_staff_task: 1532 +the_restless_ghost_task: 1249 +click_your_heels_three_times_task: 1533 +come_and_have_a_go_task: 1534 +reach_out_and_touch_someone_task: 1535 +three_rounds_rapid_men_task: 1536 +death_from_above_task: 1537 +flour_power_task: 1538 +a_labour_of_loaf_task: 1539 +cooks_assistant: 1250 +om_nom_nom_nom_task: 1540 +on_the_level_task: 1541 +rune_mysteries: 1251 +so_thats_what_ess_stands_for_task: 1542 +air_craft_task: 1543 +greasing_the_wheels_of_commerce_task: 1544 +must_be_funny_in_a_rich_mans_world_task: 1545 +i_wonder_if_itll_sprout_task: 1546 +put_your_hands_together_for_task: 1547 +prayer_point_power_task: 1548 +not_what_we_mean_by_irony_task: 1549 +alls_ferrous_in_love_and_war_task: 1550 +am_i_a_blademaster_yet_task: 1551 +first_blood_task: 1552 +temper_temper_task: 1553 +steel_yourself_for_combat_task: 1554 +ammo_ammo_ammo_task: 1555 +take_a_bow_task: 1556 +dont_bury_this_one_task: 1557 +mace_invaders_task: 1558 +capital_protection_what_task: 1559 +clay_of_champions_task: 1202 +just_add_water_task: 1203 +very_potter_task: 1204 +hotpot_task: 1205 +hack_and_smash_task: 1560 +shrimpin_aint_easy_task: 1212 +the_fruit_of_the_sea_task: 1213 +made_for_walking_task: 1564 +did_anyone_bring_any_toast_task: 1565 +its_not_a_red_one_task: 1566 +not_so_confusing_after_all_task: 1567 +absolutely_enchanting_task: 1568 +heart_of_oak_task: 1569 +get_the_point_task: 1570 +berry_tasty_task: 1571 +dishwater_task: 1572 +cant_touch_this_task: 1573 +quarter_centurion_task: 1574 +fledgeling_adventurer_task: 1575 +myths_of_the_white_lands_task: 1252 +hail_to_the_duke_baby_task: 1197 +doom_task: 1198 +sage_advice_task: 1199 +window_shopping_task: 1200 +wait_thats_not_a_sheep_task: 1201 +in_the_countyard_task: 1206 +grinding_my_gears_task: 1207 +beware_of_pigzilla_task: 1208 +the_rules_of_engagement_task: 1209 +tower_power_task: 1210 +a_grave_consideration_task: 1214 +tinkle_the_ivories_task: 1215 +ring_my_bell_task: 1216 +passing_out_task: 1217 +# Lumbridge/Draynor Easy +what_is_this_place_task: 1243 +artisan_crafting_task: 1229 +bless_is_more_task: 1230 +morgan_the_merrier_task: 1231 +iron_on_task: 1232 +and_it_was_this_big_task: 1233 +belter_of_a_smelter_task: 1234 +nowt_tool_look_at_task: 1235 +you_doity_rat_task: 1236 +it_was_dead_already_task: 1237 +camping_trip_task: 1238 +ratatouille_task: 1239 +slippery_when_wet_task: 1240 +i_cant_hear_dead_people_task: 1241 +come_in_here_and_say_that_task: 1242 +money_down_the_drayn_task: 1244 +klept_old_man_ia_task: 1245 +eye_on_the_prize_task: 1246 +draaaaaiiiiiins_task: 1247 +# Lumbridge/Draynor Medium +steel_justice_task: 1253 +ease_of_access_task: 1254 +everybody_loves_coal_task: 1255 +weeping_willow_task: 1256 +willow_the_wisp_of_smoke_task: 1257 +a_meal_fit_for_a_duke_task: 1258 +always_be_prepared_task: 1259 +hi_ho_silver_task: 1260 +lovely_with_a_squeeze_of_lemon_task: 1261 +one_day_you_shall_be_a_fork_task: 1262 +made_to_order_task: 1263 +wheres_the_beef_task: 1264 +# Lumbridge/Draynor Hard +a_body_in_the_sewers_task: 1222 +building_up_strength_task: 1223 +have_your_cake_and_eat_it_task: 1224 +blast_and_hellfire_task: 1225 +gods_give_me_strength_task: 1226 +not_waving_but_drowning_task: 1227 +are_yew_as_fired_up_as_i_am_task: 1228 +# Falador Easy +amulet_of_weedspeak_task: 1309 +the_good_stuff_task: 1310 +chain_store_task: 1311 +sir_mitt_task: 1312 +family_values_task: 1313 +sniffing_out_the_mole_task: 1314 +chinchompa_powered_task: 1315 +fill_yer_bucket_task: 1316 +elementary_medicine_task: 1317 +its_not_wabbit_season_task: 1318 +stand_and_deliver_task: 1319 +making_my_mind_up_task: 1320 +mudskip_the_light_fantastic_task: 1321 +disarm_and_embark_task: 1322 +going_along_with_the_fro_task: 1323 +# Falador Medium +fruit_of_the_loom_task: 1328 +is_it_so_hard_to_walk_round_task: 1329 +climbing_the_walls_task: 1330 +its_nothing_personal_task: 1331 +ice_the_icy_task: 1332 +blinded_with_science_task: 1333 +they_have_families_to_feed_task: 1334 +stoic_sweetcorn_guardian_task: 1335 +look_spiffy_for_tiffy_task: 1336 +do_they_come_in_other_colours_task: 1337 +these_arent_the_coins_youre_looking_for_task: 1338 +fun_for_the_whole_family_task: 1339 +# Falador Hard +a_knight_in_the_darkness_task: 1340 +child_of_saradomin_task: 1341 +mass_production_task: 1342 +it_spoiled_my_view_task: 1343 +i_heard_you_like_mudskips_task: 1344 +it_matches_my_eyes_task: 1345 +the_stonemasons_task: 1346 +the_mogre_mash_task: 1347 +why_oh_wyvern_task: 1348 +banned_for_life_task: 1349 +# Falador Elite +when_this_caverns_rockin_task: 1350 +youd_best_come_a_cookin_task: 1351 +concentration_is_key_task: 1352 +i_swear_i_heard_it_scream_task: 1353 +ive_changed_my_mind_task: 1354 +a_string_and_a_flare_task: 1355 +altar_ed_state_task: 1356 +# Fremennik Easy +bring_the_antipoisons_task: 1421 +why_wont_you_die_task: 1422 +king_conifer_task: 1423 +assaulted_goodies_task: 1424 +oxymoron_incarnate_task: 1425 +why_did_the_lobster_blush_task: 1426 +hunting_the_hunter_task: 1427 +peer_off_the_pier_task: 1428 +a_familiar_feeling_task: 1429 +endangered_species_task: 1430 +# Fremennik Medium +fremennik_history_101_task: 1431 +cool_story_bro_task: 1432 +whos_a_good_boy_task: 1433 +only_takes_a_little_vial_task: 1434 +you_know_you_want_it_task: 1435 +yak_attack_task: 1436 +fremmental_task: 1437 +fairy_mountaineering_task: 1438 +you_really_dont_need_any_more_shoes_task: 1439 +big_game_hunter_task: 1440 +grand_theft_fish_task: 1441 +# Fremennik Hard +defeating_deadly_dagannoths_task: 1408 +dress_to_impress_task: 1409 +the_graceful_barbarian_task: 1410 +runes_on_the_moon_task: 1411 +pyre_at_will_task: 1412 +fish_fingers_task: 1413 +easy_as_pie_task: 1414 +how_to_maim_your_dragon_task: 1415 +a_periodic_table_task: 1416 +# Fremennik Elite +jaws_breaker_task: 1442 +limber_lumber_jumper_task: 1443 +astronomical_task: 1444 +first_stryke_task: 1445 +leap_of_faith_task: 1446 +no_smoke_without_pyre_task: 1447 +this_hasta_work_task: 1448 +potting_with_otto_task: 1449 +axell_grease_task: 1450 +# Ardougne Easy +the_essence_of_magic_task: 1592 +yoink_task: 1593 +silky_smooth_task: 1594 +preaching_to_the_infected_task: 1595 +playing_the_waiting_game_task: 1596 +gone_fishing_task: 1597 +boot_camp_task: 1598 +a_cat_is_for_life_task: 1599 +creator_and_destroyer_task: 1600 +red_revolution_task: 1601 +going_on_a_summer_holiday_task: 1602 +breaking_and_entering_task: 1603 +p_p_p_pick_up_some_prizes_task: 1604 +a_gift_from_khazard_task: 1605 +party_pooper_task: 1606 +vial_deeds_task: 1607 +star_seeker_task: 1608 +dukes_of_khazard_task: 1609 +dont_eat_the_pointy_bit_task: 1610 +bargain_hunter_task: 1611 +are_you_being_served_task: 1612 +no_time_to_lose_task: 1613 +theyre_long_and_pointy_task: 1614 +# Ardougne Medium +a_visit_to_charlie_task: 1576 +i_wonder_what_this_does_task: 1577 +sandys_secret_getaway_task: 1578 +i_know_a_shortcut_task: 1579 +volatile_valuables_task: 1580 +what_a_melon_task: 1581 +ardougne_express_task: 1582 +arriving_in_style_task: 1583 +by_the_bucketload_task: 1584 +meeting_history_again_task: 1585 +fearless_fishing_task: 1586 +water_logged_task: 1587 +green_fingers_task: 1588 +a_natural_thief_task: 1589 +the_coal_train_task: 1590 +are_you_chicken_task: 1591 +# Ardougne Hard +brace_yourself_task: 1624 +shadow_boxing_task: 1625 +just_like_that_task: 1626 +nice_view_task: 1627 +youre_the_dirty_rascal_task: 1628 +ourania_mania_task: 1629 +not_on_my_watch_task: 1630 +it_just_croaked_task: 1631 +get_your_stinking_hands_off_me_task: 1632 +vine_detta_task: 1633 +living_on_a_prayer_task: 1634 +who_wants_to_watch_the_watchtower_task: 1635 +monkey_business_task: 1636 +its_my_newt_task: 1637 +a_taste_of_the_exotic_task: 1638 +blood_bank_withdrawal_task: 1639 +artillery_strike_task: 1640 +# Ardougne Elite +catching_some_rays_task: 1619 +abyssal_valet_task: 1620 +you_could_just_knock_task: 1621 +honestly_its_not_a_purse_task: 1622 +almost_made_in_ardougne_task: 1623 +# Elsewhere... None +no_task_available_task: 1642 +world_map_blue_marker: 972 +world_map_grave_marker: 0 +world_map_default_marker: 280 \ No newline at end of file diff --git a/data/definitions/variables-client-string.yml b/data/definitions/variables-client-string.yml index 6d46dde42f..d87bb6dc42 100644 --- a/data/definitions/variables-client-string.yml +++ b/data/definitions/variables-client-string.yml @@ -19,4 +19,9 @@ equipment_name: 321 equipment_titles: 322 equipment_names: 323 equipment_stats: 324 -comparison_stats: 325 \ No newline at end of file +comparison_stats: 325 +world_map_marker_text_1: 53 +world_map_marker_text_2: 54 +world_map_marker_text_3: 55 +world_map_marker_text_4: 56 +world_map_marker_text_5: 190 diff --git a/data/definitions/variables-client.yml b/data/definitions/variables-client.yml index a28348503d..d52fec3e2b 100644 --- a/data/definitions/variables-client.yml +++ b/data/definitions/variables-client.yml @@ -213,12 +213,6 @@ tab: format: list default: Inventory values: [ CombatStyles, TaskSystem, Stats, QuestJournals, Inventory, WornEquipment, PrayerList, MagicSpellbook, FriendsList, FriendsChat, ClanChat, Options, Emotes, MusicPlayer, Notes ] -world_map_centre: - id: 622 - format: int -world_map_player: - id: 674 - format: int equipment_emote: id: 779 default: 1426 @@ -369,4 +363,54 @@ celestial_surgebox_wave: format: int celestial_surgebox_surge: id: 1403 - format: int \ No newline at end of file + format: int +task_progress_total: + id: 1423 + format: int +task_progress_current: + id: 1424 + format: int +task_dont_show_again: + id: 1421 + format: boolean + persist: true +task_popup: + id: 1425 + format: int +task_previous_popup: + id: 1426 + format: int +task_fade_in_cycle: + id: 1427 + format: int +task_popup_summary: + id: 1428 + format: boolean +task_disable_popups: + id: 1429 + format: boolean + persist: true +world_map_zoom_level: + id: 172 + format: int +world_map_centre: + id: 622 + format: int +world_map_marker_player: + id: 674 + format: int +world_map_marker_1: + id: 623 + format: int +world_map_marker_2: + id: 625 + format: int +world_map_marker_3: + id: 627 + format: int +world_map_marker_4: + id: 629 + format: int +world_map_marker_5: + id: 940 + format: int diff --git a/data/definitions/variables-custom.yml b/data/definitions/variables-custom.yml index 578fa3c762..ce0eb2d3d4 100644 --- a/data/definitions/variables-custom.yml +++ b/data/definitions/variables-custom.yml @@ -25,7 +25,7 @@ cooks_assistant_flour: persist: true cooks_assistant_talked_to_millie: format: boolean - persist: true + persist: true bone_delay: format: int recover_special_delay: @@ -339,4 +339,138 @@ gem_bag_ruby: persist: true gem_bag_diamond: format: int - persist: true \ No newline at end of file + persist: true +varrock_easy: + persist: true + format: bitwise + values: [ strike_a_pose, essential_facilitator, doing_the_ironing, plank_you_very_much, making_learning_fun, jumping_off_point, lumbering_around, read_all_about_it, dog_and_bone, pot_stop, on_the_ragged_edge, relocation_relocation_relocation, it_belongs_in_a_museum, journey_to_the_centre_of_the_earth_altar, jackanory, limey, sherpas_delight, king_of_the_castle, stick_the_knife_in ] +varrock_medium: + persist: true + format: bitwise + values: [ double_strength_weaksauce, champion, what_lies_below, with_a_ten_foot_pole, cant_make_an_omelette, point_of_en_tree, unlocking_your_emotions, a_lick_of_paint, for_fast_transactions, you_wouldnt_like_me_when_im_angry, return_to_senntisten, promised_the_earth, royale_with_thieve, like_a_varrocket, challenge_vannaka, flatpack_backpack, master_scrumper, engage, faster_pussycat_kill_kill, dial_v_for_varrock, the_body_shop ] +varrock_hard: + persist: true + format: bitwise + values: [ burning_bush, but_it_wont_warp_you_anywhere, lighten_up, put_your_smithing_hat_on, kudos_on_the_kudos, who_ate_all_the_pie, battle_of_the_elements, changing_rooms, keeping_tabs_on_varrock, hand_me_downs, waka_waka_waka, living_on_the_edge, intersceptre ] +varrock_elite: + persist: true + format: bitwise + values: [ stick_a_bork_in_him_hes_done, nomadness, double_jointed, it_all_adze_up, mind_your_back, red_red_pies_of_summer, splitting_headache, a_bolt_from_the_blue, a_ton_of_earth ] +karamja_easy: + persist: true + format: bitwise + values: [ five_a_day, im_lichen_this, golden_shores, put_to_port_in_port_sarim, avast_ardougne, show_that_you_cairn, fruity_catch, beachcomber, tzhaar_wars, its_a_jungle_ogre ] +karamja_medium: + persist: true + format: bitwise + values: [ just_the_ticket, back_cran_door, dungeons_and_dragons, horseless_carriage, they_like_me_they_really_like_me, arachnophagia, romancing_the_stone, im_a_lumberjack_and_im_okay, i_sleep_all_night_and_i_work_all_day, to_catch_a_karambwan, thats_not_a_knife, falling_with_style, scourge_of_scurvy, hunters_of_the_horned_graahk, the_roots_of_all_evil, hotfooting_it, stairway_to_haven, thank_you_madam, shipping_out_from_the_shipyard ] +karamja_hard: + persist: true + format: bitwise + values: [ flawless_victory, play_dead_doggy, id_be_kharazi_to_eat_this, at_one_with_nature, drop_it_like_its_hot, deadwing, quick_as_a_shot, a_palm_for_each_finger, yes_my_master, can_opener ] +karamja_elite: + persist: true + format: bitwise + values: [ at_one_plus_fifty_five_with_nature, the_power_of_lava, boxing_clever, its_a_snap, crunchy_coating, walkies, tread_carefully, ten_in_a_row ] +seers_village_easy: + persist: true + format: bitwise + values: [ reflax_actions, why, stir_galahad, la_morte_darthur, bunch_of_flours, happy_hour, jute_alors, sinclair_swirling, grand_candle, a_seer_ing_light, mack_rolled ] +seers_village_medium: + persist: true + format: bitwise + values: [ fleeing_the_scene, its_a_slightly_magical_stick, king_coal, i_can_seer_my_house_from_here, mastering_the_elements, its_only_a_model, sniper_training, arch_archer, what_no_cuddly_toy, familiar_fire_familiarity, at_least_it_doesnt_need_walking, all_your_bass ] +seers_village_hard: + persist: true + format: bitwise + values: [ at_home_on_the_range, see_yew_at_five, the_short_of_it, prayer_of_attorney, beware_of_the_dog, twisted_fire_starter, alch_aholic, gonna_need_a_bigger_boat, gonna_need_a_bigger_range, water_palaver, island_hopper ] +seers_village_elite: + persist: true + format: bitwise + values: [ its_a_trap_no_wait_its_a_pie, make_a_bolt_for_it, the_long_of_it, plentypotionentiary, moon_raker ] +elsewhere_none: + persist: true + format: bitwise + values: [ ] +lumbridge_draynor_beginner_rewards: + persist: true + format: bitwise + values: [ on_the_run, a_world_in_microcosm, master_of_all_i_survey, raise_the_roof, take_your_pick, adventurers_log, arent_they_supposed_to_be_twins, log_a_rhythm, shellfish_roasting_on_an_open_fire, heavy_metal, bar_one, cutting_edge_technology, armed_and_dangerous, on_your_way, you_can_bank_on_us, hang_on_to_something, bovine_intervention, tan_your_hide, handicrafts, handy_dandy, just_cant_get_the_staff, click_your_heels_three_times, come_and_have_a_go, reach_out_and_touch_someone, three_rounds_rapid_men, death_from_above, flour_power, a_labour_of_loaf, om_nom_nom_nom, on_the_level, so_thats_what_ess_stands_for, air_craft, greasing_the_wheels_of_commerce, must_be_funny_in_a_rich_mans_world, i_wonder_if_itll_sprout, put_your_hands_together_for, prayer_point_power, not_what_we_mean_by_irony, alls_ferrous_in_love_and_war, am_i_a_blademaster_yet, first_blood, temper_temper, steel_yourself_for_combat, ammo_ammo_ammo, take_a_bow, dont_bury_this_one, mace_invaders, capital_protection_what, clay_of_champions, just_add_water, very_potter, hotpot, hack_and_smash, shrimpin_aint_easy, the_fruit_of_the_sea, made_for_walking, did_anyone_bring_any_toast, its_not_a_red_one, not_so_confusing_after_all, absolutely_enchanting, heart_of_oak, get_the_point, berry_tasty, dishwater, cant_touch_this, quarter_centurion, fledgeling_adventurer, hail_to_the_duke_baby, doom, sage_advice, window_shopping, wait_thats_not_a_sheep, in_the_countyard, grinding_my_gears, beware_of_pigzilla, the_rules_of_engagement, tower_power, a_grave_consideration, tinkle_the_ivories, ring_my_bell, passing_out ] +lumbridge_draynor_easy_rewards: + persist: true + format: bitwise + values: [ what_is_this_place, artisan_crafting, bless_is_more, morgan_the_merrier, iron_on, and_it_was_this_big, belter_of_a_smelter, nowt_tool_look_at, you_doity_rat, it_was_dead_already, camping_trip, ratatouille, slippery_when_wet, i_cant_hear_dead_people, come_in_here_and_say_that, money_down_the_drayn, klept_old_man_ia, eye_on_the_prize, draaaaaiiiiiins ] +lumbridge_draynor_medium_rewards: + persist: true + format: bitwise + values: [ steel_justice, ease_of_access, everybody_loves_coal, weeping_willow, willow_the_wisp_of_smoke, a_meal_fit_for_a_duke, always_be_prepared, hi_ho_silver, lovely_with_a_squeeze_of_lemon, one_day_you_shall_be_a_fork, made_to_order, wheres_the_beef ] +lumbridge_draynor_hard_rewards: + persist: true + format: bitwise + values: [ a_body_in_the_sewers, building_up_strength, have_your_cake_and_eat_it, blast_and_hellfire, gods_give_me_strength, not_waving_but_drowning, are_yew_as_fired_up_as_i_am ] +falador_easy_rewards: + persist: true + format: bitwise + values: [ amulet_of_weedspeak, the_good_stuff, chain_store, sir_mitt, family_values, sniffing_out_the_mole, chinchompa_powered, fill_yer_bucket, elementary_medicine, its_not_wabbit_season, stand_and_deliver, making_my_mind_up, mudskip_the_light_fantastic, disarm_and_embark, going_along_with_the_fro ] +falador_medium_rewards: + persist: true + format: bitwise + values: [ fruit_of_the_loom, is_it_so_hard_to_walk_round, climbing_the_walls, its_nothing_personal, ice_the_icy, blinded_with_science, they_have_families_to_feed, stoic_sweetcorn_guardian, look_spiffy_for_tiffy, do_they_come_in_other_colours, these_arent_the_coins_youre_looking_for, fun_for_the_whole_family ] +falador_hard_rewards: + persist: true + format: bitwise + values: [ a_knight_in_the_darkness, child_of_saradomin, mass_production, it_spoiled_my_view, i_heard_you_like_mudskips, it_matches_my_eyes, the_stonemasons, the_mogre_mash, why_oh_wyvern, banned_for_life ] +falador_elite_rewards: + persist: true + format: bitwise + values: [ when_this_caverns_rockin, youd_best_come_a_cookin, concentration_is_key, i_swear_i_heard_it_scream, ive_changed_my_mind, a_string_and_a_flare, altar_ed_state ] +fremennik_easy_rewards: + persist: true + format: bitwise + values: [ bring_the_antipoisons, why_wont_you_die, king_conifer, assaulted_goodies, oxymoron_incarnate, why_did_the_lobster_blush, hunting_the_hunter, peer_off_the_pier, a_familiar_feeling, endangered_species ] +fremennik_medium_rewards: + persist: true + format: bitwise + values: [ fremennik_history_101, cool_story_bro, whos_a_good_boy, only_takes_a_little_vial, you_know_you_want_it, yak_attack, fremmental, fairy_mountaineering, you_really_dont_need_any_more_shoes, big_game_hunter, grand_theft_fish ] +fremennik_hard_rewards: + persist: true + format: bitwise + values: [ defeating_deadly_dagannoths, dress_to_impress, the_graceful_barbarian, runes_on_the_moon, pyre_at_will, fish_fingers, easy_as_pie, how_to_maim_your_dragon, a_periodic_table ] +fremennik_elite_rewards: + persist: true + format: bitwise + values: [ jaws_breaker, limber_lumber_jumper, astronomical, first_stryke, leap_of_faith, no_smoke_without_pyre, this_hasta_work, potting_with_otto, axell_grease ] +ardougne_easy_rewards: + persist: true + format: bitwise + values: [ the_essence_of_magic, yoink, silky_smooth, preaching_to_the_infected, playing_the_waiting_game, gone_fishing, boot_camp, a_cat_is_for_life, creator_and_destroyer, red_revolution, going_on_a_summer_holiday, breaking_and_entering, p_p_p_pick_up_some_prizes, a_gift_from_khazard, party_pooper, vial_deeds, star_seeker, dukes_of_khazard, dont_eat_the_pointy_bit, bargain_hunter, are_you_being_served, no_time_to_lose, theyre_long_and_pointy ] +ardougne_medium_rewards: + persist: true + format: bitwise + values: [ a_visit_to_charlie, i_wonder_what_this_does, sandys_secret_getaway, i_know_a_shortcut, volatile_valuables, what_a_melon, ardougne_express, arriving_in_style, by_the_bucketload, meeting_history_again, fearless_fishing, water_logged, green_fingers, a_natural_thief, the_coal_train, are_you_chicken ] +ardougne_hard_rewards: + persist: true + format: bitwise + values: [ brace_yourself, shadow_boxing, just_like_that, nice_view, youre_the_dirty_rascal, ourania_mania, not_on_my_watch, it_just_croaked, get_your_stinking_hands_off_me, vine_detta, living_on_a_prayer, who_wants_to_watch_the_watchtower, monkey_business, its_my_newt, a_taste_of_the_exotic, blood_bank_withdrawal, artillery_strike ] +ardougne_elite_rewards: + persist: true + format: bitwise + values: [ catching_some_rays, abyssal_valet, you_could_just_knock, honestly_its_not_a_purse, almost_made_in_ardougne ] +giant_rat_aggressive: + persist: true + format: boolean +giant_rat_defensive: + persist: true + format: boolean +giant_rat_controlled: + persist: true + format: boolean +equip_shortbow: + persist: true + format: boolean +equip_longbow: + persist: true + format: boolean +equip_crossbow: + persist: true + format: boolean diff --git a/data/definitions/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index d2a2b5e808..ee2fe7464a 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -365,14 +365,6 @@ unlocked_emote_seal_of_approval: id: 8688 persist: true format: boolean -unlocked_emote_taskmaster: - id: 8601 - persist: true - format: map - default: false - values: - false: 0 - true: 417 equipment_banking: id: 4894 format: boolean @@ -430,9 +422,18 @@ fist_of_guthix_charges: stealing_creation_points: id: 5505 format: int -penguins_found: +penguin_points: + id: 5275 + format: int + persist: true +penguins_found_weekly: id: 5276 format: int + persist: true +penguin_hide_and_seek_explained: + id: 5277 + format: boolean + persist: true investment_credits: id: 6351 format: int @@ -575,7 +576,7 @@ death_altar_ruins: blood_altar_ruins: id: 619 format: boolean -minigame_type: +minigame_format: id: 4540 format: map default: none @@ -648,4 +649,2047 @@ scrying_orb_wizard_distentor: id: 2318 format: boolean persist: true - transmit: false \ No newline at end of file + transmit: false +task_slot_1: + id: 8587 + format: int +task_slot_2: + id: 8588 + format: int +task_slot_3: + id: 8589 + format: int +task_slot_4: + id: 8590 + format: int +task_slot_5: + id: 8591 + format: int +task_slot_6: + id: 8592 + format: int +task_pinned: + id: 8576 + format: int + persist: true +task_pin_index: + id: 8577 + format: int + persist: true +task_area: + id: 8575 + format: map + default: empty + values: + dnd_activities: 0 + lumbridge_draynor: 1 + varrock: 2 + falador: 3 + seers_village: 4 + ardougne: 5 + karamja: 6 + fremennik: 7 + unstable_foundations: 60 + empty: 61 + elsewhere: 63 +task_progress_overall: + id: 8601 + format: int +task_list_area: + id: 8582 + format: map + persist: true + default: unstable_foundations + values: + dnd_activities: 0 + lumbridge_draynor: 1 + varrock: 2 + falador: 3 + seers_village: 4 + ardougne: 5 + karamja: 6 + fremennik: 7 + unstable_foundations: 60 + empty: 61 + elsewhere: 63 +task_hide_completed: + id: 8579 + format: boolean + persist: true +task_filter_sets: + id: 8580 + format: boolean + persist: true +tower_of_life: + id: 3337 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 18 +wolf_whistle: + id: 4302 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 110 +fairy_rings_unlocked: + id: 2328 + format: boolean + persist: true +kenniths_concerns: + id: 4505 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 100 +enlightened_journey: + id: 2866 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 200 +hand_in_the_sand: + id: 1527 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 160 +meeting_history: + id: 5075 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 20 +lunar_diplomacy: + id: 2448 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 190 +back_to_my_roots: + id: 4055 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 65 +catapult_construction: + id: 4396 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 60 +dragon_slayer_received_shield: + id: 3746 + format: boolean + persist: true +garden_of_tranquillity: + id: 961 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 60 +wanted: + id: 1051 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 10 +rat_catchers: + id: 1404 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 127 +recruitment_drive: + id: 657 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 2 +temple_at_senntisten: + id: 6775 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 90 +slug_menace: + id: 2610 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 14 +bar_crawl_started: + id: 3378 + format: boolean + persist: true +barbarian_training_fishing_unlocked: + id: 3757 + format: boolean + persist: true +barbarian_training_mix_unlocked: + id: 3761 + format: boolean + persist: true +barbarian_training_hasta_unlocked: + id: 3763 + format: boolean + persist: true +barbarian_training_pyre_unlocked: + id: 3764 + format: boolean + persist: true +royal_trouble: + id: 2140 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 30 +blood_runs_deep: + id: 6883 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 147 +while_guthix_sleeps: + id: 5491 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 910 +elemental_workshop_i: + id: 2067 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 1 +knights_waves: + id: 3909 + format: int + persist: true +what_lies_below: + id: 3523 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 150 +souls_bane: + id: 2011 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 13 +teleport_to_digsite_with_pendant: + id: 3639 + format: boolean + persist: true +desert_treasure: + id: 358 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 15 +nomads_requiem: + id: 6962 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 12 +all_fired_up: + id: 5133 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 90 +nurture_evil_tree_stage: + id: 1545 + format: boolean + persist: true +circus_magic: + id: 5251 + format: boolean + persist: true +circus_agility: + id: 5252 + format: boolean + persist: true +circus_ranged: + id: 5253 + format: boolean + persist: true +fur_n_seek: + id: 6307 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 12 +skeletal_horror_respawn_minute: + id: 6305 + format: int + persist: true +kings_ransom: + id: 3888 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 90 +# D&Ds / Activities None +introducing_explorer_jack_task: + id: 6494 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 3 +# Varrock Easy +strike_a_pose_task: + id: 3986 + format: boolean + persist: true +essential_facilitator_task: + id: 3987 + format: boolean + persist: true +doing_the_ironing_task: + id: 3988 + format: boolean + persist: true +plank_you_very_much_task: + id: 3989 + format: boolean + persist: true +making_learning_fun_task: + id: 3990 + format: boolean + persist: true +jumping_off_point_task: + id: 3991 + format: boolean + persist: true +lumbering_around_task: + id: 3992 + format: boolean + persist: true +read_all_about_it_task: + id: 3993 + format: boolean + persist: true +dog_and_bone_task: + id: 3994 + format: boolean + persist: true +pot_stop_task: + id: 3995 + format: boolean + persist: true +on_the_ragged_edge_task: + id: 3996 + format: boolean + persist: true +relocation_relocation_relocation_task: + id: 3997 + format: boolean + persist: true +it_belongs_in_a_museum_task: + id: 3998 + format: boolean + persist: true +journey_to_the_centre_of_the_earth_altar_task: + id: 3999 + format: boolean + persist: true +jackanory_task: + id: 4000 + format: boolean + persist: true +limey_task: + id: 4001 + format: boolean + persist: true +sherpas_delight_task: + id: 4002 + format: boolean + persist: true +king_of_the_castle_task: + id: 4004 + format: boolean + persist: true +stick_the_knife_in_task: + id: 4005 + format: boolean + persist: true +# Varrock Medium +double_strength_weaksauce_task: + id: 4003 + format: boolean + persist: true +champion_task: + id: 4007 + format: boolean + persist: true +what_lies_below_task: + id: 4008 + format: boolean + persist: true +with_a_ten_foot_pole_task: + id: 4009 + format: boolean + persist: true +cant_make_an_omelette_task: + id: 4010 + format: boolean + persist: true +point_of_en_tree_task: + id: 4011 + format: boolean + persist: true +unlocking_your_emotions_task: + id: 4012 + format: boolean + persist: true +a_lick_of_paint_task: + id: 4013 + format: boolean + persist: true +for_fast_transactions_task: + id: 4014 + format: boolean + persist: true +you_wouldnt_like_me_when_im_angry_task: + id: 4015 + format: boolean + persist: true +return_to_senntisten_task: + id: 4016 + format: boolean + persist: true +promised_the_earth_task: + id: 4017 + format: boolean + persist: true +royale_with_thieve_task: + id: 4018 + format: boolean + persist: true +like_a_varrocket_task: + id: 4019 + format: boolean + persist: true +challenge_vannaka_task: + id: 4020 + format: boolean + persist: true +flatpack_backpack_task: + id: 4021 + format: boolean + persist: true +master_scrumper_task: + id: 4022 + format: boolean + persist: true +engage_task: + id: 4023 + format: boolean + persist: true +faster_pussycat_kill_kill_task: + id: 4024 + format: boolean + persist: true +dial_v_for_varrock_task: + id: 4025 + format: boolean + persist: true +the_body_shop_task: + id: 4026 + format: boolean + persist: true +# Varrock Hard +burning_bush_task: + id: 4027 + format: boolean + persist: true +but_it_wont_warp_you_anywhere_task: + id: 4028 + format: boolean + persist: true +lighten_up_task: + id: 4029 + format: boolean + persist: true +put_your_smithing_hat_on_task: + id: 4030 + format: boolean + persist: true +kudos_on_the_kudos_task: + id: 4031 + format: boolean + persist: true +who_ate_all_the_pie_task: + id: 4032 + format: boolean + persist: true +battle_of_the_elements_task: + id: 4033 + format: boolean + persist: true +changing_rooms_task: + id: 4035 + format: boolean + persist: true +keeping_tabs_on_varrock_task: + id: 4036 + format: boolean + persist: true +hand_me_downs_task: + id: 4037 + format: boolean + persist: true +waka_waka_waka_task: + id: 4038 + format: boolean + persist: true +living_on_the_edge_task: + id: 4039 + format: boolean + persist: true +intersceptre_task: + id: 4034 + format: boolean + persist: true +# Varrock Elite +stick_a_bork_in_him_hes_done_task: + id: 8136 + format: boolean + persist: true +nomadness_task: + id: 8137 + format: boolean + persist: true +double_jointed_task: + id: 8138 + format: boolean + persist: true +it_all_adze_up_task: + id: 8139 + format: boolean + persist: true +mind_your_back_task: + id: 8140 + format: boolean + persist: true +red_red_pies_of_summer_task: + id: 8141 + format: boolean + persist: true +splitting_headache_task: + id: 8145 + format: boolean + persist: true +a_bolt_from_the_blue_task: + id: 8146 + format: boolean + persist: true +a_ton_of_earth_task: + id: 8148 + format: boolean + persist: true +# Karamja Easy +five_a_day_task: + id: 3566 + format: boolean + persist: true +im_lichen_this_task: + id: 3567 + format: boolean + persist: true +golden_shores_task: + id: 3568 + format: boolean + persist: true +put_to_port_in_port_sarim_task: + id: 3569 + format: boolean + persist: true +avast_ardougne_task: + id: 3570 + format: boolean + persist: true +show_that_you_cairn_task: + id: 3571 + format: boolean + persist: true +fruity_catch_task: + id: 3572 + format: boolean + persist: true +beachcomber_task: + id: 3573 + format: boolean + persist: true +tzhaar_wars_task: + id: 3574 + format: boolean + persist: true +its_a_jungle_ogre_task: + id: 3575 + format: boolean + persist: true +# Karamja Medium +just_the_ticket_task: + id: 3579 + format: boolean + persist: true +back_cran_door_task: + id: 3580 + format: boolean + persist: true +dungeons_and_dragons_task: + id: 3581 + format: boolean + persist: true +horseless_carriage_task: + id: 3582 + format: boolean + persist: true +they_like_me_they_really_like_me_task: + id: 3583 + format: boolean + persist: true +arachnophagia_task: + id: 3584 + format: boolean + persist: true +romancing_the_stone_task: + id: 3585 + format: boolean + persist: true +im_a_lumberjack_and_im_okay_task: + id: 3586 + format: boolean + persist: true +i_sleep_all_night_and_i_work_all_day_task: + id: 3587 + format: boolean + persist: true +to_catch_a_karambwan_task: + id: 3588 + format: boolean + persist: true +thats_not_a_knife_task: + id: 3589 + format: boolean + persist: true +falling_with_style_task: + id: 3590 + format: boolean + persist: true +scourge_of_scurvy_task: + id: 3591 + format: boolean + persist: true +hunters_of_the_horned_graahk_task: + id: 3592 + format: boolean + persist: true +the_roots_of_all_evil_task: + id: 3593 + format: boolean + persist: true +hotfooting_it_task: + id: 3594 + format: boolean + persist: true +stairway_to_haven_task: + id: 3595 + format: boolean + persist: true +thank_you_madam_task: + id: 3596 + format: boolean + persist: true +shipping_out_from_the_shipyard_task: + id: 3597 + format: boolean + persist: true +# Karamja Hard +flawless_victory_task: + id: 3600 + format: boolean + persist: true +play_dead_doggy_task: + id: 3601 + format: boolean + persist: true +id_be_kharazi_to_eat_this_task: + id: 3602 + format: boolean + persist: true +at_one_with_nature_task: + id: 3603 + format: boolean + persist: true +drop_it_like_its_hot_task: + id: 3604 + format: boolean + persist: true +deadwing_task: + id: 3605 + format: boolean + persist: true +quick_as_a_shot_task: + id: 3606 + format: boolean + persist: true +a_palm_for_each_finger_task: + id: 3607 + format: boolean + persist: true +yes_my_master_task: + id: 3608 + format: boolean + persist: true +can_opener_task: + id: 3609 + format: boolean + persist: true +# Karamja Elite +at_one_plus_fifty_five_with_nature_task: + id: 8121 + format: boolean + persist: true +the_power_of_lava_task: + id: 8122 + format: boolean + persist: true +boxing_clever_task: + id: 8123 + format: boolean + persist: true +its_a_snap_task: + id: 8124 + format: boolean + persist: true +crunchy_coating_task: + id: 8125 + format: boolean + persist: true +walkies_task: + id: 8126 + format: boolean + persist: true +tread_carefully_task: + id: 8127 + format: boolean + persist: true +ten_in_a_row_task: + id: 8128 + format: boolean + persist: true +# Seers' Village Easy +reflax_actions_task: + id: 5782 + format: boolean + persist: true +why_task: + id: 5783 + format: boolean + persist: true +stir_galahad_task: + id: 5785 + format: boolean + persist: true +la_morte_darthur_task: + id: 5786 + format: boolean + persist: true +bunch_of_flours_task: + id: 5788 + format: boolean + persist: true +happy_hour_task: + id: 5789 + format: boolean + persist: true +jute_alors_task: + id: 5784 + format: boolean + persist: true +sinclair_swirling_task: + id: 5790 + format: boolean + persist: true +grand_candle_task: + id: 5791 + format: boolean + persist: true +a_seer_ing_light_task: + id: 5792 + format: boolean + persist: true +mack_rolled_task: + id: 5793 + format: boolean + persist: true +# Seers' Village Medium +fleeing_the_scene_task: + id: 5794 + format: boolean + persist: true +its_a_slightly_magical_stick_task: + id: 5795 + format: boolean + persist: true +king_coal_task: + id: 5796 + format: boolean + persist: true +i_can_seer_my_house_from_here_task: + id: 5801 + format: boolean + persist: true +mastering_the_elements_task: + id: 5797 + format: boolean + persist: true +its_only_a_model_task: + id: 5798 + format: boolean + persist: true +sniper_training_task: + id: 5805 + format: boolean + persist: true +arch_archer_task: + id: 5799 + format: boolean + persist: true +what_no_cuddly_toy_task: + id: 5800 + format: boolean + persist: true +familiar_fire_familiarity_task: + id: 5802 + format: boolean + persist: true +at_least_it_doesnt_need_walking_task: + id: 5803 + format: boolean + persist: true +all_your_bass_task: + id: 5804 + format: boolean + persist: true +# Seers' Village Hard +at_home_on_the_range_task: + id: 5806 + format: boolean + persist: true +see_yew_at_five_task: + id: 5807 + format: boolean + persist: true +the_short_of_it_task: + id: 5808 + format: boolean + persist: true +prayer_of_attorney_task: + id: 5809 + format: boolean + persist: true +beware_of_the_dog_task: + id: 5810 + format: boolean + persist: true +twisted_fire_starter_task: + id: 5811 + format: boolean + persist: true +alch_aholic_task: + id: 5812 + format: boolean + persist: true +gonna_need_a_bigger_boat_task: + id: 5814 + format: boolean + persist: true +gonna_need_a_bigger_range_task: + id: 5815 + format: boolean + persist: true +water_palaver_task: + id: 5816 + format: boolean + persist: true +island_hopper_task: + id: 5813 + format: boolean + persist: true +# Seers' Village Elite +its_a_trap_no_wait_its_a_pie_task: + id: 8205 + format: boolean + persist: true +make_a_bolt_for_it_task: + id: 8212 + format: boolean + persist: true +the_long_of_it_task: + id: 8217 + format: boolean + persist: true +plentypotionentiary_task: + id: 8221 + format: boolean + persist: true +moon_raker_task: + id: 8224 + format: boolean + persist: true +# Elsewhere... None +# Lumbridge/Draynor Beginner +on_the_run_task: + id: 8522 + format: boolean + persist: true +a_world_in_microcosm_task: + id: 8521 + format: boolean + persist: true +master_of_all_i_survey_task: + id: 4952 + format: boolean + persist: true +raise_the_roof_task: + id: 4953 + format: boolean + persist: true +take_your_pick_task: + id: 4961 + format: boolean + persist: true +adventurers_log_task: + id: 8523 + format: boolean + persist: true +arent_they_supposed_to_be_twins_task: + id: 8524 + format: boolean + persist: true +log_a_rhythm_task: + id: 8525 + format: boolean + persist: true +shellfish_roasting_on_an_open_fire_task: + id: 8526 + format: boolean + persist: true +heavy_metal_task: + id: 8517 + format: boolean + persist: true +bar_one_task: + id: 8518 + format: boolean + persist: true +cutting_edge_technology_task: + id: 8519 + format: boolean + persist: true +armed_and_dangerous_task: + id: 8520 + format: boolean + persist: true +on_your_way_task: + id: 8527 + format: boolean + persist: true +you_can_bank_on_us_task: + id: 8528 + format: boolean + persist: true +hang_on_to_something_task: + id: 8529 + format: boolean + persist: true +bovine_intervention_task: + id: 8560 + format: boolean + persist: true +tan_your_hide_task: + id: 8573 + format: boolean + persist: true +handicrafts_task: + id: 8574 + format: boolean + persist: true +handy_dandy_task: + id: 8530 + format: boolean + persist: true +just_cant_get_the_staff_task: + id: 8531 + format: boolean + persist: true +click_your_heels_three_times_task: + id: 8532 + format: boolean + persist: true +come_and_have_a_go_task: + id: 8533 + format: boolean + persist: true +reach_out_and_touch_someone_task: + id: 8534 + format: boolean + persist: true +three_rounds_rapid_men_task: + id: 8535 + format: boolean + persist: true +death_from_above_task: + id: 8536 + format: boolean + persist: true +flour_power_task: + id: 8537 + format: boolean + persist: true +a_labour_of_loaf_task: + id: 8538 + format: boolean + persist: true +om_nom_nom_nom_task: + id: 8539 + format: boolean + persist: true +on_the_level_task: + id: 8540 + format: boolean + persist: true +so_thats_what_ess_stands_for_task: + id: 8541 + format: boolean + persist: true +air_craft_task: + id: 8542 + format: boolean + persist: true +greasing_the_wheels_of_commerce_task: + id: 8543 + format: boolean + persist: true +must_be_funny_in_a_rich_mans_world_task: + id: 8544 + format: boolean + persist: true +i_wonder_if_itll_sprout_task: + id: 8545 + format: boolean + persist: true +put_your_hands_together_for_task: + id: 8546 + format: boolean + persist: true +prayer_point_power_task: + id: 8547 + format: boolean + persist: true +not_what_we_mean_by_irony_task: + id: 8548 + format: boolean + persist: true +alls_ferrous_in_love_and_war_task: + id: 8549 + format: boolean + persist: true +am_i_a_blademaster_yet_task: + id: 8550 + format: boolean + persist: true +first_blood_task: + id: 8551 + format: boolean + persist: true +temper_temper_task: + id: 8552 + format: boolean + persist: true +steel_yourself_for_combat_task: + id: 8553 + format: boolean + persist: true +ammo_ammo_ammo_task: + id: 8554 + format: boolean + persist: true +take_a_bow_task: + id: 8555 + format: boolean + persist: true +dont_bury_this_one_task: + id: 8556 + format: boolean + persist: true +mace_invaders_task: + id: 8557 + format: boolean + persist: true +capital_protection_what_task: + id: 8558 + format: boolean + persist: true +clay_of_champions_task: + id: 4968 + format: boolean + persist: true +just_add_water_task: + id: 4969 + format: boolean + persist: true +very_potter_task: + id: 4970 + format: boolean + persist: true +hotpot_task: + id: 4971 + format: boolean + persist: true +hack_and_smash_task: + id: 8559 + format: boolean + persist: true +shrimpin_aint_easy_task: + id: 4951 + format: boolean + persist: true +the_fruit_of_the_sea_task: + id: 4967 + format: boolean + persist: true +made_for_walking_task: + id: 8561 + format: boolean + persist: true +did_anyone_bring_any_toast_task: + id: 8562 + format: boolean + persist: true +its_not_a_red_one_task: + id: 8563 + format: boolean + persist: true +not_so_confusing_after_all_task: + id: 8564 + format: boolean + persist: true +absolutely_enchanting_task: + id: 8565 + format: boolean + persist: true +heart_of_oak_task: + id: 8566 + format: boolean + persist: true +get_the_point_task: + id: 8567 + format: boolean + persist: true +berry_tasty_task: + id: 8568 + format: boolean + persist: true +dishwater_task: + id: 8569 + format: boolean + persist: true +cant_touch_this_task: + id: 8570 + format: boolean + persist: true +quarter_centurion_task: + id: 8571 + format: boolean + persist: true +fledgeling_adventurer_task: + id: 8572 + format: boolean + persist: true +hail_to_the_duke_baby_task: + id: 4954 + format: boolean + persist: true +doom_task: + id: 4950 + format: boolean + persist: true +sage_advice_task: + id: 4957 + format: boolean + persist: true +window_shopping_task: + id: 4955 + format: boolean + persist: true +wait_thats_not_a_sheep_task: + id: 4966 + format: boolean + persist: true +in_the_countyard_task: + id: 4963 + format: boolean + persist: true +grinding_my_gears_task: + id: 4956 + format: boolean + persist: true +beware_of_pigzilla_task: + id: 4965 + format: boolean + persist: true +the_rules_of_engagement_task: + id: 4960 + format: boolean + persist: true +tower_power_task: + id: 4964 + format: boolean + persist: true +a_grave_consideration_task: + id: 4949 + format: boolean + persist: true +tinkle_the_ivories_task: + id: 4958 + format: boolean + persist: true +ring_my_bell_task: + id: 4962 + format: boolean + persist: true +passing_out_task: + id: 4959 + format: boolean + persist: true +# Lumbridge/Draynor Easy +what_is_this_place_task: + id: 4985 + format: boolean + persist: true +artisan_crafting_task: + id: 4987 + format: boolean + persist: true +bless_is_more_task: + id: 4988 + format: boolean + persist: true +morgan_the_merrier_task: + id: 4989 + format: boolean + persist: true +iron_on_task: + id: 4991 + format: boolean + persist: true +and_it_was_this_big_task: + id: 4972 + format: boolean + persist: true +belter_of_a_smelter_task: + id: 4974 + format: boolean + persist: true +nowt_tool_look_at_task: + id: 4980 + format: boolean + persist: true +you_doity_rat_task: + id: 4981 + format: boolean + persist: true +it_was_dead_already_task: + id: 4982 + format: boolean + persist: true +camping_trip_task: + id: 4983 + format: boolean + persist: true +ratatouille_task: + id: 4984 + format: boolean + persist: true +slippery_when_wet_task: + id: 4976 + format: boolean + persist: true +i_cant_hear_dead_people_task: + id: 4979 + format: boolean + persist: true +come_in_here_and_say_that_task: + id: 4975 + format: boolean + persist: true +money_down_the_drayn_task: + id: 4986 + format: boolean + persist: true +klept_old_man_ia_task: + id: 4977 + format: boolean + persist: true +eye_on_the_prize_task: + id: 4978 + format: boolean + persist: true +draaaaaiiiiiins_task: + id: 4973 + format: boolean + persist: true +# Lumbridge/Draynor Medium +steel_justice_task: + id: 4997 + format: boolean + persist: true +ease_of_access_task: + id: 4998 + format: boolean + persist: true +everybody_loves_coal_task: + id: 4992 + format: boolean + persist: true +weeping_willow_task: + id: 4995 + format: boolean + persist: true +willow_the_wisp_of_smoke_task: + id: 4999 + format: boolean + persist: true +a_meal_fit_for_a_duke_task: + id: 4993 + format: boolean + persist: true +always_be_prepared_task: + id: 4996 + format: boolean + persist: true +hi_ho_silver_task: + id: 5001 + format: boolean + persist: true +lovely_with_a_squeeze_of_lemon_task: + id: 4994 + format: boolean + persist: true +one_day_you_shall_be_a_fork_task: + id: 5002 + format: boolean + persist: true +made_to_order_task: + id: 5003 + format: boolean + persist: true +wheres_the_beef_task: + id: 5998 + format: boolean + persist: true +# Lumbridge/Draynor Hard +a_body_in_the_sewers_task: + id: 8180 + format: boolean + persist: true +building_up_strength_task: + id: 8181 + format: boolean + persist: true +have_your_cake_and_eat_it_task: + id: 8188 + format: boolean + persist: true +blast_and_hellfire_task: + id: 8191 + format: boolean + persist: true +gods_give_me_strength_task: + id: 8192 + format: boolean + persist: true +not_waving_but_drowning_task: + id: 8193 + format: boolean + persist: true +are_yew_as_fired_up_as_i_am_task: + id: 8194 + format: boolean + persist: true +# Falador Easy +amulet_of_weedspeak_task: + id: 5691 + format: boolean + persist: true +the_good_stuff_task: + id: 5692 + format: boolean + persist: true +chain_store_task: + id: 5705 + format: boolean + persist: true +sir_mitt_task: + id: 5693 + format: boolean + persist: true +family_values_task: + id: 5694 + format: boolean + persist: true +sniffing_out_the_mole_task: + id: 5695 + format: boolean + persist: true +chinchompa_powered_task: + id: 5696 + format: boolean + persist: true +fill_yer_bucket_task: + id: 5697 + format: boolean + persist: true +elementary_medicine_task: + id: 5698 + format: boolean + persist: true +its_not_wabbit_season_task: + id: 5699 + format: boolean + persist: true +stand_and_deliver_task: + id: 5700 + format: boolean + persist: true +making_my_mind_up_task: + id: 5701 + format: boolean + persist: true +mudskip_the_light_fantastic_task: + id: 5703 + format: boolean + persist: true +disarm_and_embark_task: + id: 5704 + format: boolean + persist: true +going_along_with_the_fro_task: + id: 5702 + format: boolean + persist: true +# Falador Medium +fruit_of_the_loom_task: + id: 5706 + format: boolean + persist: true +is_it_so_hard_to_walk_round_task: + id: 5707 + format: boolean + persist: true +climbing_the_walls_task: + id: 5709 + format: boolean + persist: true +its_nothing_personal_task: + id: 5710 + format: boolean + persist: true +ice_the_icy_task: + id: 5711 + format: boolean + persist: true +blinded_with_science_task: + id: 5712 + format: boolean + persist: true +they_have_families_to_feed_task: + id: 5713 + format: boolean + persist: true +stoic_sweetcorn_guardian_task: + id: 5714 + format: boolean + persist: true +look_spiffy_for_tiffy_task: + id: 5717 + format: boolean + persist: true +do_they_come_in_other_colours_task: + id: 5715 + format: boolean + persist: true +these_arent_the_coins_youre_looking_for_task: + id: 5723 + format: boolean + persist: true +fun_for_the_whole_family_task: + id: 5716 + format: boolean + persist: true +# Falador Hard +a_knight_in_the_darkness_task: + id: 5727 + format: boolean + persist: true +child_of_saradomin_task: + id: 5719 + format: boolean + persist: true +mass_production_task: + id: 5720 + format: boolean + persist: true +it_spoiled_my_view_task: + id: 5721 + format: boolean + persist: true +i_heard_you_like_mudskips_task: + id: 5708 + format: boolean + persist: true +it_matches_my_eyes_task: + id: 5718 + format: boolean + persist: true +the_stonemasons_task: + id: 5722 + format: boolean + persist: true +the_mogre_mash_task: + id: 5724 + format: boolean + persist: true +why_oh_wyvern_task: + id: 5725 + format: boolean + persist: true +banned_for_life_task: + id: 5726 + format: boolean + persist: true +# Falador Elite +when_this_caverns_rockin_task: + id: 8114 + format: boolean + persist: true +youd_best_come_a_cookin_task: + id: 8115 + format: boolean + persist: true +concentration_is_key_task: + id: 8116 + format: boolean + persist: true +i_swear_i_heard_it_scream_task: + id: 8117 + format: boolean + persist: true +ive_changed_my_mind_task: + id: 8118 + format: boolean + persist: true +a_string_and_a_flare_task: + id: 8119 + format: boolean + persist: true +altar_ed_state_task: + id: 8120 + format: boolean + persist: true +# Fremennik Easy +bring_the_antipoisons_task: + id: 5648 + format: boolean + persist: true +why_wont_you_die_task: + id: 5649 + format: boolean + persist: true +king_conifer_task: + id: 5650 + format: boolean + persist: true +assaulted_goodies_task: + id: 5651 + format: boolean + persist: true +oxymoron_incarnate_task: + id: 5652 + format: boolean + persist: true +why_did_the_lobster_blush_task: + id: 5653 + format: boolean + persist: true +hunting_the_hunter_task: + id: 5654 + format: boolean + persist: true +peer_off_the_pier_task: + id: 5655 + format: boolean + persist: true +a_familiar_feeling_task: + id: 5656 + format: boolean + persist: true +endangered_species_task: + id: 5657 + format: boolean + persist: true +# Fremennik Medium +fremennik_history_101_task: + id: 5658 + format: boolean + persist: true +cool_story_bro_task: + id: 5659 + format: boolean + persist: true +whos_a_good_boy_task: + id: 5660 + format: boolean + persist: true +only_takes_a_little_vial_task: + id: 5661 + format: boolean + persist: true +you_know_you_want_it_task: + id: 5662 + format: boolean + persist: true +yak_attack_task: + id: 5666 + format: boolean + persist: true +fremmental_task: + id: 5667 + format: boolean + persist: true +fairy_mountaineering_task: + id: 5663 + format: boolean + persist: true +you_really_dont_need_any_more_shoes_task: + id: 5664 + format: boolean + persist: true +big_game_hunter_task: + id: 5665 + format: boolean + persist: true +grand_theft_fish_task: + id: 5668 + format: boolean + persist: true +# Fremennik Hard +defeating_deadly_dagannoths_task: + id: 5669 + format: boolean + persist: true +dress_to_impress_task: + id: 5670 + format: boolean + persist: true +the_graceful_barbarian_task: + id: 5671 + format: boolean + persist: true +runes_on_the_moon_task: + id: 5672 + format: boolean + persist: true +pyre_at_will_task: + id: 5673 + format: boolean + persist: true +fish_fingers_task: + id: 5674 + format: boolean + persist: true +easy_as_pie_task: + id: 5675 + format: boolean + persist: true +how_to_maim_your_dragon_task: + id: 5676 + format: boolean + persist: true +a_periodic_table_task: + id: 5677 + format: boolean + persist: true +# Fremennik Elite +jaws_breaker_task: + id: 8231 + format: boolean + persist: true +limber_lumber_jumper_task: + id: 8232 + format: boolean + persist: true +astronomical_task: + id: 8233 + format: boolean + persist: true +first_stryke_task: + id: 8234 + format: boolean + persist: true +leap_of_faith_task: + id: 8235 + format: boolean + persist: true +no_smoke_without_pyre_task: + id: 8236 + format: boolean + persist: true +this_hasta_work_task: + id: 8237 + format: boolean + persist: true +potting_with_otto_task: + id: 8238 + format: boolean + persist: true +axell_grease_task: + id: 8239 + format: boolean + persist: true +# Ardougne Easy +the_essence_of_magic_task: + id: 6598 + format: boolean + persist: true +yoink_task: + id: 6599 + format: boolean + persist: true +silky_smooth_task: + id: 6600 + format: boolean + persist: true +preaching_to_the_infected_task: + id: 6601 + format: boolean + persist: true +playing_the_waiting_game_task: + id: 6602 + format: boolean + persist: true +gone_fishing_task: + id: 6603 + format: boolean + persist: true +boot_camp_task: + id: 6604 + format: boolean + persist: true +a_cat_is_for_life_task: + id: 6605 + format: boolean + persist: true +creator_and_destroyer_task: + id: 6606 + format: boolean + persist: true +red_revolution_task: + id: 6607 + format: boolean + persist: true +going_on_a_summer_holiday_task: + id: 6608 + format: boolean + persist: true +breaking_and_entering_task: + id: 6609 + format: boolean + persist: true +p_p_p_pick_up_some_prizes_task: + id: 1421 + format: boolean + persist: true +a_gift_from_khazard_task: + id: 6611 + format: boolean + persist: true +party_pooper_task: + id: 6612 + format: boolean + persist: true +vial_deeds_task: + id: 6613 + format: boolean + persist: true +star_seeker_task: + id: 6614 + format: boolean + persist: true +dukes_of_khazard_task: + id: 6615 + format: boolean + persist: true +dont_eat_the_pointy_bit_task: + id: 6616 + format: boolean + persist: true +bargain_hunter_task: + id: 6617 + format: boolean + persist: true +are_you_being_served_task: + id: 6618 + format: boolean + persist: true +no_time_to_lose_task: + id: 6619 + format: boolean + persist: true +theyre_long_and_pointy_task: + id: 6620 + format: boolean + persist: true +# Ardougne Medium +a_visit_to_charlie_task: + id: 6622 + format: boolean + persist: true +i_wonder_what_this_does_task: + id: 6623 + format: boolean + persist: true +sandys_secret_getaway_task: + id: 6624 + format: boolean + persist: true +i_know_a_shortcut_task: + id: 6625 + format: boolean + persist: true +volatile_valuables_task: + id: 6626 + format: boolean + persist: true +what_a_melon_task: + id: 6627 + format: boolean + persist: true +ardougne_express_task: + id: 6650 + format: boolean + persist: true +arriving_in_style_task: + id: 6629 + format: boolean + persist: true +by_the_bucketload_task: + id: 6630 + format: boolean + persist: true +meeting_history_again_task: + id: 6631 + format: boolean + persist: true +fearless_fishing_task: + id: 6632 + format: boolean + persist: true +water_logged_task: + id: 6633 + format: boolean + persist: true +green_fingers_task: + id: 6634 + format: boolean + persist: true +a_natural_thief_task: + id: 6635 + format: boolean + persist: true +the_coal_train_task: + id: 6636 + format: boolean + persist: true +are_you_chicken_task: + id: 6637 + format: boolean + persist: true +# Ardougne Hard +brace_yourself_task: + id: 6639 + format: boolean + persist: true +shadow_boxing_task: + id: 6640 + format: boolean + persist: true +just_like_that_task: + id: 6641 + format: boolean + persist: true +nice_view_task: + id: 6642 + format: boolean + persist: true +youre_the_dirty_rascal_task: + id: 6643 + format: boolean + persist: true +ourania_mania_task: + id: 6644 + format: boolean + persist: true +not_on_my_watch_task: + id: 6645 + format: boolean + persist: true +it_just_croaked_task: + id: 6646 + format: boolean + persist: true +get_your_stinking_hands_off_me_task: + id: 6647 + format: boolean + persist: true +vine_detta_task: + id: 6648 + format: boolean + persist: true +living_on_a_prayer_task: + id: 6649 + format: boolean + persist: true +who_wants_to_watch_the_watchtower_task: + id: 6628 + format: boolean + persist: true +monkey_business_task: + id: 6651 + format: boolean + persist: true +its_my_newt_task: + id: 6652 + format: boolean + persist: true +a_taste_of_the_exotic_task: + id: 6653 + format: boolean + persist: true +blood_bank_withdrawal_task: + id: 6654 + format: boolean + persist: true +artillery_strike_task: + id: 6655 + format: boolean + persist: true +# Ardougne Elite +catching_some_rays_task: + id: 6658 + format: boolean + persist: true +abyssal_valet_task: + id: 6659 + format: boolean + persist: true +you_could_just_knock_task: + id: 6660 + format: boolean + persist: true +honestly_its_not_a_purse_task: + id: 6661 + format: boolean + persist: true +almost_made_in_ardougne_task: + id: 6662 + format: boolean + persist: true +world_map_hide_player_location: + id: 6174 + format: boolean + persist: true +world_map_hide_links: + id: 6175 + format: boolean + persist: true +world_map_hide_labels: + id: 6176 + format: boolean + persist: true +world_map_hide_tooltips: + id: 6177 + format: boolean + persist: true +world_map_list_order: + id: 5367 + format: map + default: categorised + values: + categorised: 0 + traditional: 1 + alphabetical: 2 +show_daemonheim_map: + id: 6090 + format: boolean diff --git a/data/definitions/variables-player.yml b/data/definitions/variables-player.yml index 970e4098d7..a0bf9b9340 100644 --- a/data/definitions/variables-player.yml +++ b/data/definitions/variables-player.yml @@ -104,7 +104,7 @@ cooks_assistant: values: unstarted: 0 started: 1 - completed: 2 + completed: 2 dorics_quest: id: 31 persist: true @@ -127,16 +127,16 @@ rune_mysteries: research_package: 3 package_delivered: 4 research_notes: 5 - completed: 6 + completed: 6 unstable_foundations: id: 281 persist: true format: map - default: complete + default: unstarted values: unstarted: 0 incomplete: 1 - complete: 1000 + completed: 1000 skill_stat_flash: id: 1179 persist: true @@ -177,152 +177,152 @@ unlocked_music_0: id: 20 persist: true format: bitwise - values: [adventure, al_kharid, alone, ambient_jungle, arabian, arabian_2, arabian_3, arabique, army_of_darkness, arrival, attack_1, attack_2, attack_3, attack_4, attack_5, attack_6, attention, autumn_voyage, background, ballad_of_enchantment, baroque, beyond, big_chords, book_of_spells, camelot, cave_background, cavern, chain_of_command, crystal_cave, crystal_sword, dangerous, dark] + values: [ adventure, al_kharid, alone, ambient_jungle, arabian, arabian_2, arabian_3, arabique, army_of_darkness, arrival, attack_1, attack_2, attack_3, attack_4, attack_5, attack_6, attention, autumn_voyage, background, ballad_of_enchantment, baroque, beyond, big_chords, book_of_spells, camelot, cave_background, cavern, chain_of_command, crystal_cave, crystal_sword, dangerous, dark ] unlocked_music_1: id: 21 persist: true format: bitwise - values: [deep_wildy, desert_voyage, doorways, dream, dunjun, egypt, emotion, emperor, expanse, expecting, expedition, faerie, fanfare, fanfare_3, fishing, flute_salad, forever, gaol, garden, gnome_king, dwarf_theme, gnome_village, gnome_village_2, goblin_village, gnomeball, greatness, harmony, high_seas, horizon, iban, in_the_manor, inspiration] + values: [ deep_wildy, desert_voyage, doorways, dream, dunjun, egypt, emotion, emperor, expanse, expecting, expedition, faerie, fanfare, fanfare_3, fishing, flute_salad, forever, gaol, garden, gnome_king, dwarf_theme, gnome_village, gnome_village_2, goblin_village, gnomeball, greatness, harmony, high_seas, horizon, iban, in_the_manor, inspiration ] unlocked_music_2: id: 22 persist: true format: bitwise - values: [intrepid, jolly_r, jungle_island, jungly_1, jungly_2, jungly_3, knightly, lasting, legion, lightness, lightwalk, long_ago, long_way_home, lullaby, mage_arena, magic_dance, magical_journey, march, medieval, mellow, miles_away, miracle_dance, monarch_waltz, moody, neverland, newbie_melody, nightfall, oriental, overture, parade, quest, regal] + values: [ intrepid, jolly_r, jungle_island, jungly_1, jungly_2, jungly_3, knightly, lasting, legion, lightness, lightwalk, long_ago, long_way_home, lullaby, mage_arena, magic_dance, magical_journey, march, medieval, mellow, miles_away, miracle_dance, monarch_waltz, moody, neverland, newbie_melody, nightfall, oriental, overture, parade, quest, regal ] unlocked_music_3: id: 23 persist: true format: bitwise - values: [reggae, reggae_2, riverside, royale, rune_essence, sad_meadow, scape_cave, scape_original, scape_sad, scape_wild, sea_shanty, sea_shanty_2, serenade, serene, shine, soundscape, spirit, splendour, spooky, spooky_jungle, starlight, start, still_night, talking_forest, the_desert, the_shadow, the_tower, theme, trawler, trawler_minor, tree_spirits, tribal_background] + values: [ reggae, reggae_2, riverside, royale, rune_essence, sad_meadow, scape_cave, scape_original, scape_sad, scape_wild, sea_shanty, sea_shanty_2, serenade, serene, shine, soundscape, spirit, splendour, spooky, spooky_jungle, starlight, start, still_night, talking_forest, the_desert, the_shadow, the_tower, theme, trawler, trawler_minor, tree_spirits, tribal_background ] unlocked_music_4: id: 24 persist: true format: bitwise - values: [tribal, tribal_2, trinity, troubled, underground, unknown_land, underground_pass, upcoming, venture, vision, voodoo_cult, voyage, wander, waterfall, wilderness, wilderness_2, wilderness_3, witching, wonder, wonderous, workshop, lonesome, scape_main, ground_scape, scape_scared, scape_santa, land_of_snow, shaping_up, exam_conditions, roots_and_flutes, incarceration, scape_soft] + values: [ tribal, tribal_2, trinity, troubled, underground, unknown_land, underground_pass, upcoming, venture, vision, voodoo_cult, voyage, wander, waterfall, wilderness, wilderness_2, wilderness_3, witching, wonder, wonderous, workshop, lonesome, scape_main, ground_scape, scape_scared, scape_santa, land_of_snow, shaping_up, exam_conditions, roots_and_flutes, incarceration, scape_soft ] unlocked_music_5: id: 25 persist: true format: bitwise - values: [shining, yesteryear, fanfare_2, tomorrow, duel_arena, ice_melody, wild_isle, harmony_2, venture_2, landlubber, undercurrent, nomad, zealot, cellar_song, heart_and_mind, close_quarters, escape, grumpy, chompy_hunt, twilight, morytania, dead_quiet, village, bone_dance, mausoleum, forbidden, cursed, understanding, principality, tremble, kingdom, hermit] + values: [ shining, yesteryear, fanfare_2, tomorrow, duel_arena, ice_melody, wild_isle, harmony_2, venture_2, landlubber, undercurrent, nomad, zealot, cellar_song, heart_and_mind, close_quarters, escape, grumpy, chompy_hunt, twilight, morytania, dead_quiet, village, bone_dance, mausoleum, forbidden, cursed, understanding, principality, tremble, kingdom, hermit ] unlocked_music_6: id: 298 persist: true format: bitwise - values: [la_mort, stagnant, breeze, stratosphere, time_out, natural, grotto, waterlogged, artistry, aztec, elven_mist, forest, lost_soul, meridian, woodland, overpass, contest, sojourn, crystal_castle, marzipan, insect_queen, mad_eadgar, bandit_camp, sunburn, bone_dry, competition, spooky_2, everywhere, exposed, well_of_voyage, haunted_mine, righteousness] + values: [ la_mort, stagnant, breeze, stratosphere, time_out, natural, grotto, waterlogged, artistry, aztec, elven_mist, forest, lost_soul, meridian, woodland, overpass, contest, sojourn, crystal_castle, marzipan, insect_queen, mad_eadgar, bandit_camp, sunburn, bone_dry, competition, spooky_2, everywhere, exposed, well_of_voyage, haunted_mine, righteousness ] unlocked_music_7: id: 311 persist: true format: bitwise - values: [deep_down, chamber, miscellania, etcetera, shadowland, lair, deadlands, rellekka, saga, borderland, stranded, legend, frostbite, warrior, technology, monkey_madness, anywhere, marooned, island_life, temple, suspicious, showdown, find_my_way, castle_wars, melodrama, ready_for_battle, stillness, lighthouse, goblin_game, out_of_the_deep, hell's_bells, the_navigator] + values: [ deep_down, chamber, miscellania, etcetera, shadowland, lair, deadlands, rellekka, saga, borderland, stranded, legend, frostbite, warrior, technology, monkey_madness, anywhere, marooned, island_life, temple, suspicious, showdown, find_my_way, castle_wars, melodrama, ready_for_battle, stillness, lighthouse, goblin_game, out_of_the_deep, hell's_bells, the_navigator ] unlocked_music_8: id: 346 persist: true format: bitwise - values: [wildwood, barbarianism, complication, down_to_earth, courage, superstition, pirates_of_peril, dangerous_road, romancing_the_crone, faithless, tiptoe, the_terrible_tower, masquerade, the_slayer, body_parts, fenkenstrain's_refrain, monster_melee, fruits_de_mer, barking_mad, dynasty, shipwrecked, phasmatys, the_other_side, settlement, cave_of_beasts, dragontooth_island, scarab, sarcophagus, down_below, 7th_realm, karamja_jam, pathways] + values: [ wildwood, barbarianism, complication, down_to_earth, courage, superstition, pirates_of_peril, dangerous_road, romancing_the_crone, faithless, tiptoe, the_terrible_tower, masquerade, the_slayer, body_parts, fenkenstrain's_refrain, monster_melee, fruits_de_mer, barking_mad, dynasty, shipwrecked, phasmatys, the_other_side, settlement, cave_of_beasts, dragontooth_island, scarab, sarcophagus, down_below, 7th_realm, karamja_jam, pathways ] unlocked_music_9: id: 414 persist: true format: bitwise - values: [eagle_peak, time_to_mine, in_between, claustrophobia, far_away, fight_or_flight, temple_of_light, the_golem, forgotten, throne_of_the_demon, dance_of_the_undead, dangerous_way, city_of_the_dead, hypnotized, sphinx, mirage, cave_of_the_goblins, bish_bash_bosh, zogre_dance, path_of_peril, wayward, tale_of_keldagrim, land_of_the_dwarves, tears_of_guthix, romper_chomper, the_rogues'_den, the_far_side, the_lost_melody, evil_bob's_island, into_the_abyss, the_quiz_master, the_power_of_tears] + values: [ eagle_peak, time_to_mine, in_between, claustrophobia, far_away, fight_or_flight, temple_of_light, the_golem, forgotten, throne_of_the_demon, dance_of_the_undead, dangerous_way, city_of_the_dead, hypnotized, sphinx, mirage, cave_of_the_goblins, bish_bash_bosh, zogre_dance, path_of_peril, wayward, tale_of_keldagrim, land_of_the_dwarves, tears_of_guthix, romper_chomper, the_rogues'_den, the_far_side, the_lost_melody, evil_bob's_island, into_the_abyss, the_quiz_master, the_power_of_tears ] unlocked_music_10: id: 464 persist: true format: bitwise - values: [320, pheasant_peasant, the_lost_tribe, corporal_punishment, the_chosen, have_a_blast, forgettable_melody, right_on_track, over_to_nardah, the_monsters_below, the_desolate_isle, spirits_of_elid, the_genie, desert_heat, fire_and_brimstone, in_the_pits, frogland, strange_place, brew_hoo_hoo, tz_haar!, wild_side, dead_can_dance, the_cellar_dwellers, jungle_troubles, catch_me_if_you_can, rat_a_tat_tat, the_noble_rodent, bubble_and_squeak, sarim's_vermin, rat_hunt, homescape, aye_car_rum_ba] + values: [ 320, pheasant_peasant, the_lost_tribe, corporal_punishment, the_chosen, have_a_blast, forgettable_melody, right_on_track, over_to_nardah, the_monsters_below, the_desolate_isle, spirits_of_elid, the_genie, desert_heat, fire_and_brimstone, in_the_pits, frogland, strange_place, brew_hoo_hoo, tz_haar!, wild_side, dead_can_dance, the_cellar_dwellers, jungle_troubles, catch_me_if_you_can, rat_a_tat_tat, the_noble_rodent, bubble_and_squeak, sarim's_vermin, rat_hunt, homescape, aye_car_rum_ba ] unlocked_music_11: id: 598 persist: true format: bitwise - values: [blistering_barnacles, distant_land, fangs_for_the_memory, pharaoh's_tomb, land_down_under, meddling_kids, corridors_of_power, slither_and_thither, in_the_clink, mudskipper_melody, subterranea, incantation, grip_of_the_talon, dagannoth_dawn, xenophobe, title_fight, victory_is_mine, woe_of_the_wyvern, in_the_brine, diango's_little_helpers, roll_the_bones, mind_over_matter, golden_touch, 375, the_enchanter, scape_hunter, making_waves, cabin_fever, last_stand, lament, poles_apart, scarabaeoidea] + values: [ blistering_barnacles, distant_land, fangs_for_the_memory, pharaoh's_tomb, land_down_under, meddling_kids, corridors_of_power, slither_and_thither, in_the_clink, mudskipper_melody, subterranea, incantation, grip_of_the_talon, dagannoth_dawn, xenophobe, title_fight, victory_is_mine, woe_of_the_wyvern, in_the_brine, diango's_little_helpers, roll_the_bones, mind_over_matter, golden_touch, 375, the_enchanter, scape_hunter, making_waves, cabin_fever, last_stand, lament, poles_apart, scarabaeoidea ] unlocked_music_12: id: 662 persist: true format: bitwise - values: [jungle_hunt, home_sweet_home, joy_of_the_hunt, dogs_of_war, food_for_thought, malady, dance_of_death, wrath_and_ruin, storm_brew, the_mad_mole, davy_jones's_locker, chickened_out, hot_'n'_bothered, mastermindless, too_many_cooks, chef_surprize, null_and_void, pest_control, tomb_raider, no_way_out, method_of_madness, fear_and_loathing, funny_bunnies, assault_and_battery, the_depths, distillery_hilarity, trouble_brewing, head_to_head, pinball_wizard, beetle_juice, back_to_life, labyrinth] + values: [ jungle_hunt, home_sweet_home, joy_of_the_hunt, dogs_of_war, food_for_thought, malady, dance_of_death, wrath_and_ruin, storm_brew, the_mad_mole, davy_jones's_locker, chickened_out, hot_'n'_bothered, mastermindless, too_many_cooks, chef_surprize, null_and_void, pest_control, tomb_raider, no_way_out, method_of_madness, fear_and_loathing, funny_bunnies, assault_and_battery, the_depths, distillery_hilarity, trouble_brewing, head_to_head, pinball_wizard, beetle_juice, back_to_life, labyrinth ] unlocked_music_13: id: 721 persist: true format: bitwise - values: [safety_in_numbers, everlasting_fire, waking_dream, dreamstate, the_lunar_isle, isle_of_everywhere, way_of_the_enchanter, warriors'_guild, life's_a_beach!, on_the_wing, little_cave_of_horrors, the_mollusc_menace, the_galleon, h_a_m__fisted, lament_of_meiyerditch, sigmund's_showdown, the_last_shanty, night_of_the_vampyre, we_are_the_fairies, dimension_x, all's_fairy_in_love_and_war, major_miner, jester_minute, norse_code, volcanic_vikings, island_of_the_trolls, pirates_of_penance, brimstail's_scales, my_arm's_journey, slug_a_bug_ball, prime_time, rising_damp] + values: [ safety_in_numbers, everlasting_fire, waking_dream, dreamstate, the_lunar_isle, isle_of_everywhere, way_of_the_enchanter, warriors'_guild, life's_a_beach!, on_the_wing, little_cave_of_horrors, the_mollusc_menace, the_galleon, h_a_m__fisted, lament_of_meiyerditch, sigmund's_showdown, the_last_shanty, night_of_the_vampyre, we_are_the_fairies, dimension_x, all's_fairy_in_love_and_war, major_miner, jester_minute, norse_code, volcanic_vikings, island_of_the_trolls, pirates_of_penance, brimstail's_scales, my_arm's_journey, slug_a_bug_ball, prime_time, rising_damp ] unlocked_music_14: id: 906 persist: true format: bitwise - values: [where_eagles_lair, ogre_the_top, work_work_work, magic_magic_magic, mutant_medley, dorgeshuun_city, dorgeshuun_deep, floating_free, roc_and_roll, high_spirits, looking_back, jungle_island_xmas, sea_shanty_xmas, jungle_bells, garden_of_summer, garden_of_spring, garden_of_winter, garden_of_autumn, have_an_ice_day, zombiism, creature_cruelty, alternative_root, espionage, undead_dungeon, slice_of_station, barb_wire, impetuous, easter_jig, ham_attack, slice_of_silent_movie, ham_and_seek, venomous] + values: [ where_eagles_lair, ogre_the_top, work_work_work, magic_magic_magic, mutant_medley, dorgeshuun_city, dorgeshuun_deep, floating_free, roc_and_roll, high_spirits, looking_back, jungle_island_xmas, sea_shanty_xmas, jungle_bells, garden_of_summer, garden_of_spring, garden_of_winter, garden_of_autumn, have_an_ice_day, zombiism, creature_cruelty, alternative_root, espionage, undead_dungeon, slice_of_station, barb_wire, impetuous, easter_jig, ham_attack, slice_of_silent_movie, ham_and_seek, venomous ] unlocked_music_15: id: 1009 persist: true format: bitwise - values: [mouse_trap, fe_fi_fo_fum, school's_out, inadequacy, illusive, everlasting, untouchable, down_and_out, on_the_up, melzar's_maze, zamorak_zoo, strength_of_saradomin, bandos_battalion, armadyl_alliance, armageddon, storeroom_shuffle, the_longramble_scramble, waste_defaced, knightmare, lore_and_order, terrorbird_tussle, altar_ego, bolrie's_diary, healin'_feelin', animal_apogee, temple_of_tribes, catacombs_and_tombs, zanik's_theme, dusk_in_yu'biusk, grimly_fiendish, tune_from_the_dune, spa_bizarre] + values: [ mouse_trap, fe_fi_fo_fum, school's_out, inadequacy, illusive, everlasting, untouchable, down_and_out, on_the_up, melzar's_maze, zamorak_zoo, strength_of_saradomin, bandos_battalion, armadyl_alliance, armageddon, storeroom_shuffle, the_longramble_scramble, waste_defaced, knightmare, lore_and_order, terrorbird_tussle, altar_ego, bolrie's_diary, healin'_feelin', animal_apogee, temple_of_tribes, catacombs_and_tombs, zanik's_theme, dusk_in_yu'biusk, grimly_fiendish, tune_from_the_dune, spa_bizarre ] unlocked_music_16: id: 1104 persist: true format: bitwise - values: [copris_lunaris, narnode's_theme, tournament!, clan_wars, charmin'_farmin', bounty_hunter_level_1, bounty_hunter_level_2, bounty_hunter_level_3, the_adventurer, creepy, a_new_menace, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, brain_battle, 534, 535, surok's_theme, 537, 538, 539, 540, 541, 542, 543] + values: [ copris_lunaris, narnode's_theme, tournament!, clan_wars, charmin'_farmin', bounty_hunter_level_1, bounty_hunter_level_2, bounty_hunter_level_3, the_adventurer, creepy, a_new_menace, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, brain_battle, 534, 535, surok's_theme, 537, 538, 539, 540, 541, 542, 543 ] unlocked_music_17: id: 1136 persist: true format: bitwise - values: [544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, the_trade_parade, jungle_community, 557, icy_trouble_ahead, icy_a_worried_gnome, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575] + values: [ 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, the_trade_parade, jungle_community, 557, icy_trouble_ahead, icy_a_worried_gnome, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575 ] unlocked_music_18: id: 1180 persist: true format: bitwise - values: [576, distant_land_2, castle_wars_2, pest_control_2, competition_2, poles_apart_2, far_away_2, hell's_bells_2, bloodbath, the_route_of_all_evil, the_route_of_the_problem, the_wrong_path, the_columbarium, the_terrible_tunnels, the_terrible_caverns, dillo_gence_is_key, arma_gonna_get_you, tok_tz_ket_ek_mack, jailbird, bittersweet_bunny, something_fishy, under_the_sand, desert_smoke, a_pirate's_life_for_me, conspiracy:_part_1, conspiracy:_part_2, scape_summon, guthix's_hunter, waiting_for_the_hunt, cool_for_ali_cats, second_vision, undead_army] + values: [ 576, distant_land_2, castle_wars_2, pest_control_2, competition_2, poles_apart_2, far_away_2, hell's_bells_2, bloodbath, the_route_of_all_evil, the_route_of_the_problem, the_wrong_path, the_columbarium, the_terrible_tunnels, the_terrible_caverns, dillo_gence_is_key, arma_gonna_get_you, tok_tz_ket_ek_mack, jailbird, bittersweet_bunny, something_fishy, under_the_sand, desert_smoke, a_pirate's_life_for_me, conspiracy:_part_1, conspiracy:_part_2, scape_summon, guthix's_hunter, waiting_for_the_hunt, cool_for_ali_cats, second_vision, undead_army ] unlocked_music_19: id: 1202 persist: true format: bitwise - values: [zombie_invasion, the_ruins_of_camdozaal, dream_theatre, the_mentor, slain_to_waste, ardougne_ago, sarah's_lullaby, shining_spirit, troubled_spirit, bane_of_summer, the_vacant_abyss, historic_memories, stealing_creation, circus, dangerous_logic, black_of_knight, the_art_of_hocus_pocus, magic_and_mystery, the_sound_of_guthix, 627, temple_desecrated, command_centre, the_phoenix, mobilising_armies, the_evil_within, 633, the_dance_of_the_snow_queen, cavernous_mythology, winter_funfare, waiting_for_battle, lair_of_kang_admi, frost_fight] + values: [ zombie_invasion, the_ruins_of_camdozaal, dream_theatre, the_mentor, slain_to_waste, ardougne_ago, sarah's_lullaby, shining_spirit, troubled_spirit, bane_of_summer, the_vacant_abyss, historic_memories, stealing_creation, circus, dangerous_logic, black_of_knight, the_art_of_hocus_pocus, magic_and_mystery, the_sound_of_guthix, 627, temple_desecrated, command_centre, the_phoenix, mobilising_armies, the_evil_within, 633, the_dance_of_the_snow_queen, cavernous_mythology, winter_funfare, waiting_for_battle, lair_of_kang_admi, frost_fight ] unlocked_music_20: id: 1381 persist: true format: bitwise - values: [glorious_recallation, glorious_recallation_2, glorious_recallation_2, the_adventurers_re_united!, the_plundered_tomb, ancestral_wisdom, nial's_widow, the_muspah's_tomb, lamistard's_labyrinth, the_heist, snack_attack, 651, soul_wars, the_waiting_game, rest_for_the_weary, trees_aren't_your_friends, the_throne_of_bandos, penguin_possible, don't_panic_zanik, demise_of_the_dorgeshuun, the_chosen_commander, the_pengmersible, desert_island_bear, 663, 664, ice_day_for_penguins, face_off, 667, 668, 669, 670, 671] + values: [ glorious_recallation, glorious_recallation_2, glorious_recallation_2, the_adventurers_re_united!, the_plundered_tomb, ancestral_wisdom, nial's_widow, the_muspah's_tomb, lamistard's_labyrinth, the_heist, snack_attack, 651, soul_wars, the_waiting_game, rest_for_the_weary, trees_aren't_your_friends, the_throne_of_bandos, penguin_possible, don't_panic_zanik, demise_of_the_dorgeshuun, the_chosen_commander, the_pengmersible, desert_island_bear, 663, 664, ice_day_for_penguins, face_off, 667, 668, 669, 670, 671 ] unlocked_music_21: id: 1394 persist: true format: bitwise - values: [672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, zaros_stirs, the_horn_of_chill, godslayer, but_we_can_fight, lazy_wabbit, hare_brained_machines, 697, 698, 699, 700, 701, 702, 703] + values: [ 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, zaros_stirs, the_horn_of_chill, godslayer, but_we_can_fight, lazy_wabbit, hare_brained_machines, 697, 698, 699, 700, 701, 702, 703 ] unlocked_music_22: id: 1434 persist: true format: bitwise - values: [704, 705, 706, eruption, i'm_counting_on_you, kharidian_nights, living_rock, exhibit_'a', fight_of_the_dwarves, 713, 714, final_destination, elven_seed, scape_theme, honkytonky_newbie_melody, honkytonky_harmony, trick_or_treat, itsy_bitsy, poison_dreams, honkytonky_medieval, jaws_of_the_dagannoth, the_duke, the_fallen_hero, 727, honkytonky_sea_shanty, honkytonky_parade, maiasaura, 731, 732, root_canal, desolate_ruins, smorgasbord] + values: [ 704, 705, 706, eruption, i'm_counting_on_you, kharidian_nights, living_rock, exhibit_'a', fight_of_the_dwarves, 713, 714, final_destination, elven_seed, scape_theme, honkytonky_newbie_melody, honkytonky_harmony, trick_or_treat, itsy_bitsy, poison_dreams, honkytonky_medieval, jaws_of_the_dagannoth, the_duke, the_fallen_hero, 727, honkytonky_sea_shanty, honkytonky_parade, maiasaura, 731, 732, root_canal, desolate_ruins, smorgasbord ] unlocked_music_23: id: 1596 persist: true format: bitwise - values: [silent_knight, ghost_of_christmas_presents, 738, battle_of_souls, these_stones, a_familiar_feeling, dead_and_buried, the_pact, freshwater, saltwater, stillwater, an_easter_united, 748, thieves'_guild_i, thieves'_guild_ii, thieves'_guild_iii, thieves'_guild_iv, body_talk, 754, love_lost, love_and_hate, love_bites, 758, castle_warz, 760, mindful, void_knights'_theme, lortnoc_tsep, 764, judge_and_jury, born_to_do_this, 767] + values: [ silent_knight, ghost_of_christmas_presents, 738, battle_of_souls, these_stones, a_familiar_feeling, dead_and_buried, the_pact, freshwater, saltwater, stillwater, an_easter_united, 748, thieves'_guild_i, thieves'_guild_ii, thieves'_guild_iii, thieves'_guild_iv, body_talk, 754, love_lost, love_and_hate, love_bites, 758, castle_warz, 760, mindful, void_knights'_theme, lortnoc_tsep, 764, judge_and_jury, born_to_do_this, 767 ] unlocked_music_24: id: 1618 persist: true format: bitwise - values: [768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, glacialis_i, glacialis_ii, glacialis_iii, glacialis_iv, glacialis_v, glacialis_vi, glacialis_vii, glacialis_viii, glacialis_ix, glacialis_x, astea_frostweb, to'kash_the_bloodchiller, icy_bones, luminescent_icefiend, gluttonous_behemoth, plane_freezer_lakhrahnaz] + values: [ 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, glacialis_i, glacialis_ii, glacialis_iii, glacialis_iv, glacialis_v, glacialis_vi, glacialis_vii, glacialis_viii, glacialis_ix, glacialis_x, astea_frostweb, to'kash_the_bloodchiller, icy_bones, luminescent_icefiend, gluttonous_behemoth, plane_freezer_lakhrahnaz ] unlocked_music_25: id: 1619 persist: true format: bitwise - values: [800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, desolo_i, desolo_ii, desolo_iii, desolo_iv, desolo_v, desolo_vi, desolo_vii, desolo_viii, desolo_ix, desolo_x, bal'lak_the_pummeller, bulwark_beast, hobgoblin_geomancer, shadow_forger_ihlakhizan, unholy_cursebearer, divine_skinweaver] + values: [ 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, desolo_i, desolo_ii, desolo_iii, desolo_iv, desolo_v, desolo_vi, desolo_vii, desolo_viii, desolo_ix, desolo_x, bal'lak_the_pummeller, bulwark_beast, hobgoblin_geomancer, shadow_forger_ihlakhizan, unholy_cursebearer, divine_skinweaver ] unlocked_music_26: id: 1620 persist: true format: bitwise - values: [832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, adorno_i, adorno_ii, adorno_iii, adorno_iv, adorno_v, adorno_vi, adorno_vii, adorno_viii, adorno_ix, adorno_x, har'lakk_the_riftsplitter, lexicus_runewright, night_gazer_khighorahk, sagittare, rammernaut, stomp] + values: [ 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, adorno_i, adorno_ii, adorno_iii, adorno_iv, adorno_v, adorno_vi, adorno_vii, adorno_viii, adorno_ix, adorno_x, har'lakk_the_riftsplitter, lexicus_runewright, night_gazer_khighorahk, sagittare, rammernaut, stomp ] unlocked_music_28: id: 1864 persist: true format: bitwise - values: [occulo_i, occulo_ii, occulo_iii, occulo_iv, occulo_v, occulo_vi, occulo_vii, occulo_viii, occulo_ix, occulo_x, necrolord, gravecreeper, skeletal_trio, yk'lagor_the_thunderous, runed_behemoth, flesh_spoiler_haasghenahk, torqueo_i, torqueo_ii, torqueo_iii, torqueo_iv, torqueo_v, torqueo_vi, torqueo_vii, torqueo_viii, torqueo_ix, torqueo_x, blink, kal'ger_the_warmonger, hope_devourer, warped_gulega, dreadnaught, world_gorger_shukarhazh] + values: [ occulo_i, occulo_ii, occulo_iii, occulo_iv, occulo_v, occulo_vi, occulo_vii, occulo_viii, occulo_ix, occulo_x, necrolord, gravecreeper, skeletal_trio, yk'lagor_the_thunderous, runed_behemoth, flesh_spoiler_haasghenahk, torqueo_i, torqueo_ii, torqueo_iii, torqueo_iv, torqueo_v, torqueo_vi, torqueo_vii, torqueo_viii, torqueo_ix, torqueo_x, blink, kal'ger_the_warmonger, hope_devourer, warped_gulega, dreadnaught, world_gorger_shukarhazh ] unlocked_music_29: id: 1865 persist: true format: bitwise - values: [out_of_control, chain_reaction, all_for_the_pest, destiny, unavoidable_conflict, right_of_conquest, 934, yk'lagor_the_thunderous_2, gunnarsgrunn, 937, 938, halloween_party, black_zabeth:_live!, black_zabeth, in_security, give_it_your_pest_shot, 944, the_void_stares_back, precarious_void, mystery_revealed, who_are_we_to_judge, 949, 950, 951, 952, christmas_caverns, seasonal_sports, the_task_at_hand, monkey_see_monkey_do, monkey_see_monkey_do_2, simian_scuffle, 959] + values: [ out_of_control, chain_reaction, all_for_the_pest, destiny, unavoidable_conflict, right_of_conquest, 934, yk'lagor_the_thunderous_2, gunnarsgrunn, 937, 938, halloween_party, black_zabeth:_live!, black_zabeth, in_security, give_it_your_pest_shot, 944, the_void_stares_back, precarious_void, mystery_revealed, who_are_we_to_judge, 949, 950, 951, 952, christmas_caverns, seasonal_sports, the_task_at_hand, monkey_see_monkey_do, monkey_see_monkey_do_2, simian_scuffle, 959 ] unlocked_music_30: id: 2019 persist: true format: bitwise - values: [960, 961, monkey_see_monkey_do_2, rocky_rescue, go_with_the_flow, the_records_chamber, corporate_callousness, 967, 968, colonel_grimsson, only_a_king, 971, zaros_zeitgeist, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991] + values: [ 960, 961, monkey_see_monkey_do_2, rocky_rescue, go_with_the_flow, the_records_chamber, corporate_callousness, 967, 968, colonel_grimsson, only_a_king, 971, zaros_zeitgeist, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991 ] autocast: id: 108 format: int @@ -405,4 +405,214 @@ enter_the_abyss: id: 492 persist: true format: list - values: [ unstarted, started, scrying, orb_inspect, completed ] \ No newline at end of file + values: [ unstarted, started, scrying, orb_inspect, completed ] +plague_city: + id: 165 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 29 +biohazard: + id: 68 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 16 +gertrudes_cat: + id: 180 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 6 +monks_friend: + id: 30 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 80 +watchtower: + id: 212 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 14 +sea_slug: + id: 159 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 12 +legends_quest: + id: 139 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 75 +monkey_madness: + id: 365 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 9 +restless_ghost: + id: 107 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 5 +dragon_slayer: + id: 176 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + received_shield: 1 + completed: 10 +fremennik_trials: + id: 347 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 10 +bar_crawl_miniquest: + id: 76 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 6 +shilo_village: + id: 116 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 15 +jungle_potion: + id: 175 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 12 +tai_bwo_wannai_trio: + id: 320 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 6 +grand_tree: + id: 150 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 160 +murder_mystery: + id: 192 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 2 +scorpion_catcher: + id: 76 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 6 +one_small_favour: + id: 416 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 280 +family_crest: + id: 148 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 11 +tree_gnome_village: + id: 111 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 9 +bork_defeated_day: + id: 1199 + format: int + persist: true +priest_in_peril: + id: 302 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 60 +shades_of_mortton: + id: 339 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 85 +prince_ali_rescue: + id: 273 + format: map + persist: true + default: unstarted + values: + unstarted: 0 + completed: 110 +task_reward_items: + id: 1959 + format: bitwise + persist: true + values: [ magic_staff, red_dye ] +stat_advance_selected_skill: + id: 261 + format: int +world_map_marker_custom: + id: 1159 + format: int + persist: true + diff --git a/data/map/areas.yml b/data/map/areas.yml index 93f8a98d3b..0066a426ab 100644 --- a/data/map/areas.yml +++ b/data/map/areas.yml @@ -1,3 +1,11 @@ +lumbridge: + area: + x: [ 3252, 3136, 3136, 3153, 3153, 3156, 3173, 3180, 3201, 3209, 3224, 3227, 3233, 3238, 3247, 3253, 3270, 3270, 3266, 3266, 3265, 3264, 3264, 3265, 3265, 3266, 3266, 3267, 3267, 3266, 3266, 3265, 3265, 3262, 3253, 3253 ] + y: [ 3136, 3136, 3336, 3336, 3346, 3349, 3347, 3347, 3337, 3333, 3333, 3330, 3330, 3334, 3334, 3329, 3329, 3326, 3322, 3272, 3255, 3254, 3247, 3246, 3238, 3237, 3232, 3231, 3211, 3210, 3208, 3207, 3202, 3200, 3175, 3166 ] +draynor: + area: + x: [ 3072, 3135 ] + y: [ 3136, 3391 ] lumbridge_north_trees: area: x: [ 3220, 3234 ] @@ -619,6 +627,12 @@ wizards_tower_multi_area: y: [ 3144, 3176 ] level: 0 tags: [ multi_combat ] +wizards_tower_top_floor: + area: + x: [ 3094, 3125 ] + y: [ 3144, 3176 ] + level: 2 + tags: [ multi_combat ] draynor_village_multi_area: area: x: [ 3112, 3136, 3136, 3104, 3104, 3112 ] @@ -1020,4 +1034,16 @@ sedridor_return: essence_mine_teleport: area: x: [ 2898, 2893, 2887, 2894, 2898, 2905, 2905, 2902, 2892, 2884, 2893, 2900, 2900, 2910, 2913, 2919, 2920, 2920, 2932, 2932, 2922, 2914, 2917, 2925, 2935, 2935, 2928, 2921, 2923, 2915, 2906, 2900, 2900 ] - y: [ 4807, 4807, 4814, 4821, 4821, 4827, 4836, 4841, 4841, 4849, 4857, 4852, 4844, 4838, 4838, 4842, 4848, 4856, 4856, 4843, 4843, 4835, 4825, 4820, 4820, 4815, 4808, 4813, 4817, 4825, 4825, 4817, 4808 ] \ No newline at end of file + y: [ 4807, 4807, 4814, 4821, 4821, 4827, 4836, 4841, 4841, 4849, 4857, 4852, 4844, 4838, 4838, 4842, 4848, 4856, 4856, 4843, 4843, 4835, 4825, 4820, 4820, 4815, 4808, 4813, 4817, 4825, 4825, 4817, 4808 ] +freds_farmhouse: + area: + x: [ 3184, 3192 ] + y: [ 3270, 3275 ] +draynor_manor_courtyard: + area: + x: [ 3084, 3084, 3129, 3129, 3124, 3115, 3114, 3105, 3104, 3089 ] + y: [ 3335, 3353, 3353, 3335, 3330, 3330, 3331, 3331, 3330, 3330 ] +draynor_village_market: + area: + x: [ 3074, 3074, 3082, 3082, 3086, 3086 ] + y: [ 3246, 3257, 3257, 3255, 3255, 3246 ] diff --git a/data/map/teleports.yml b/data/map/teleports.yml index 3cc0d9b508..0c1ad7b2f8 100644 --- a/data/map/teleports.yml +++ b/data/map/teleports.yml @@ -2716,7 +2716,7 @@ x: -1 y: 1 level: 1 -- id: 12537 +- id: wizards_tower_staircase option: Climb-down tile: x: 3103 @@ -2726,7 +2726,7 @@ x: 1 y: -1 level: -1 -- id: 12537 +- id: wizards_tower_staircase option: Climb-up tile: x: 3103 @@ -3660,7 +3660,7 @@ level: 1 delta: level: -1 -- id: 36771 +- id: lumbridge_castle_ladder option: Climb-up tile: x: 3207 diff --git a/data/spawns/drops.yml b/data/spawns/drops.yml index a297a77645..da5f3fc81c 100644 --- a/data/spawns/drops.yml +++ b/data/spawns/drops.yml @@ -1694,5 +1694,5 @@ monk_of_zamorak_drop_table: - id: bones - roll: 20 drops: - - id: zamorak_monk_bottom - - id: zamorak_monk_top \ No newline at end of file + - id: zamorak_robe_bottom + - id: zamorak_robe_top \ No newline at end of file diff --git a/data/spawns/npc-spawns.yml b/data/spawns/npc-spawns.yml index 59c1e962a3..e0796491fc 100644 --- a/data/spawns/npc-spawns.yml +++ b/data/spawns/npc-spawns.yml @@ -2053,6 +2053,7 @@ - { id: goblin_light_grey_hat, x: 3258, y: 3220 } - { id: goblin_light_brown_mohawk, x: 3260, y: 3237 } - { id: goblin_light_topless_spiked, x: 3260, y: 3240 } +- { id: explorer_jack, x: 3204, y: 3242 } # 12851 - { id: duck_swim, x: 3235, y: 3265 } - { id: duck_swim, x: 3233, y: 3267 } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt index 0da7658584..c19e693845 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt @@ -91,6 +91,7 @@ val engineModule = module { single(createdAtStart = true) { DropTables().load(itemDefinitions = get()) } // Definitions single(createdAtStart = true) { SoundDefinitions().load() } + single(createdAtStart = true) { QuestDefinitions().load() } single(createdAtStart = true) { RenderEmoteDefinitions().load() } single(createdAtStart = true) { MidiDefinitions().load() } single(createdAtStart = true) { VariableDefinitions().load() } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/EncodeExtensions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/EncodeExtensions.kt index 0e1f3ab309..6e62e901e5 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/client/EncodeExtensions.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/EncodeExtensions.kt @@ -3,6 +3,7 @@ package world.gregs.voidps.engine.client import net.pearx.kasechange.toSnakeCase import world.gregs.voidps.engine.client.ui.chat.Colours import world.gregs.voidps.engine.data.definition.ClientScriptDefinitions +import world.gregs.voidps.engine.data.definition.FontDefinitions import world.gregs.voidps.engine.entity.character.Character import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.chat.ChatType @@ -32,7 +33,10 @@ fun Character.message( return } getOrPut("messages") { FixedSizeQueue(100) }.add(text) - client?.message(Colours.replaceCustomTags(text), type.id, tile, name, name?.toSnakeCase()) + val font = get().get("p12_full") + for (line in font.splitLines(Colours.replaceCustomTags(text), 484)) { + client?.message(line, type.id, tile, name, name?.toSnakeCase()) + } } private class FixedSizeQueue(private val capacity: Int) : LinkedList() { diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/InstructionHandlers.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/InstructionHandlers.kt index 4c20fe36c8..6d8a27d42f 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/InstructionHandlers.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/InstructionHandlers.kt @@ -43,6 +43,7 @@ class InstructionHandlers( private val interactInterfaceItem = InterfaceOnInterfaceOptionHandler(handler) private val interactInterfaceFloorItem = InterfaceOnFloorItemOptionHandler(items, handler) private val walk = WalkHandler() + private val worldMapClick = WorldMapClickHandler() private val finishRegionLoad = FinishRegionLoadHandler() private val executeCommand = ExecuteCommandHandler() private val enterString = EnterStringHandler() @@ -81,6 +82,7 @@ class InstructionHandlers( is ExamineObject -> examineObject.validate(player, instruction) is ChangeDisplayMode -> changeDisplayMode.validate(player, instruction) is Walk -> walk.validate(player, instruction) + is WorldMapClick -> worldMapClick.validate(player, instruction) is FinishRegionLoad -> finishRegionLoad.validate(player, instruction) is ExecuteCommand -> executeCommand.validate(player, instruction) is EnterString -> enterString.validate(player, instruction) diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WalkHandler.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WalkHandler.kt index c418874a1f..5da343c94c 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WalkHandler.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WalkHandler.kt @@ -18,6 +18,9 @@ class WalkHandler : InstructionHandler() { player.clearWatch() player.queue.clearWeak() player.suspension = null + if (instruction.minimap && !player["a_world_in_microcosm_task", false]) { + player["a_world_in_microcosm_task"] = true + } player.walkTo(player.tile.copy(instruction.x, instruction.y)) } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WorldMapClickHandler.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WorldMapClickHandler.kt new file mode 100644 index 0000000000..1c48bd2d61 --- /dev/null +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WorldMapClickHandler.kt @@ -0,0 +1,19 @@ +package world.gregs.voidps.engine.client.instruction.handle + +import world.gregs.voidps.engine.client.instruction.InstructionHandler +import world.gregs.voidps.engine.client.variable.hasClock +import world.gregs.voidps.engine.client.variable.start +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.network.client.instruction.WorldMapClick + +class WorldMapClickHandler : InstructionHandler() { + + override fun validate(player: Player, instruction: WorldMapClick) { + if (player.hasClock("world_map_double_click") && player["previous_world_map_click", 0] == instruction.tile) { + player["world_map_marker_custom"] = instruction.tile + } + player["previous_world_map_click"] = instruction.tile + player.start("world_map_double_click", 1) + } + +} \ No newline at end of file diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/Interfaces.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/Interfaces.kt index 875818bcc4..a838715322 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/Interfaces.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/Interfaces.kt @@ -174,8 +174,9 @@ class Interfaces( } fun sendVisibility(id: String, component: String, visible: Boolean): Boolean { - val comp = definitions.getComponent(id, component) ?: return false - client?.interfaceVisibility(comp["parent", -1], comp.id, !visible) + val componentId = definitions.getComponentId(id, component) ?: return false + val comp = definitions.getComponent(id, componentId) ?: return false + client?.interfaceVisibility(comp["parent", -1], componentId, !visible) return true } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/variable/VariableSet.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/variable/VariableSet.kt index 81e2886c66..765f568df5 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/client/variable/VariableSet.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/variable/VariableSet.kt @@ -15,6 +15,8 @@ data class VariableSet( val from: Any?, val to: Any? ) : Event { + override val notification = true + override val size = 5 override fun parameter(dispatcher: EventDispatcher, index: Int) = when (index) { diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/AreaDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/AreaDefinitions.kt index 48d527ddb9..fedd3e6a46 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/AreaDefinitions.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/AreaDefinitions.kt @@ -42,7 +42,7 @@ class AreaDefinitions( super.set(map, key, ObjectOpenHashSet(value as List), indent, parentMap) } else if (key == "area") { value as Map - val area = Area.fromMap(value, 0) + val area = Area.fromMap(value, 3) super.set(map, key, area, indent, parentMap) } else if (indent == 0) { val area = AreaDefinition.fromMap(key, value as MutableMap) diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/EnumDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/EnumDefinitions.kt index dedf18944c..1e3cd73de5 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/EnumDefinitions.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/EnumDefinitions.kt @@ -22,6 +22,12 @@ class EnumDefinitions( return structs.get(struct)[param] } + fun getStructOrNull(id: String, index: Int, param: String): T? { + val enum = get(id) + val struct = enum.getInt(index) + return structs.getOrNull(struct)?.getOrNull(param) + } + fun getStruct(id: String, index: Int, param: String, default: T): T { val enum = get(id) val struct = enum.getInt(index) diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/QuestDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/QuestDefinitions.kt new file mode 100644 index 0000000000..6a8afbbcbc --- /dev/null +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/QuestDefinitions.kt @@ -0,0 +1,25 @@ +package world.gregs.voidps.engine.data.definition + +import world.gregs.voidps.cache.config.data.QuestDefinition +import world.gregs.voidps.engine.data.yaml.decode +import world.gregs.voidps.engine.get +import world.gregs.voidps.engine.getProperty +import world.gregs.voidps.engine.timedLoad +import world.gregs.yaml.Yaml + +class QuestDefinitions : DefinitionsDecoder { + + override lateinit var definitions: Array + override lateinit var ids: Map + + fun load(yaml: Yaml = get(), path: String = getProperty("questDefinitionsPath")): QuestDefinitions { + timedLoad("quest definition") { + decode(yaml, path) { id, key, _ -> + QuestDefinition(id = id, stringId = key) + } + } + return this + } + + override fun empty() = QuestDefinition.EMPTY +} \ No newline at end of file diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/StructDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/StructDefinitions.kt index b34c59f06c..5692252b43 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/StructDefinitions.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/StructDefinitions.kt @@ -1,9 +1,13 @@ package world.gregs.voidps.engine.data.definition import world.gregs.voidps.cache.config.data.StructDefinition +import world.gregs.voidps.engine.get +import world.gregs.voidps.engine.getProperty +import world.gregs.voidps.engine.timedLoad +import world.gregs.yaml.Yaml /** - * Also known as attribute maps in cs2 + * Also known as AttributeMaps in cs2 */ class StructDefinitions( override var definitions: Array @@ -13,7 +17,10 @@ class StructDefinitions( override fun empty() = StructDefinition.EMPTY - fun load(): StructDefinitions { + fun load(yaml: Yaml = get(), path: String = getProperty("structDefinitionsPath")): StructDefinitions { + timedLoad("struct extra") { + decode(yaml, path) + } return this } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/inv/ItemChanged.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/inv/ItemChanged.kt index 405e12d59a..27d2004b2a 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/inv/ItemChanged.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/inv/ItemChanged.kt @@ -74,6 +74,10 @@ fun itemRemoved(item: String = "*", index: Int? = null, inventory: String = "*", Events.handle("item_change", "*", index ?: "*", inventory, item, "*", "*", handler = handler) } +fun itemReplaced(from: String = "*", to: String = "*", inventory: String = "*", handler: suspend ItemChanged.(Player) -> Unit) { + Events.handle("item_change", to, "*", inventory, from, "*", "*", handler = handler) +} + fun itemChange(inventory: String = "*", slot: EquipSlot, handler: suspend ItemChanged.(Player) -> Unit) { itemChange(inventory, slot.index, handler = handler) } @@ -82,6 +86,10 @@ fun itemChange(inventory: String = "*", index: Int? = null, fromInventory: Strin Events.handle("item_change", "*", index ?: "*", inventory, "*", fromIndex ?: "*", fromInventory, handler = handler) } +fun itemChange(inventory: String = "*", index: Int? = null, fromInventory: String = "*", fromIndex: Int? = null, item: String = "*", handler: suspend ItemChanged.(Player) -> Unit) { + Events.handle("item_change", item, index ?: "*", inventory, "*", fromIndex ?: "*", fromInventory, handler = handler) +} + fun itemChange(vararg inventories: String = arrayOf("*"), handler: suspend ItemChanged.(Player) -> Unit) { for (inventory in inventories) { itemChange(inventory, handler = handler) diff --git a/game/src/main/kotlin/world/gregs/voidps/bot/BotSpawns.kts b/game/src/main/kotlin/world/gregs/voidps/bot/BotSpawns.kts index 20890d55bb..2255c8e9ba 100644 --- a/game/src/main/kotlin/world/gregs/voidps/bot/BotSpawns.kts +++ b/game/src/main/kotlin/world/gregs/voidps/bot/BotSpawns.kts @@ -83,7 +83,7 @@ adminCommand("bot") { } else { val bot = player.initBot() if (content.isNotBlank()) { - player["task"] = content + player["task_bot"] = content } bot.emit(StartBot) } diff --git a/game/src/main/kotlin/world/gregs/voidps/bot/DecisionMaking.kts b/game/src/main/kotlin/world/gregs/voidps/bot/DecisionMaking.kts index 6b4e673679..862c2fb000 100644 --- a/game/src/main/kotlin/world/gregs/voidps/bot/DecisionMaking.kts +++ b/game/src/main/kotlin/world/gregs/voidps/bot/DecisionMaking.kts @@ -19,13 +19,13 @@ val scope = CoroutineScope(Contexts.Game) val logger = InlineLogger("Bot") onEvent { bot -> - if (!bot.contains("task") || bot.contains("task_started")) { + if (!bot.contains("task_bot") || bot.contains("task_started")) { return@onEvent } - val name: String = bot["task"]!! + val name: String = bot["task_bot"]!! val task = tasks.get(name) if (task == null) { - bot.clear("task") + bot.clear("task_bot") } else { assign(bot, task) } @@ -35,8 +35,8 @@ onEvent { players.forEach { player -> if (player.isBot) { val bot: Bot = player["bot"]!! - if (!bot.contains("task")) { - val lastTask: String? = bot["last_task"] + if (!bot.contains("task_bot")) { + val lastTask: String? = bot["last_task_bot"] assign(player, tasks.assign(bot, lastTask)) } player.bot.resume("tick") @@ -48,11 +48,11 @@ fun assign(bot: Player, task: Task) { if (bot["debug", false]) { logger.debug { "Task assigned: ${bot.accountName} - ${task.name}" } } - val last = bot.get("task") + val last = bot.get("task_bot") if (last != null) { - bot["last_task"] = last + bot["last_task_bot"] = last } - bot["task"] = task.name + bot["task_bot"] = task.name bot["task_started"] = true task.spaces-- scope.launch { @@ -61,7 +61,7 @@ fun assign(bot: Player, task: Task) { } catch (t: Throwable) { logger.warn(t) { "Task cancelled for $bot" } } - bot.clear("task") + bot.clear("task_bot") task.spaces++ } } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/AntiqueLamp.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/AntiqueLamp.kts new file mode 100644 index 0000000000..3b3b912e3a --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/AntiqueLamp.kts @@ -0,0 +1,16 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.entity.character.player.skill.exp.exp +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.engine.inv.remove +import world.gregs.voidps.world.interact.dialogue.type.skillLamp +import world.gregs.voidps.world.interact.dialogue.type.statement +import world.gregs.voidps.world.interact.entity.player.equip.inventoryItem + +inventoryItem("Rub", "antique_lamp_easy_lumbridge_tasks", "inventory") { + val skill = skillLamp() + if (player.inventory.remove(slot, item.id)) { + player.exp(skill, 500.0) + statement("Your wish has been granted!
You have been awarded 500 ${skill.name} experience!") + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorerJack.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorerJack.kts new file mode 100644 index 0000000000..c539cc5ea6 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorerJack.kts @@ -0,0 +1,145 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.client.sendScript +import world.gregs.voidps.engine.client.variable.BitwiseValues +import world.gregs.voidps.engine.data.definition.VariableDefinitions +import world.gregs.voidps.engine.entity.World.name +import world.gregs.voidps.engine.entity.character.npc.NPCOption +import world.gregs.voidps.engine.entity.character.npc.npcOperate +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.entity.character.player.chat.inventoryFull +import world.gregs.voidps.engine.inject +import world.gregs.voidps.engine.inv.add +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.engine.inv.transact.TransactionError +import world.gregs.voidps.engine.inv.transact.operation.AddItem.add +import world.gregs.voidps.world.activity.achievement.Tasks.isCompleted +import world.gregs.voidps.world.interact.dialogue.Happy +import world.gregs.voidps.world.interact.dialogue.Neutral +import world.gregs.voidps.world.interact.dialogue.Quiz +import world.gregs.voidps.world.interact.dialogue.Talk +import world.gregs.voidps.world.interact.dialogue.type.choice +import world.gregs.voidps.world.interact.dialogue.type.npc +import world.gregs.voidps.world.interact.dialogue.type.player + +npcOperate("Talk-to", "explorer_jack") { + if (player["introducing_explorer_jack_task", "uncompleted"] == "uncompleted") { + npc("Ah! Welcome to ${name}, lad. My name's Explorer jack. I'm an explorer by trade, and I'm one of the Taskmasters around these parts") + player("Taskmaster? What Tasks are you Master of?") + whatIsTaskSystem() + } + if (!player["unlocked_emote_explore", false] && completedAllBeginner(player)) { + player("I think I've finished all of the Beginner Tasks in the Lumbridge set.") + npc("You have? Oh, well done! We'll make an explorer of you yet.") + player("Thank you. Is there a reward?") + npc("Ah, yes indeed.") + if (!player.inventory.add("explorers_ring_1", "antique_lamp_beginner_lumbridge_tasks")) { + npc("You don't seem to have space, speak to me again when you have two free spaces in your inventory.") // TODO proper message + return@npcOperate + } + player["unlocked_emote_explore"] = true + npc("Having completed the beginner tasks, you have been granted the ability to use the Explorer emote to show your friends.") + npc("I have also given you an explorer's ring. Now, this is more than just any old ring. Aside from looking good, it also has magical properties giving you a small but useful boost to your Magic and Prayer.") + npc("Your ring has the ability to restore some of your run energy to you.") + npc("For each of the first three sections of the diary you complete, your ring will gain an extra charge; so the ring you receive from the medium level tasks will have 3 charges for example.") + npc("If they should run out, the ring is recharged by the sun each day, so you will be able to use it again tomorrow and so on.") + npc("As an extra reward, you can have this old magical lamp to help with your skills. I was going to use it myself, but I don't really need it.") + player("Thanks very much.") + npc("If you should lose your ring, come back to see me and I'm sure I'll have another. Now, did you have anything further to ask?") + } + choice { + option("Tell me about the Task System.") { + whatIsTaskSystem() + } + option("Can I claim any rewards from you?") { + npc("You certainly can!") + choice("Where would you like the items sent?") { + option("Inventory.") { + claim("inventory") + } + option("Bank.") { + claim("bank") + } + } + } + option("Sorry, I was just leaving.") + } + /* + npc("What ho! Where did you come from?") + player("Um... Well, I was in the cellar of some old guy called Roddeck, and then there was a dragon, and we had to break through your wall to escape.") + npc("Hahaha! I always told Roddeck he shouldn't keep a dragon in his cellar. They're wild creatures, you know. It takes real skill to rear them as pets.") + npc("I don't think he'll be trying it again. You're not angry about your wall?") + npc("No, no. I'm an explorer; my house is just a place where I sleep between expeditions. Anyway, can I do anything for you?") + player("What do you mean?") + npc("I can tell you about the Achievement Diary.") + player("What is the Achievement Diary?") + npc("Ah, well it's a diary that helps you keep track of particular achievements in the world of ${World.name}. In Lumbridge and Draynor, it can help you discover some very useful things indeed.") + npc("Eventually, with enough exploration, you will be rewarded for your explorative efforts.") + npc("You can find your Achievement Diary by clicking on the green star icon.") + npc("You should see the icon flashing now. Go ahead and click on it to find your Achievement Diary. If you have any questions, feel free to speak to me again.") // TODO +*/ +} + +suspend fun NPCOption.whatIsTaskSystem() { + npc("Well, the Task System is a potent method of guiding yourself to useful things to do around the world.") + npc("You'll see up to six Tasks in your side bar if you click on the glowing Task List icon. You can click on one for more information about it, hints, waypoint arrows, that sort of thing.") + npc("Every Task you do will earn you something of value which you can claim from me. It'll be money, mostly, but the Rewards tab for a Task will tell you more.
Good luck!") + player["introducing_explorer_jack_task"] = "completed" + player["unstable_foundations"] = "completed" + player.sendScript("task_list_button_hide", 0) + player.interfaces.sendVisibility("task_system", "ok", true) +} + +val variables: VariableDefinitions by inject() + +suspend fun NPCOption.claim(inventoryId: String) { + npc("I'll just fill your $inventoryId with what you need, then.") + val inventory = player.inventories.inventory(inventoryId) + val progress = player["task_progress_overall", 0] + val rewards = progress - player["task_progress_rewarded", 0] + var coins = 0 + for (i in 0 until rewards) { + coins += when { + progress + i < 10 -> 10 + progress + i < 25 -> 40 + progress + i < 50 -> 160 + progress + i < 75 -> 640 + else -> 2560 + } + } + val values = (variables.get("task_reward_items")!!.values as BitwiseValues).values + inventory.transaction { + add("coins", coins) + if (player.contains("task_reward_items")) { + for (value in values) { + if (player.containsVarbit("task_reward_items", value)) { + add(value as String) + } + } + } + } + when (inventory.transaction.error) { + is TransactionError.Full -> player.inventoryFull() + TransactionError.None -> { + player.message("You receive $coins coins.") + npc("There you go.") + player["task_progress_rewarded"] = player["task_progress_overall", 0] + player.clear("task_reward_items") + if (coins > 100) { + player["must_be_funny_in_a_rich_mans_world_task"] = true + } + } + else -> { + } + } +} + +fun completedAllBeginner(player: Player): Boolean { + return Tasks.forEach(1) { + if (definition["task_difficulty", 0] == 1 && !isCompleted(player, definition.stringId)) { + return@forEach false + } + null + } ?: false +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorersRing.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorersRing.kts new file mode 100644 index 0000000000..9b7ddbff66 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorersRing.kts @@ -0,0 +1,29 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.entity.character.setAnimation +import world.gregs.voidps.engine.entity.character.setGraphic +import world.gregs.voidps.engine.entity.playerSpawn +import world.gregs.voidps.engine.inv.discharge +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.world.interact.entity.player.energy.MAX_RUN_ENERGY +import world.gregs.voidps.world.interact.entity.player.energy.runEnergy +import world.gregs.voidps.world.interact.entity.player.equip.inventoryOption +import java.util.concurrent.TimeUnit + +playerSpawn { player -> + val lastUse = player["explorers_ring_last_use", -1L] + if (lastUse != -1L && lastUse != TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis())) { + player["explorers_ring_charges"] = 1 + } +} + +inventoryOption("Run-replenish", "explorers_ring_*") { + if (player.inventory.discharge(player, slot)) { + player.setAnimation("run_replenish") + player.setGraphic("run_replenish") + player.runEnergy += MAX_RUN_ENERGY / 2 + player["explorers_ring_last_use"] = TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis()) + player.message("You feel refreshed as the ring revitalises you and a charge is used up.") + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasks.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasks.kts new file mode 100644 index 0000000000..ce2c284006 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasks.kts @@ -0,0 +1,370 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.client.variable.variableSet +import world.gregs.voidps.engine.data.definition.AreaDefinitions +import world.gregs.voidps.engine.data.definition.WeaponStyleDefinitions +import world.gregs.voidps.engine.entity.character.mode.move.enterArea +import world.gregs.voidps.engine.entity.character.mode.move.move +import world.gregs.voidps.engine.entity.character.move.running +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.maxLevelChange +import world.gregs.voidps.engine.entity.obj.GameObjects +import world.gregs.voidps.engine.entity.obj.ObjectShape +import world.gregs.voidps.engine.inject +import world.gregs.voidps.engine.inv.itemAdded +import world.gregs.voidps.engine.inv.itemChange +import world.gregs.voidps.engine.inv.itemRemoved +import world.gregs.voidps.engine.inv.itemReplaced +import world.gregs.voidps.engine.timer.timerStop +import world.gregs.voidps.network.login.protocol.visual.update.player.EquipSlot +import world.gregs.voidps.type.Tile +import world.gregs.voidps.world.interact.entity.combat.attackStyle +import world.gregs.voidps.world.interact.entity.combat.hit.combatAttack +import world.gregs.voidps.world.interact.entity.combat.killer +import world.gregs.voidps.world.interact.entity.death.npcDeath +import world.gregs.voidps.world.interact.entity.npc.shop.itemSold +import world.gregs.voidps.world.interact.entity.npc.shop.shopOpen +import world.gregs.voidps.world.interact.entity.obj.teleportLand +import world.gregs.voidps.world.interact.entity.player.combat.prayer.prayerStart +import world.gregs.voidps.world.interact.entity.player.combat.range.ammo + +move({ player.running && !player["on_the_run_task", false] }) { + player["on_the_run_task"] = true +} + +teleportLand("Climb-up", "lumbridge_castle_ladder") { + player["master_of_all_i_survey_task"] = true +} + +val areas: AreaDefinitions by inject() + +itemAdded("copper_ore", inventory = "inventory") { player -> + if (player.softTimers.contains("mining") && player.tile in areas["lumbridge_swamp_east_copper_mine"]) { + player["take_your_pick_task"] = true + } +} + +itemAdded("logs", inventory = "inventory") { player -> + if (player.softTimers.contains("woodcutting")) { + player["adventurers_log_task"] = true + } +} + +itemAdded("raw_crayfish", inventory = "inventory") { player -> + if (player.softTimers.contains("fishing")) { + player["arent_they_supposed_to_be_twins_task"] = true + } +} + +val objects: GameObjects by inject() + +itemRemoved("logs", inventory = "inventory") { player -> + if (!player["log_a_rhythm_task", false]) { + player["burnt_regular_log"] = true + player["fire_tile"] = player.tile + } +} + +timerStop("firemaking") { player -> + val regular: Boolean = player.remove("burnt_regular_log") ?: return@timerStop + val tile: Tile = player.remove("fire_tile") ?: return@timerStop + if (regular) { + val fire = objects.getShape(tile, ObjectShape.CENTRE_PIECE_STRAIGHT) + if (fire != null && fire.id.startsWith("fire_")) { + player["log_a_rhythm_task"] = true + } + } +} + +itemReplaced("raw_crayfish", "crayfish", "inventory") { player -> + if (player.softTimers.contains("cooking")) { + player["shellfish_roasting_on_an_open_fire_task"] = true + } +} + +itemAdded("tin_ore", inventory = "inventory") { player -> + if (player.softTimers.contains("mining")) { + player["heavy_metal_task"] = true + } +} + +itemAdded("bronze_bar", inventory = "inventory") { player -> + if (player.softTimers.contains("smelting")) { + player["bar_one_task"] = true + } +} + +itemAdded("bronze_dagger", inventory = "inventory") { player -> + if (player.softTimers.contains("smithing")) { + player["cutting_edge_technology_task"] = true + } +} + +val styleDefinitions: WeaponStyleDefinitions by inject() + +itemChange("worn_equipment") { player -> + when (index) { + EquipSlot.Feet.index, EquipSlot.Shield.index, EquipSlot.Legs.index, EquipSlot.Chest.index -> { + if (item.id.contains("iron")) { + player["alls_ferrous_in_love_and_war_task"] = true + } else if (item.id.contains("steel")) { + player["steel_yourself_for_combat_task"] = true + } + } + EquipSlot.Weapon.index -> { + if (item.id.contains("iron")) { + player["not_what_we_mean_by_irony_task"] = true + } else if (item.id.contains("steel")) { + player["temper_temper_task"] = true + } + val id = item.def["weapon_style", -1] + when (val style = styleDefinitions.get(id).stringId) { + "staff" -> player["just_cant_get_the_staff_task"] = true + "axe", "pickaxe", "dagger", "sword", "2h", "mace", "claws", "hammer", "whip", "spear", "halberd", "ivandis_flail", "salamander" -> { + player["armed_and_dangerous_task"] = true + } + "bow", "crossbow", "thrown", "chinchompa", "sling" -> { + player["reach_out_and_touch_someone_task"] = true + if (!player["take_a_bow_task", false]) { + if (style == "bow") { + if (item.id.contains("longbow")) { + player["equip_longbow"] = true + } else { + player["equip_shortbow"] = true + } + } else if (style == "crossbow") { + player["equip_crossbow"] = true + } + if (player["equip_shortbow", false] || player["equip_longbow", false] || player["equip_crossbow", false]) { + player["take_a_bow_task"] = true + player.clear("equip_shortbow") + player.clear("equip_longbow") + player.clear("equip_crossbow") + } + } + if (item.id == "oak_shortbow" || item.id == "oak_longbow") { + player["heart_of_oak_task"] = true + } + } + } + } + EquipSlot.Ammo.index -> if (item.id == "iron_arrow") { + player["ammo_ammo_ammo_task"] = true + } + } +} + +itemChange("worn_equipment", EquipSlot.Weapon.index) { player -> + if (player["armed_and_dangerous_task", false] && player["just_cant_get_the_staff_task", false] && player["reach_out_and_touch_someone_task", false]) { + return@itemChange + } +} + +variableSet("task_progress_overall") { player -> + if ((from == null || from is Int && (from as Int) < 10) && to is Int && (to as Int) >= 10) { + player["on_your_way_task"] = true + } +} + +itemAdded(inventory = "bank") { player -> + if (!player["hang_on_to_something_task", false]) { + player["hang_on_to_something_task"] = true + player.addVarbit("task_reward_items", "magic_staff") + } +} + +npcDeath("cow*") { cow -> + val killer = cow.killer + if (killer is Player) { + killer["bovine_intervention_task"] = true + } +} + +itemReplaced("cowhide", "leather") { player -> + player["tan_your_hide_task"] = true +} + +itemAdded("leather_gloves", inventory = "inventory") { player -> + if (player.softTimers.contains("item_on_item")) { + player["handicrafts_task"] = true + } +} + +itemChange(item = "leather_gloves", index = EquipSlot.Hands.index, inventory = "worn_equipment") { player -> + player["handy_dandy_task"] = true +} + +combatAttack(spell = "wind_strike") { player -> + player["death_from_above_task"] = true +} + +itemReplaced(to = "bread", inventory = "inventory") { player -> + if (player.softTimers.contains("cooking")) { + player["a_labour_of_loaf_task"] = true + } +} + +maxLevelChange { player -> + if (!player["on_the_level_task", false] || !player["quarter_centurion_task", false]) { + val total = Skill.all.sumOf { (if (it == Skill.Constitution) player.levels.getMax(it) / 10 - 10 else player.levels.getMax(it) - 1) } + if (total == 10) { + player["on_the_level_task"] = true + } else if (total == 25) { + player["quarter_centurion_task"] = true + } + } +} + +itemAdded("pure_essence", inventory = "inventory") { player -> + if (player.softTimers.contains("mining")) { + player["so_thats_what_ess_stands_for_task"] = true + } +} + +itemAdded("rune_essence", inventory = "inventory") { player -> + if (player.softTimers.contains("mining")) { + player["so_thats_what_ess_stands_for_task"] = true + } +} + +itemAdded("air_rune", inventory = "inventory") { player -> + if (player.softTimers.contains("runecrafting")) { + player["air_craft_task"] = true + } +} + +itemSold { player -> + player["greasing_the_wheels_of_commerce_task"] = true +} + +prayerStart { player -> + player["put_your_hands_together_for_task"] = true +} + +npcDeath("giant_rat*") { npc -> + val killer = npc.killer + if (killer is Player && !killer["am_i_a_blademaster_yet_task", false]) { + when (val style = killer.attackStyle) { + "aggressive" -> killer["giant_rat_$style"] = true + "controlled" -> killer["giant_rat_$style"] = true + "defensive" -> killer["giant_rat_$style"] = true + } + if (killer["giant_rat_aggressive", false] && killer["giant_rat_controlled", false] && killer["giant_rat_defensive", false]) { + killer["am_i_a_blademaster_yet_task"] = true + killer.clear("giant_rat_aggressive") + killer.clear("giant_rat_controlled") + killer.clear("giant_rat_defensive") + } + } +} + +maxLevelChange(Skill.Attack, Skill.Defence) { player -> + if (from < 5 && to >= 5 && player.levels.getMax(Skill.Attack) >= 5 && player.levels.getMax(Skill.Defence) >= 5) { + player["first_blood_task"] = true + } +} + +itemAdded("iron_hatchet", inventory = "inventory") { player -> + player["dont_bury_this_one_task"] = true +} + +itemAdded("bronze_mace", inventory = "inventory") { player -> + if (player.softTimers.contains("smithing")) { + player["mace_invaders_task"] = true + } +} + +itemAdded("bronze_med_helm", inventory = "inventory") { player -> + if (player.softTimers.contains("smithing")) { + player["capital_protection_what_task"] = true + } +} + +itemAdded("bronze_full_helm", inventory = "inventory") { player -> + if (player.softTimers.contains("smithing")) { + player["capital_protection_what_task"] = true + } +} + +itemAdded("empty_pot", inventory = "inventory") { player -> + if (player.softTimers.contains("pottery") && player.tile in areas["draynor"]) { + player["hotpot_task"] = true + } +} + +maxLevelChange(Skill.Mining) { player -> + if (from < 5 && to >= 5) { + player["hack_and_smash_task"] = true + } +} + +itemAdded("raw_shrimps", inventory = "inventory") { player -> + if (player.softTimers.contains("fishing") && player.tile in areas["lumbridge_swamp_fishing_area"]) { + player["shrimpin_aint_easy_task"] = true + } +} + +itemSold("raw_shrimps", "lumbridge_fishing_supplies") { player -> + player["the_fruit_of_the_sea_task"] = true +} + +itemAdded("leather_boots", inventory = "inventory") { player -> + if (player.softTimers.contains("item_on_item")) { + player["made_for_walking_task"] = true + } +} + +itemAdded("raw_sardine", inventory = "inventory") { player -> + if (player.softTimers.contains("fishing")) { + player["did_anyone_bring_any_toast_task"] = true + } +} + +itemReplaced("raw_herring", "herring", "inventory") { player -> + if (player.softTimers.contains("cooking")) { + player["its_not_a_red_one_task"] = true + } +} + +itemReplaced("uncooked_berry_pie", "redberry_pie", "inventory") { player -> + if (player.softTimers.contains("cooking")) { + player["berry_tasty_task"] = true + } +} + +combatAttack(spell = "confuse") { player -> + player["not_so_confusing_after_all_task"] = true +} + +combatAttack(type = "range") { player -> + if (player.ammo == "steel_arrow") { + player["get_the_point_task"] = true + } +} + +variableSet("quest_points") { player -> + if ((from == null || from is Int && (from as Int) < 4) && to != null && to is Int && to as Int >= 4) { + player["fledgeling_adventurer_task"] = true + } +} + +shopOpen("lumbridge_general_store") { player -> + player["window_shopping_task"] = true +} + +enterArea("freds_farmhouse") { + player["wait_thats_not_a_sheep_task"] = true +} + +enterArea("draynor_manor_courtyard") { + player["in_the_countyard_task"] = true +} + +enterArea("draynor_village_market") { + player["beware_of_pigzilla_task"] = true +} + +enterArea("wizards_tower_top_floor") { + player["tower_power_task"] = true +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskList.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskList.kts new file mode 100644 index 0000000000..98b9283ec8 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskList.kts @@ -0,0 +1,153 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.client.sendScript +import world.gregs.voidps.engine.client.ui.close +import world.gregs.voidps.engine.client.ui.event.interfaceOpen +import world.gregs.voidps.engine.client.ui.interfaceOption +import world.gregs.voidps.engine.client.ui.open +import world.gregs.voidps.engine.client.variable.variableSet +import world.gregs.voidps.engine.data.definition.EnumDefinitions +import world.gregs.voidps.engine.data.definition.VariableDefinitions +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.entity.playerSpawn +import world.gregs.voidps.engine.inject + +val variables: VariableDefinitions by inject() + +playerSpawn { player -> + player.sendVariable("task_disable_popups") + player["task_popup"] = 0 + player["task_previous_popup"] = 0 + var total = 0 + for (area in 0 until 8) { + Tasks.forEach(area) { + if (Tasks.isCompleted(player, definition.stringId)) { + player.sendVariable(definition.stringId) + total++ + } + null + } + } + player["task_progress_overall"] = total + player.sendVariable("task_hide_completed") + player.sendVariable("task_filter_sets") +} + +interfaceOpen("task_list") { player -> + player.interfaceOptions.unlockAll("task_list", "tasks", 0..492) + refresh(player) +} + +interfaceOption("Select", "area_*", "task_list") { + player["task_list_area"] = component.removePrefix("area_") + refresh(player) +} + +interfaceOption("Summary", "tasks", "task_list") { + player["task_selected"] = itemSlot / 4 +} + +interfaceOption("Pin", "tasks", "task_list") { + pin(player, itemSlot / 4) +} + +interfaceOption("Pin", "pin", "task_list") { + pin(player, player["task_selected", 0]) +} + +fun indexOfSlot(player: Player, slot: Int): Int? { + var count = 0 + return Tasks.forEach(areaId(player)) { + if (player["task_hide_completed", false] && Tasks.isCompleted(player, definition.stringId)) { + return@forEach null + } + if (player["task_filter_sets", false] && !definition.contains("task_sprite_offset")) { + return@forEach null + } + if (count++ == slot) { + return@forEach index + } + null + } +} + +fun find(player: Player, id: Int): Int { + for (i in 0 until 6) { + if (player["task_slot_${i}", -1] == id) { + return i + } + } + return 1 +} + +interfaceOption("Filter-sets", "filter_sets", "task_list") { + player["task_filter_sets"] = !player["task_filter_sets", false] +} + +interfaceOption("Filter-done", "filter_done", "task_list") { + player["task_hide_completed"] = !player["task_hide_completed", false] +} + +interfaceOption("Turn-off", "toggle_popups", "task_list") { + val disable = !player["task_disable_popups", false] + player["task_disable_popups"] = disable + if (disable) { + player["task_popup"] = 0 + player["task_previous_popup"] = 0 + } +} + +fun refresh(player: Player) { + player.sendVariable("task_list_area") + val id = areaId(player) + player.sendScript("task_main_list_populate", id, 999, 999) + refreshCompletedCount(player) +} + +variableSet("task_pin_index") { player -> + player.close("task_list") +} + +fun areaId(player: Player) = variables.get("task_list_area")!!.values.toInt(player["task_list_area", "unstable_foundations"]) + +fun pin(player: Player, index: Int) { + val id = indexOfSlot(player, index) ?: return + if (player["task_pinned", -1] == id) { + player.clear("task_pinned") + player.clear("task_pin_index") + } else { + player["task_pinned"] = id + player["task_pin_index"] = find(player, id) + } +} + +fun refreshCompletedCount(player: Player) { + var total = 0 + var completed = 0 + Tasks.forEach(areaId(player)) { + if (Tasks.isCompleted(player, definition.stringId)) { + completed++ + player.sendVariable(definition.stringId) + } + total++ + null + } + player["task_progress_current"] = completed + player["task_progress_total"] = total +} + +/* + Hints + */ + +val enumDefinitions: EnumDefinitions by inject() + +interfaceOption("Hint", "hint_*", "task_list") { + val selected = player["task_selected", 0] + val index = indexOfSlot(player, selected) ?: return@interfaceOption + val tile: Int = enumDefinitions.getStructOrNull("task_structs", index, component.replace("hint_", "task_hint_tile_")) ?: return@interfaceOption + // TODO I expect the functionality is actually minimap highlights not world map + player["world_map_marker_1"] = tile + player["world_map_marker_text_1"] = "" + player.open("world_map") +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskSystem.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskSystem.kts index 1c12bc5e70..6791fdbb56 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskSystem.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskSystem.kts @@ -1,8 +1,229 @@ package world.gregs.voidps.world.activity.achievement +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.client.ui.chat.plural +import world.gregs.voidps.engine.client.ui.event.adminCommand +import world.gregs.voidps.engine.client.ui.event.interfaceOpen import world.gregs.voidps.engine.client.ui.interfaceOption import world.gregs.voidps.engine.client.ui.open +import world.gregs.voidps.engine.client.variable.variableSet +import world.gregs.voidps.engine.data.definition.EnumDefinitions +import world.gregs.voidps.engine.data.definition.StructDefinitions +import world.gregs.voidps.engine.data.definition.VariableDefinitions +import world.gregs.voidps.engine.entity.World +import world.gregs.voidps.engine.entity.character.mode.move.enterArea +import world.gregs.voidps.engine.entity.character.mode.move.exitArea +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.inject +import world.gregs.voidps.world.interact.entity.player.display.Tab + +val variables: VariableDefinitions by inject() +val enumDefinitions: EnumDefinitions by inject() +val structDefinitions: StructDefinitions by inject() + +interfaceOpen("task_system") { player -> + player.sendVariable("task_pin_index") + player.sendVariable("task_pinned") + player.sendVariable("introducing_explorer_jack_task") + refreshSlots(player) + if (player.contains("task_dont_show_again")) { + player.sendVariable("task_dont_show_again") + } + if (player["unstable_foundations", "unstarted"] == "unstarted") { + player["task_pinned"] = 3520 // Talk to explorer jack + player["task_pin_index"] = 1 + player["task_selected"] = 1 + player["unstable_foundations"] = "incomplete" + } +} + +enterArea("lumbridge") { + player["task_area"] = "lumbridge_draynor" +} + +exitArea("lumbridge") { + player["task_area"] = "dnd_activities" +} + +enterArea("draynor") { + player["task_area"] = "lumbridge_draynor" +} + +exitArea("draynor") { + player["task_area"] = "dnd_activities" +} + +interfaceOption("Close", "close_hint", "task_system") { + player.interfaces.sendVisibility(id, "message_overlay", false) +} + +interfaceOption("Select Task", "task_*", "task_system") { + val index = component.removePrefix("task_").toInt() + player["task_selected"] = index +} + +interfaceOption("Toggle", "dont_show", "task_system") { + player["task_dont_show_again"] = !player["task_dont_show_again", false] +} interfaceOption("Open", "task_list", "task_system") { player.open("task_list") } + +interfaceOption("OK", "ok", "task_system") { + player.interfaces.sendVisibility("task_system", "summary_overlay", false) + val selected = player["task_selected", -1] + if (selected != -1 && selected == player["task_pin_index", -1]) { + player.clear("task_pinned") + player.clear("task_pin_index") + player.interfaces.sendVisibility("task_system", "ok", false) + } + refreshSlots(player) +} + +interfaceOption("Pin/Unpin Task", "task_*", "task_system") { + val index = component.removePrefix("task_").toInt() + if (player["task_pin_index", -1] == index) { + player.clear("task_pinned") + player.clear("task_pin_index") + } else { + player["task_pinned"] = indexOfSlot(player, index) ?: return@interfaceOption + player["task_pin_index"] = index + } +} + +fun indexOfSlot(player: Player, slot: Int): Int? { + var count = 1 + return Tasks.forEach(areaId(player)) { + val hideCompleted = Tasks.isCompleted(player, definition.stringId) + val hideMembers = definition["task_members", 0] == 1 && !World.members + if (hideCompleted || hideMembers) { + return@forEach null + } + if (count == player["task_pin_index", -1]) { + val pinned = player["task_pinned", 4091] + if (count == slot) { + return@forEach pinned + } + skip = pinned != index + } + if (count++ == slot) { + return@forEach index + } + null + } +} + +variableSet("task_pin_index", "task_area") { player -> + refreshSlots(player) +} + +fun refreshSlots(player: Player) { + var slot = 1 + var completed = 0 + var total = 0 + Tasks.forEach(areaId(player)) { + total++ + val pinned = pinned(player, slot) + if (player["task_pinned", -1] == index && !pinned || !Tasks.hasRequirements(player, definition)) { + return@forEach null + } + if (Tasks.isCompleted(player, definition.stringId)) { + completed++ + return@forEach null + } + if (pinned) { + player["task_slot_${slot++}"] = player["task_pinned", 4091] + skip = true + } else if (slot < 7) { + player["task_slot_${slot++}"] = index + } + null + } + if (slot < 7) { + for (i in slot..6) { + player["task_slot_${i}"] = 4091 + } + } + player["task_progress_total"] = total + player["task_progress_current"] = completed +} + +fun pinned(player: Player, index: Int): Boolean { + val pinIndex = player["task_pin_index", -1] + return pinIndex != -1 && index == pinIndex +} + +fun areaId(player: Player) = variables.get("task_area")!!.values.toInt(player["task_area", "empty"]) + +/* + Task completion + */ + +interfaceOption("Details", "details", "task_popup") { + player["task_popup_summary"] = true + player["tab"] = Tab.TaskSystem.name +} + +variableSet("*_task") { player -> + if (to == true || to == "completed") { + completeTask(player, key) + } +} + +fun completeTask(player: Player, id: String) { + val definition = structDefinitions.get(id) + val index = definition["task_index", -1] + player["task_popup"] = index + val difficulty = definition["task_difficulty", 0] + val area = definition["task_area", 61] + val areaName = enumDefinitions.get("task_area_names").getString(area) + val difficultyName = enumDefinitions.get("task_difficulties").getString(difficulty) + if (areaName.isNotBlank() && difficultyName.isNotBlank()) { + player.message("You have completed the Task '${definition["task_name", ""]}' in the $difficultyName $areaName set!") + } else { + player.message("You have completed the Task '${definition["task_name", ""]}'!") + } + val before = player["task_progress_current", 0] + refreshSlots(player) + val total = player.inc("task_progress_overall") + player.message("You have now completed $total ${"Task".plural(total)} in total.") + val after = player["task_progress_current", 0] + val maximum = player["task_progress_total", -1] + if (before != after && after == maximum) { + val prettyName = when (area) { + 1 -> "Lumbridge and Draynor" + else -> areaName + } + player.message("Congratulations! You have completed all of the $difficultyName Tasks in the $prettyName") + val npc = when { + area == 1 && difficulty == 1 -> "Explorer Jack in Lumbridge" + area == 1 && difficulty == 2 -> "Bob in Bob's Axes in Lumbridge" + area == 1 && difficulty == 3 -> "Ned in Draynor Village" + else -> "someone somewhere" + } + player.message("set. Speak to $npc to claim your reward.") + } +} + +/* + Hints + */ + +interfaceOption("Hint", "hint_*", "task_system") { + val selected = player["task_selected", 0] + val index = indexOfSlot(player, selected) ?: return@interfaceOption + val tile: Int = enumDefinitions.getStructOrNull("task_structs", index, component.replace("hint_", "task_hint_tile_")) ?: return@interfaceOption + // TODO I expect the functionality is actually minimap highlights not world map + player["world_map_marker_1"] = tile + player["world_map_marker_text_1"] = "" + player.open("world_map") +} + +adminCommand("tasks", "achievements") { + for (struct in structDefinitions.definitions) { + if (struct.stringId.endsWith("_task")) { + player[struct.stringId] = true + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/Tasks.kt b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/Tasks.kt new file mode 100644 index 0000000000..2bfdc4054d --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/Tasks.kt @@ -0,0 +1,296 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.cache.config.data.StructDefinition +import world.gregs.voidps.engine.client.variable.BooleanValues +import world.gregs.voidps.engine.client.variable.MapValues +import world.gregs.voidps.engine.data.definition.EnumDefinitions +import world.gregs.voidps.engine.data.definition.QuestDefinitions +import world.gregs.voidps.engine.data.definition.StructDefinitions +import world.gregs.voidps.engine.data.definition.VariableDefinitions +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.entity.character.player.combatLevel +import world.gregs.voidps.engine.entity.character.player.skill.Skill +import world.gregs.voidps.engine.entity.character.player.skill.level.Level.has +import world.gregs.voidps.engine.entity.character.player.skill.level.Level.hasMax +import world.gregs.voidps.engine.entity.character.player.summoningCombatLevel +import world.gregs.voidps.engine.get +import world.gregs.voidps.world.activity.quest.questComplete +import java.util.* +import java.util.Calendar.HOUR_OF_DAY +import java.util.concurrent.TimeUnit + +object Tasks { + + fun isCompleted(player: Player, id: String): Boolean { + val variable = get().get(id)?.values ?: return false + return when (variable) { + is BooleanValues -> player[id, false] + is MapValues -> player[id, "unstarted"] == "completed" + else -> false + } + } + + class TaskIterator { + lateinit var definition: StructDefinition + var index: Int = -1 + var skip: Boolean = false + } + + fun forEach(areaId: Int, block: TaskIterator.() -> R?): R? { + val enumDefinitions: EnumDefinitions = get() + val structDefinitions: StructDefinitions = get() + var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) + val structs = enumDefinitions.get("task_structs") + val iterator = TaskIterator() + while (next != 4091 && next != 450 && next != 4094) { + val struct = structs.getInt(next) + iterator.definition = structDefinitions.getOrNull(struct) ?: break + iterator.index = next + iterator.skip = false + val result = block.invoke(iterator) + if (result != null) { + return result + } + if (!iterator.skip) { + next = iterator.definition["task_next_index", 4091] + } + } + return null + } + + fun hasRequirements(player: Player, definition: StructDefinition): Boolean { + for (i in 1..10) { + val req = definition["task_skill_$i", -1] + val value = definition["task_level_$i", 1] + when (req) { + -1 -> break + 63 -> return hasRequirements(player, definition.id) + 62 -> { + val quest = get().get(value) + if (player.questComplete(quest.stringId)) { + return false + } + } + else -> { + val skill = skills[req - 1] + if (!player.hasMax(skill, value)) { + return false + } + } + } + } + return true + } + + private val skills = listOf( + Skill.Attack, + Skill.Strength, + Skill.Ranged, + Skill.Magic, + Skill.Defence, + Skill.Constitution, + Skill.Prayer, + Skill.Agility, + Skill.Herblore, + Skill.Thieving, + Skill.Crafting, + Skill.Runecrafting, + Skill.Mining, + Skill.Smithing, + Skill.Fishing, + Skill.Cooking, + Skill.Firemaking, + Skill.Woodcutting, + Skill.Fletching, + Skill.Slayer, + Skill.Farming, + Skill.Construction, + Skill.Hunter, + Skill.Summoning, + Skill.Dungeoneering, + ) + + // Missing quests: 199, 200, 229 + // Missing skills: 302, 305 + // Extra skills: 3005, 3012 + private fun hasRequirements(player: Player, id: Int): Boolean { + return when (id) { + 12 -> player["penguin_hide_and_seek_explained", false] + 23 -> player["fairy_rings_unlocked", false] + 49 -> player["unlocked_emote_air_guitar", false] + 59 -> player.questComplete("into_the_abyss") + 147, 167 -> player["fairy_rings_unlocked", false] + 107 -> player.getInt("dragon_slayer", "unstarted") >= 2 && player["dragon_slayer_received_shield", false] || player.questComplete("dragon_slayer") + 219 -> player.combatLevel >= 100 + 331 -> player.summoningCombatLevel >= 100 + 276, 3011 -> player["quest_points", 0] >= 33 + 281 -> player["unlocked_emote_flap", false] && !player["unlocked_emote_slap_head", false] && !player["unlocked_emote_idea", false] && player["unlocked_emote_stomp", false] + 289 -> player.combatLevel >= 40 + 300 -> kudosCount(player) >= 153 + 3000 -> minutes() >= player["varp_451", 0] && !(player["quest_points", 0] < player["varbit_456", 0] && player["total_xp_earned", 0.0] < player["varp_450", 0.0]) + 3001 -> player.summoningCombatLevel >= 40 + 3002 -> player["penguins_found_weekly", 0] != 10 && player["penguin_points", 0] != 50 && player["penguin_hide_and_seek_explained", 0] != 0 + 3003 -> player["nurture_evil_tree_stage", 0] < 2 + 3007 -> !player["circus_magic", false] || !player["circus_agility", false] || !player["circus_ranged", false] + 3008 -> player["bork_defeated_day", 0] != days() + 3010 -> minutes() < player["skeletal_horror_respawn_minute", 0] + 3013 -> player.summoningCombatLevel >= 40 + 3015 -> player.hasMax(Skill.Attack, 65) || player.hasMax(Skill.Defence, 65) + 3031 -> player.summoningCombatLevel >= 48 + 3034 -> player.levels.getMax(Skill.Strength) + player.levels.getMax(Skill.Attack) >= 130 || !player.hasMax(Skill.Attack, 99) || !player.hasMax(Skill.Strength, 99) + 3500 -> unstableFoundationsStage(player) == 3500 + 3501 -> unstableFoundationsStage(player) == 3501 + 3505 -> unstableFoundationsStage(player) == 3505 + 3511 -> unstableFoundationsStage(player) == 3511 + 3502 -> unstableFoundationsStage(player) == 3502 + 3503 -> unstableFoundationsStage(player) == 3503 + 3504 -> unstableFoundationsStage(player) == 3504 + 3506 -> unstableFoundationsStage(player) == 3506 + 3508 -> unstableFoundationsStage(player) == 3508 + 3509 -> unstableFoundationsStage(player) == 3509 + 3507 -> unstableFoundationsStage(player) == 3507 + 3523 -> unstableFoundationsStage(player) == 3523 + 3510 -> unstableFoundationsStage(player) == 3510 + 3512 -> unstableFoundationsStage(player) == 3512 + 3513 -> unstableFoundationsStage(player) == 3513 + 3514 -> unstableFoundationsStage(player) == 3514 + 3515 -> player.getInt("unstable_foundations", "unstarted") in 135..160 && player["varbit_6495", 0] != 0 && player["varbit_6495", 0] != 1 + 3516 -> player.getInt("unstable_foundations", "unstarted") in 135..160 && player["varbit_6495", 0] != 2 && player["varbit_6495", 0] != 3 + 3517 -> player.getInt("unstable_foundations", "unstarted") >= 140 && player["varbit_6495", 0] != 0 && player["varbit_6495", 0] != 1 && !player.has(Skill.Woodcutting, 2) + 3518 -> player.getInt("unstable_foundations", "unstarted") >= 140 && player["varbit_6495", 0] != 2 && player["varbit_6495", 0] != 3 && !player.has(Skill.Mining, 2) + 3519 -> unstableFoundationsStage(player) == 3519 + 3520 -> unstableFoundationsStage(player) == 3521 && player["varbit_6494", 0] <= 2 + 3521 -> unstableFoundationsStage(player) == 3521 && player["varbit_6494", 0] == 5 + else -> true + } + } + + private fun Player.getInt(id: String, default: String): Int { + return get().get(id)!!.values.toInt(this[id, default]) + } + + private fun minutes() = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis()) + + private fun days(): Int { + val now = Calendar.getInstance() + now.set(HOUR_OF_DAY, 12) + return TimeUnit.MILLISECONDS.toDays(now.timeInMillis).toInt() + } + + private fun kudosCount(player: Player): Int { + var kudos = 88 + if (player["varbit_5387", 0] == 250) { + kudos += 5 + } + if (player["varbit_2561", 0] >= 3) { + kudos += 5 + } + if (player["varp_131", 0] >= 9) { + kudos += 5 + } + if (player["varbit_358", 0] == 15) { + kudos += 10 + } + if (player["varbit_6001", 0] >= 45) { + kudos += 10 + } + if (player["varp_150", 0] >= 160) { + kudos += 5 + } + if (player["varp_223", 0] >= 9) { + kudos += 5 + } + if (player["varbit_1990", 0] >= 430) { + kudos += 5 + } + if (player["varbit_1383", 0] >= 4) { + kudos += 5 + } + if (player["varbit_5075", 0] == 20) { + kudos += 5 + } + if (player["varp_14", 0] >= 7) { + kudos += 5 + } + if (player["varp_112", 0] >= 7) { + kudos += 5 + } + if (player["varp_302", 0] >= 61) { + kudos += 5 + } + if (player["varp_63", 0] >= 6) { + kudos += 5 + } + if (player["varp_145", 0] >= 7 || player["varp_146", 0] >= 4) { + kudos += 5 + } + if (player["varbit_1028", 0] >= 70) { + kudos += 5 + } + if (player["varp_26", 0] >= 80) { + kudos += 5 + } + if (player["varbit_3523", 0] >= 150) { + kudos += 5 + } + return kudos + } + + private fun unstableFoundationsStage(player: Player): Int { + val stage = player.getInt("unstable_foundations", "unstarted") + when (stage) { + 7 -> return 3500 + 9 -> return 3500 + 10 -> return 3501 + 15 -> return 3502 + 20 -> return 3503 + 25 -> return 3503 + 30 -> return 3503 + 35 -> return 3504 + 40 -> return 3504 + 45 -> return 3505 + 46 -> return 3505 + 47 -> return 3505 + 48 -> return 3505 + 49 -> return 3505 + 50 -> return 3506 + 55 -> return 3506 + 56 -> return 3506 + 57 -> return 3506 + 60 -> return 3508 + 62 -> return 3509 + 65 -> return 3507 + 70 -> return 3523 + 75 -> return 3507 + 80 -> return 3510 + 82 -> return 3510 + 83 -> return 3510 + 90 -> return 3510 + 93 -> return 3511 + 95 -> return 3511 + 96 -> return 3512 + 98 -> return 3512 + 100 -> return 3512 + 105 -> return 3512 + 110 -> return 3512 + 115 -> return 3512 + 120 -> return 3513 + 123 -> return 3513 + 125 -> return 3513 + 126 -> return 3513 + 127 -> return 3513 + 128 -> return 3514 + 130 -> return 3514 + 135 -> return 3514 + 140 -> return 3514 + 145 -> return 3514 + 150 -> return 3514 + 155 -> return 3514 + 160 -> return 3514 + 165 -> return 3514 + 170 -> return 3519 + 1000 -> return 3521 + } + return 4094 + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Quests.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Quests.kts index 97f0ddf510..aae5cd72bc 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Quests.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Quests.kts @@ -3,6 +3,7 @@ package world.gregs.voidps.world.activity.quest import world.gregs.voidps.engine.client.ui.event.adminCommand val quests = listOf( + "unstable_foundations", "cooks_assistant", "demon_slayer", "dorics_quest", diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/ItemOnItems.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/ItemOnItems.kts index 839160768a..056009e219 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/ItemOnItems.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/ItemOnItems.kts @@ -39,6 +39,7 @@ itemOnItem { player -> } player.closeInterfaces() player.weakQueue("item_on_item") { + player.softTimers.start("item_on_item") val maximum = getMaximum(overlaps, player) val (def, amount) = if (makeImmediately(player, overlaps, maximum, player.inventory)) { player.closeDialogue() @@ -66,10 +67,12 @@ fun useItemOnItem( count: Int ) { if (count >= amount) { + player.softTimers.stop("item_on_item") return } if (skill != null && !player.has(skill, def.level, true)) { + player.softTimers.stop("item_on_item") return } @@ -78,10 +81,12 @@ fun useItemOnItem( val message = transaction.removeItems(def, success = true) if (!transaction.revert()) { player.message(message) + player.softTimers.stop("item_on_item") return } if (transaction.failed) { player.message(message) + player.softTimers.stop("item_on_item") return } if (def.animation.isNotEmpty()) { @@ -110,6 +115,7 @@ fun replaceItems( val message = transaction.removeItems(def, success) if (!transaction.commit()) { player.message(message) + player.softTimers.stop("item_on_item") return } if (success) { diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/cooking/Cooking.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/cooking/Cooking.kts index bbb27ec984..46db4ac756 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/cooking/Cooking.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/cooking/Cooking.kts @@ -98,6 +98,7 @@ fun Player.cook(item: Item, count: Int, obj: GameObject, cooking: Uncooked, offs fun Player.failedToReplace(item: Item, raw: Uncooked, cooked: Boolean): Boolean { val id = if (cooked) raw.cooked else raw.burnt val itemId = id.ifEmpty { item.id.replace("raw", if (cooked) "cooked" else "burnt") } + println("Replace ${item.id} $itemId") if (!inventory.replace(item.id, itemId)) { return true } diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/crafting/Pottery.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/crafting/Pottery.kts index f3e65433ec..e48db682d6 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/crafting/Pottery.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/crafting/Pottery.kts @@ -52,27 +52,32 @@ suspend fun TargetObjectContext.make(animation: String, item: Item) { } val data = pottery.getValue(id) val actualAmount = if (current < amount) current else amount + player.softTimers.start("pottery") player.make(animation, target, item, id, data, actualAmount) } fun Player.make(animation: String, obj: GameObject, item: Item, id: String, data: Pottery.Ceramic, amount: Int) { if (amount <= 0) { + softTimers.stop("pottery") return } val current = inventory.count(item.id) if (current <= 0) { message("You need some ${item.id.toLowerSpaceCase()} in order to make a ${id.toLowerSpaceCase()}.") + softTimers.stop("pottery") return } face(obj) if (!has(Skill.Crafting, data.level)) { message("You need a Crafting level of ${data.level} to make a ${id.toLowerSpaceCase()}.") + softTimers.stop("pottery") return } setAnimation(animation) weakQueue("make_pottery", 3) { if (!inventory.replace(item.id, id)) { message("You need some ${item.id.toLowerSpaceCase()} in order to make a ${id.toLowerSpaceCase()}.") + softTimers.stop("pottery") return@weakQueue } player.playSound("pottery") diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/BoneBurying.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/BoneBurying.kts index d82f5acc89..a86519877d 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/BoneBurying.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/BoneBurying.kts @@ -33,6 +33,7 @@ inventoryOption("Bury", "inventory") { player.start("bone_delay", 1) player.setAnimation("bend_down") player.experience.add(Skill.Prayer, xp) + player["i_wonder_if_itll_sprout_task"] = true player.weakQueue("bury", 1, onCancel = null) { player.message("You bury the ${item.def.name.lowercase()}.", ChatType.Filter) } diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/PrayerAltars.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/PrayerAltars.kts index aee02c5fde..55bab2fe8d 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/PrayerAltars.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/prayer/PrayerAltars.kts @@ -21,6 +21,7 @@ fun ObjectOption.pray() { player.levels.set(Skill.Prayer, player.levels.getMax(Skill.Prayer)) player.setAnimation("altar_pray") player.message("You recharge your Prayer points.") + player["prayer_point_power_task"] = true } } diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/runecrafting/Runecrafting.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/runecrafting/Runecrafting.kts index abe6eed728..9efa0cec81 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/runecrafting/Runecrafting.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/runecrafting/Runecrafting.kts @@ -50,6 +50,7 @@ fun Runecrafting.bindRunes(player: Player, id: String, itemDefinition: ItemDefin if (!player.has(Skill.Runecrafting, rune.levels.first(), message = true)) { return } + player.softTimers.start("runecrafting") val pure = rune.pure || !player.inventory.contains("rune_essence") val essenceId = if (pure) "pure_essence" else "rune_essence" val essence = player.inventory.count(essenceId) @@ -72,6 +73,7 @@ fun Runecrafting.bindRunes(player: Player, id: String, itemDefinition: ItemDefin } else -> logger.warn { "Error binding runes $player $rune ${player.levels.get(Skill.Runecrafting)} $essence" } } + player.softTimers.stop("runecrafting") } itemOnObjectOperate("*_rune", "*_altar") { diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/transport/teleport/HomeTeleport.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/transport/teleport/HomeTeleport.kts index 4a02567b0d..3bbae4a789 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/transport/teleport/HomeTeleport.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/transport/teleport/HomeTeleport.kts @@ -45,6 +45,7 @@ interfaceOption("Cast", "lumbridge_home_teleport", "modern_spellbook") { } withContext(NonCancellable) { player.tele(areas["lumbridge_teleport"].random()) + player["click_your_heels_three_times_task"] = true player.start("home_teleport_timeout", TimeUnit.MINUTES.toSeconds(30).toInt(), epochSeconds()) } } diff --git a/game/src/main/kotlin/world/gregs/voidps/world/command/admin/AdminCommands.kts b/game/src/main/kotlin/world/gregs/voidps/world/command/admin/AdminCommands.kts index 7bd235dde2..b2cc28b72b 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/command/admin/AdminCommands.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/command/admin/AdminCommands.kts @@ -42,6 +42,7 @@ import world.gregs.voidps.engine.entity.worldSpawn import world.gregs.voidps.engine.get import world.gregs.voidps.engine.inject import world.gregs.voidps.engine.inv.* +import world.gregs.voidps.engine.inv.transact.TransactionError import world.gregs.voidps.engine.inv.transact.charge import world.gregs.voidps.engine.inv.transact.operation.AddItemLimit.addToLimit import world.gregs.voidps.engine.queue.softQueue @@ -171,7 +172,9 @@ adminCommand("item") { addToLimit(id, if (amount == "max") Int.MAX_VALUE else amount.toSILong().toInt()) } } - println(player.inventory.transaction.error) + if (player.inventory.transaction.error != TransactionError.None) { + player.message(player.inventory.transaction.error.toString()) + } } adminCommand("give") { @@ -361,6 +364,7 @@ adminCommand("reload") { get().load() } "sound", "sounds", "sound effects" -> get().load() + "quest", "quests" -> get().load() "midi" -> get().load() "vars", "variables" -> get().load() "music", "music effects", "jingles" -> get().load() diff --git a/game/src/main/kotlin/world/gregs/voidps/world/command/debug/InterfaceCommands.kts b/game/src/main/kotlin/world/gregs/voidps/world/command/debug/InterfaceCommands.kts index b11d969e06..dde1eae800 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/command/debug/InterfaceCommands.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/command/debug/InterfaceCommands.kts @@ -3,6 +3,7 @@ package world.gregs.voidps.world.command.debug import world.gregs.voidps.engine.client.message import world.gregs.voidps.engine.client.sendInterfaceSettings import world.gregs.voidps.engine.client.sendInventoryItems +import world.gregs.voidps.engine.client.sendScript import world.gregs.voidps.engine.client.ui.event.adminCommand import world.gregs.voidps.engine.client.ui.menu.InterfaceOptionSettings.getHash import world.gregs.voidps.engine.data.definition.InterfaceDefinitions @@ -72,8 +73,13 @@ adminCommand("setting") { adminCommand("script") { val parts = content.split(" ") - val remainder = parts.subList(1, parts.size).map { it.toIntOrNull() ?: it }.toTypedArray() - player.client?.sendScript(parts[0].toInt(), remainder.toList()) + val remainder = parts.subList(1, parts.size).map { if (it == "true") 1 else if (it == "false") 0 else it.toIntOrNull() ?: it } + val id = parts[0].toIntOrNull() + if (id == null) { + player.sendScript(id = parts[0], *remainder.toTypedArray()) + } else { + player.sendScript(id, remainder) + } } adminCommand("sendItems") { @@ -87,7 +93,7 @@ adminCommand("sendItems") { adminCommand("var") { val parts = content.split(" ") - player[parts.first()] = parts.last().toIntOrNull() ?: parts.last() + player[parts.first()] = parts.last().toBooleanStrictOrNull() ?: parts.last().toIntOrNull() ?: parts.last() } adminCommand("varp") { diff --git a/game/src/main/kotlin/world/gregs/voidps/world/community/trade/lend/Loan.kt b/game/src/main/kotlin/world/gregs/voidps/world/community/trade/lend/Loan.kt index 38e4eab8d9..906ba4b52f 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/community/trade/lend/Loan.kt +++ b/game/src/main/kotlin/world/gregs/voidps/world/community/trade/lend/Loan.kt @@ -9,7 +9,6 @@ import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.Players import world.gregs.voidps.engine.entity.character.player.name import world.gregs.voidps.engine.get -import world.gregs.voidps.engine.inject import world.gregs.voidps.engine.inv.* import world.gregs.voidps.engine.timer.epochSeconds import world.gregs.voidps.world.activity.bank.bank @@ -17,7 +16,6 @@ import world.gregs.voidps.world.community.trade.returnedItems import java.util.concurrent.TimeUnit object Loan { - private val definitions: ItemDefinitions by inject() private val logger = InlineLogger() fun getSecondsRemaining(player: Player, timeKey: String): Int { @@ -65,6 +63,7 @@ object Loan { } fun lendItem(borrower: Player, lender: Player, item: String, duration: Int) { + val definitions = get() val def = definitions.get(item) val lend = definitions.get(def.lendId).stringId if (!borrower.inventory.add(lend)) { diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/ExperienceLamp.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/ExperienceLamp.kts new file mode 100644 index 0000000000..2b1c2a650e --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/ExperienceLamp.kts @@ -0,0 +1,15 @@ +package world.gregs.voidps.world.interact.dialogue + +import world.gregs.voidps.engine.client.ui.interfaceOption +import world.gregs.voidps.engine.suspend.dialogue.StringSuspension +import world.gregs.voidps.engine.suspend.resumeDialogueSuspension + +interfaceOption("Select", id = "skill_stat_advance") { + player["stat_advance_selected_skill"] = component +} + +interfaceOption("Confirm", id = "skill_stat_advance") { + val suspension = player.dialogueSuspension as? StringSuspension ?: return@interfaceOption + suspension.string = player["stat_advance_selected_skill", "none"] + player.resumeDialogueSuspension() +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/ExpSkillLamp.kt b/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/ExpSkillLamp.kt new file mode 100644 index 0000000000..479c8e80fd --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/ExpSkillLamp.kt @@ -0,0 +1,17 @@ +package world.gregs.voidps.world.interact.dialogue.type + +import net.pearx.kasechange.toPascalCase +import world.gregs.voidps.engine.client.ui.close +import world.gregs.voidps.engine.client.ui.open +import world.gregs.voidps.engine.entity.character.CharacterContext +import world.gregs.voidps.engine.entity.character.player.skill.Skill +import world.gregs.voidps.engine.suspend.dialogue.StringSuspension + +private const val EXPERIENCE_SKILL_LAMP = "skill_stat_advance" + +suspend fun CharacterContext.skillLamp(): Skill { + check(player.open(EXPERIENCE_SKILL_LAMP)) { "Unable to open skill lamp dialogue for $player" } + val result = StringSuspension() + player.close(EXPERIENCE_SKILL_LAMP) + return Skill.valueOf(result.toPascalCase()) +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/LevelUp.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/LevelUp.kts index b55e64cc99..e78dfa71d1 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/LevelUp.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/LevelUp.kts @@ -19,7 +19,7 @@ experience { player -> val previousLevel = Experience.level(skill, from) val currentLevel = Experience.level(skill, to) if (currentLevel != previousLevel) { - player.levels.restore(skill, 1) + player.levels.restore(skill, currentLevel - previousLevel) player.emit(MaxLevelChanged(skill, previousLevel, currentLevel)) } } 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 ade9dcc08b..1770816435 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 @@ -130,6 +130,9 @@ var Character.damageDealers: MutableMap get() = getOrPut("damage_dealers") { Object2IntOpenHashMap() } set(value) = set("damage_dealers", value) +val Character.killer: Character? + get() = damageDealers.maxByOrNull { it.value }?.key + var Character.dead: Boolean get() = get("dead", false) set(value) { diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/death/NPCDeath.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/death/NPCDeath.kts index a42d6109f6..ba0105c6c9 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/death/NPCDeath.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/death/NPCDeath.kts @@ -30,10 +30,7 @@ import world.gregs.voidps.type.Direction import world.gregs.voidps.type.Tile import world.gregs.voidps.world.activity.skill.slayer.race import world.gregs.voidps.world.community.clan.clan -import world.gregs.voidps.world.interact.entity.combat.attackers -import world.gregs.voidps.world.interact.entity.combat.damageDealers -import world.gregs.voidps.world.interact.entity.combat.dead -import world.gregs.voidps.world.interact.entity.combat.inMultiCombat +import world.gregs.voidps.world.interact.entity.combat.* import world.gregs.voidps.world.interact.entity.item.tradeable import world.gregs.voidps.world.interact.entity.sound.playSound @@ -48,8 +45,7 @@ npcDeath { npc -> npc.dead = true npc.steps.clear() npc.strongQueue(name = "death", 1) { - val dealer = npc.damageDealers.maxByOrNull { it.value } - val killer = dealer?.key + val killer = npc.killer val tile = npc.tile npc["death_tile"] = tile npc.setAnimation(deathAnimation(npc)) diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/Banker.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/Banker.kts index 732a035a63..1387955e7f 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/Banker.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/Banker.kts @@ -11,8 +11,8 @@ import world.gregs.voidps.engine.inject import world.gregs.voidps.engine.suspend.approachRange import world.gregs.voidps.engine.suspend.pause import world.gregs.voidps.world.community.trade.lend.Loan.getSecondsRemaining -import world.gregs.voidps.world.interact.dialogue.Talk import world.gregs.voidps.world.interact.dialogue.Quiz +import world.gregs.voidps.world.interact.dialogue.Talk import world.gregs.voidps.world.interact.dialogue.type.choice import world.gregs.voidps.world.interact.dialogue.type.npc @@ -50,9 +50,11 @@ suspend fun CharacterContext.menu() { choice { option("And what do you do?") { npc("We will look after your items and money for you. Leave your valuables with us if you want to keep them safe.") + achievement() } option("Didn't you used to be called the Bank of Varrock?") { npc("Yes we did, but people kept on coming into our branches outside of Varrock and telling us that our signs were wrong. They acted as if we didn't know what town we were in or something.") + achievement() } } } @@ -69,4 +71,11 @@ npcApproach("Collect", "banker*") { player.approachRange(2) pause() player.open("collection_box") +} + +fun CharacterContext.achievement() { + if (!player["you_can_bank_on_us_task", false]) { + player["you_can_bank_on_us_task"] = true + player.addVarbit("task_reward_items", "red_dye") + } } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/BoughtItem.kt b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/BoughtItem.kt new file mode 100644 index 0000000000..0cbdfa75a8 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/BoughtItem.kt @@ -0,0 +1,23 @@ +package world.gregs.voidps.world.interact.entity.npc.shop + +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.entity.item.Item +import world.gregs.voidps.engine.event.Event +import world.gregs.voidps.engine.event.EventDispatcher +import world.gregs.voidps.engine.event.Events + +data class BoughtItem(val item: Item, val shop: String) : Event { + + override val size = 3 + + override fun parameter(dispatcher: EventDispatcher, index: Int) = when (index) { + 0 -> "item_bought" + 1 -> item.id + 2 -> shop + else -> null + } +} + +fun itemBought(item: String = "*", shop: String = "*", handler: suspend BoughtItem.(Player) -> Unit) { + Events.handle("item_bought", item, shop, handler = handler) +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/OpenShop.kt b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/OpenShop.kt index 15f7002176..74adba9322 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/OpenShop.kt +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/OpenShop.kt @@ -3,16 +3,24 @@ package world.gregs.voidps.world.interact.entity.npc.shop import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.event.Event import world.gregs.voidps.engine.event.EventDispatcher +import world.gregs.voidps.engine.event.Events data class OpenShop(val id: String): Event { - override val size = 1 + override val size = 2 + + override val notification: Boolean = true override fun parameter(dispatcher: EventDispatcher, index: Int) = when(index) { 0 -> "open_shop" + 1 -> id else -> null } } +fun shopOpen(shop: String = "*", handler: suspend OpenShop.(Player) -> Unit) { + Events.handle("open_shop", shop, handler = handler) +} + fun Player.openShop(id: String) { emit(OpenShop(id)) } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopBuy.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopBuy.kts index cfc6fbb0aa..97eb3253b8 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopBuy.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopBuy.kts @@ -6,6 +6,7 @@ import world.gregs.voidps.engine.client.ui.interfaceOption import world.gregs.voidps.engine.data.definition.ItemDefinitions import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.chat.inventoryFull +import world.gregs.voidps.engine.entity.item.Item import world.gregs.voidps.engine.inject import world.gregs.voidps.engine.inv.Inventory import world.gregs.voidps.engine.inv.inventory @@ -107,7 +108,10 @@ fun buy(player: Player, shop: Inventory, index: Int, amount: Int) { remove(currency, added * price) } when (player.inventory.transaction.error) { - TransactionError.None -> if (added < actualAmount) player.inventoryFull() + TransactionError.None -> { + if (added < actualAmount) player.inventoryFull() + player.emit(BoughtItem(Item(item.id, added), shop.id)) + } is TransactionError.Full -> player.inventoryFull() TransactionError.Invalid -> logger.warn { "Error buying from shop ${shop.id} $item ${shop.transaction.error}" } else -> {} diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopOpen.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopOpen.kts index ae6c6eac15..4359cfabbc 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopOpen.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopOpen.kts @@ -10,7 +10,6 @@ import world.gregs.voidps.engine.entity.character.face import world.gregs.voidps.engine.entity.character.npc.npcOperate import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.item.Item -import world.gregs.voidps.engine.event.onEvent import world.gregs.voidps.engine.inject import world.gregs.voidps.engine.inv.Inventory import world.gregs.voidps.engine.inv.itemChange @@ -35,8 +34,8 @@ interfaceClose("shop") { player -> } } -onEvent { player -> - val definition = inventoryDefinitions.getOrNull(id) ?: return@onEvent +shopOpen { player -> + val definition = inventoryDefinitions.getOrNull(id) ?: return@shopOpen val currency: String = definition["currency", "coins"] player["shop_currency"] = currency player["item_info_currency"] = currency diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopSell.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopSell.kts index 763670efc0..b59b97413f 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopSell.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopSell.kts @@ -50,8 +50,9 @@ fun sell(player: Player, item: Item, amount: Int) { return } val shop = player.shopInventory(false) + var moved = 0 player.inventory.transaction { - val moved = moveToLimit(item.id, amount, shop, notNoted.id) + moved = moveToLimit(item.id, amount, shop, notNoted.id) if (moved == 0) { this.error = TransactionError.Full(amount) return@transaction @@ -72,6 +73,6 @@ fun sell(player: Player, item: Item, amount: Int) { } } TransactionError.Invalid -> player.message("You can't sell this item to this shop.") - else -> {} + else -> player.emit(SoldItem(Item(item.id, moved), shop.id)) } } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/SoldItem.kt b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/SoldItem.kt new file mode 100644 index 0000000000..ac098c9551 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/SoldItem.kt @@ -0,0 +1,23 @@ +package world.gregs.voidps.world.interact.entity.npc.shop + +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.entity.item.Item +import world.gregs.voidps.engine.event.Event +import world.gregs.voidps.engine.event.EventDispatcher +import world.gregs.voidps.engine.event.Events + +data class SoldItem(val item: Item, val shop: String) : Event { + + override val size = 3 + + override fun parameter(dispatcher: EventDispatcher, index: Int) = when (index) { + 0 -> "item_sold" + 1 -> item.id + 2 -> shop + else -> null + } +} + +fun itemSold(item: String = "*", shop: String = "*", handler: suspend SoldItem.(Player) -> Unit) { + Events.handle("item_sold", item, shop, handler = handler) +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/CombatLevel.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/CombatLevel.kts index d7e9848fa4..9207bad9fe 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/CombatLevel.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/CombatLevel.kts @@ -1,27 +1,34 @@ package world.gregs.voidps.world.interact.entity.player.combat +import world.gregs.voidps.engine.entity.World import world.gregs.voidps.engine.entity.character.player.combatLevel import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.entity.character.player.skill.level.Levels import world.gregs.voidps.engine.entity.character.player.skill.level.maxLevelChange +import world.gregs.voidps.engine.entity.character.player.summoningCombatLevel import world.gregs.voidps.engine.entity.playerSpawn import kotlin.math.max playerSpawn { player -> player.combatLevel = calculateCombatLevel(player.levels) + player.summoningCombatLevel = calculateCombatLevel(player.levels, true) } val combatSkills = Skill.entries.filter { it.ordinal <= 6 || it.ordinal == 23 }.toTypedArray() maxLevelChange(skills = combatSkills) { player -> player.combatLevel = calculateCombatLevel(player.levels) + player.summoningCombatLevel = calculateCombatLevel(player.levels, true) } -fun calculateCombatLevel(levels: Levels): Int { +fun calculateCombatLevel(levels: Levels, summoning: Boolean = false): Int { val melee = levels.getMax(Skill.Attack) + levels.getMax(Skill.Strength) val ranged = (levels.getMax(Skill.Ranged) * 3) / 2 val mage = (levels.getMax(Skill.Magic) * 3) / 2 val highest = max(melee, max(ranged, mage)) * 13 - val def = levels.getMax(Skill.Defence) + (levels.getMax(Skill.Constitution) / 10) + (levels.getMax(Skill.Prayer) / 2) + var def = levels.getMax(Skill.Defence) + (levels.getMax(Skill.Constitution) / 10) + (levels.getMax(Skill.Prayer) / 2) + if (World.members && summoning) { + def += levels.getMax(Skill.Summoning) / 2 + } return ((highest / 10) + def) / 4 } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/Eating.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/Eating.kts index 13384978b5..258b7ac8a9 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/Eating.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/Eating.kts @@ -58,6 +58,8 @@ consume { player -> val range: IntRange = item.def.getOrNull("heals") ?: return@consume val amount = range.random() if (amount > 0) { - player.levels.restore(Skill.Constitution, amount) + if (player.levels.restore(Skill.Constitution, amount) > 0) { + player["om_nom_nom_nom_task"] = true + } } } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/drink/Ale.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/drink/Ale.kts index dd550a7cfe..a9d257578d 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/drink/Ale.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/drink/Ale.kts @@ -13,6 +13,7 @@ consume("bandits_brew") { player -> consume("beer") { player -> player.levels.boost(Skill.Strength, 1, 0.02) player.levels.drain(Skill.Attack, 1, 0.06) + player["dishwater_task"] = true } consume("keg_of_beer*") { player -> diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/GameFrame.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/GameFrame.kts index 10bffcbd90..b98c34a9ba 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/GameFrame.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/GameFrame.kts @@ -20,6 +20,7 @@ val list = listOf( "summoning_orb", "combat_styles", "task_system", + "task_popup", "stats", "quest_journals", "inventory", diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/map/WorldMap.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/map/WorldMap.kts index b78918a0c8..d6d4e679d1 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/map/WorldMap.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/map/WorldMap.kts @@ -2,6 +2,7 @@ package world.gregs.voidps.world.interact.entity.player.display.map import world.gregs.voidps.engine.client.ui.event.interfaceOpen import world.gregs.voidps.engine.client.ui.interfaceOption +import world.gregs.voidps.engine.client.ui.interfaceSlot import world.gregs.voidps.engine.client.ui.open import world.gregs.voidps.engine.data.definition.InterfaceDefinitions import world.gregs.voidps.engine.entity.character.mode.move.move @@ -13,6 +14,45 @@ val definitions: InterfaceDefinitions by inject() interfaceOpen("world_map") { player -> updateMap(player) + player.sendVariable("world_map_hide_player_location") + player.sendVariable("world_map_hide_links") + player.sendVariable("world_map_hide_labels") + player.sendVariable("world_map_hide_tooltips") + player.sendVariable("world_map_marker_custom") + player.interfaceOptions.unlockAll("world_map", "key_list", 0..182) +} + +interfaceOption("Re-sort key", "order", "world_map") { + player["world_map_list_order"] = when (player["world_map_list_order", "categorised"]) { + "categorised" -> "traditional" + "traditional" -> "alphabetical" + "alphabetical" -> "categorised" + else -> "categorised" + } +} + +interfaceSlot("key_list", "world_map", 1) { + player.toggle("world_map_hide_player_location") +} + +interfaceSlot("key_list", "world_map", 4) { + player.toggle("world_map_hide_links") +} + +interfaceSlot("key_list", "world_map", 12) { + player.toggle("world_map_hide_labels") +} + +interfaceSlot("key_list", "world_map", 16) { + player.toggle("world_map_hide_tooltips") +} + +interfaceSlot("key_list", "world_map", 19) { + player["world_map_marker_custom"] = 0 +} + +interfaceOption("Clear marker", "marker", "world_map") { + player["world_map_marker_custom"] = 0 } interfaceOption(component = "world_map", id = "toplevel*") { @@ -32,5 +72,5 @@ move({ it.interfaces.contains("world_map") }) { player -> fun updateMap(player: Player) { val tile = player.tile.id player["world_map_centre"] = tile - player["world_map_player"] = tile + player["world_map_marker_player"] = tile } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Emotes.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Emotes.kts index d01dec36a0..ac4fe2ca69 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Emotes.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Emotes.kts @@ -87,6 +87,15 @@ suspend fun CharacterContext.unlocked(id: String, emote: String): Boolean { statement("This emote can be unlocked during the Lost Tribe quest.") return false } + if (emote == "Taskmaster") { + if (player["task_progress_overall", 0] < 417) { + statement("Complete the Task Master achievement to unlock this emote.") + return false + } + if (!areaClear(player)) { + return false + } + } if (!player["unlocked_emote_$id", false]) { when (emote) { "Glass Wall", "Glass Box", "Climb Rope", "Lean" -> statement("This emote can be unlocked during the mine random event.") @@ -116,13 +125,9 @@ suspend fun CharacterContext.unlocked(id: String, emote: String): Boolean { """) } "Faint" -> statement("This emote can be unlocked by completing the mime court case.") - "Taskmaster" -> statement("Complete the Task Master achievement to unlock this emote.") } return false } - if (emote == "Taskmaster" && !areaClear(player)) { - return false - } if (emote == "Skillcape" && player.equipped(EquipSlot.Cape).id == "dungeoneering_master_cape" && !areaClear(player)) { return false } diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ellis.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ellis.kts index ff2586a546..0e319fb792 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ellis.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ellis.kts @@ -68,7 +68,7 @@ suspend fun NPCOption.leather() { } } -interfaceOption(component = "Tan *", id = "tanner") { +interfaceOption(option = "Tan *", id = "tanner") { val amount = when (option.lowercase()) { "tan ${Colours.ORANGE.toTag()}1" -> 1 "tan ${Colours.ORANGE.toTag()}5" -> 5 @@ -92,6 +92,7 @@ fun tan(player: Player, type: String, amount: Int) { player.message("You don't have any ${item.toLowerSpaceCase()} to tan.") return } + player.softTimers.start("tanning") val tanning: Tanning = itemDefs.get(item)["tanning"] val (leather, cost) = tanning.prices[if (type.endsWith("_1")) 1 else 0] var tanned = 0 @@ -108,6 +109,7 @@ fun tan(player: Player, type: String, amount: Int) { } tanned++ } + player.softTimers.stop("tanning") if (tanned == 1) { player.message("The tanner tans your ${item.toLowerSpaceCase()}.") } else if (tanned > 0) { diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Tollgate.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Tollgate.kts index 606f3b51d2..a2b0128204 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Tollgate.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Tollgate.kts @@ -24,9 +24,9 @@ import world.gregs.voidps.type.Direction import world.gregs.voidps.type.Distance.nearestTo import world.gregs.voidps.type.Tile import world.gregs.voidps.type.area.Rectangle +import world.gregs.voidps.world.interact.dialogue.Quiz import world.gregs.voidps.world.interact.dialogue.Talk import world.gregs.voidps.world.interact.dialogue.Uncertain -import world.gregs.voidps.world.interact.dialogue.Quiz import world.gregs.voidps.world.interact.dialogue.Upset import world.gregs.voidps.world.interact.dialogue.type.choice import world.gregs.voidps.world.interact.dialogue.type.npc @@ -61,6 +61,7 @@ suspend fun CharacterContext.dialogue(player: Player, npc: NPC? = getGuard(playe npc("You must pay a toll of 10 gold coins to pass.") choice { option("Okay, I'll pay.") { + player["passing_out_task"] = true if (!player.inventory.contains("coins", 10)) { player("Oh dear I don't actually seem to have enough money.") } else { diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/DukeHoracio.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/DukeHoracio.kts index d15762a3b0..39c9b1e232 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/DukeHoracio.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/DukeHoracio.kts @@ -12,6 +12,7 @@ import world.gregs.voidps.world.interact.dialogue.* import world.gregs.voidps.world.interact.dialogue.type.* npcOperate("Talk-to", "duke_horacio") { + player["hail_to_the_duke_baby_task"] = true npc("Greetings. Welcome to my castle.") when (player.quest("rune_mysteries")) { "unstarted" -> unstarted() diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeChurch.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeChurch.kts new file mode 100644 index 0000000000..13c7c7ea45 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeChurch.kts @@ -0,0 +1,19 @@ +package world.gregs.voidps.world.map.lumbridge + +import world.gregs.voidps.engine.entity.character.setAnimation +import world.gregs.voidps.engine.entity.obj.objectApproach +import world.gregs.voidps.engine.entity.obj.objectOperate +import world.gregs.voidps.world.interact.entity.sound.playJingle +import world.gregs.voidps.world.interact.entity.sound.playMidi + +objectOperate("Play", "lumbridge_organ") { + player.setAnimation("play_organ") + player.playMidi("church_organ") + player.playJingle("ambient_church_happy") + player["tinkle_the_ivories_task"] = true +} + +objectApproach("Ring", "lumbridge_church_bell") { + // TODO obj anim and sound + player["ring_my_bell_task"] = true +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeFlag.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeFlag.kts index 3420c64c00..e3d9599a73 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeFlag.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeFlag.kts @@ -12,5 +12,6 @@ objectOperate("Raise", "lumbridge_flag") { player.playAnimation("lumbridge_flag_stop_raise") player.forceChat = "All Hail the Duke!" player.playAnimation("emote_salute") + player["raise_the_roof_task"] = true } } diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/combat_hall/CombatDummy.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/combat_hall/CombatDummy.kts index 089d33e891..e2ae0a1cd1 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/combat_hall/CombatDummy.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/combat_hall/CombatDummy.kts @@ -28,7 +28,7 @@ npcApproach("Attack", "magic_dummy", "melee_dummy", override = false) { val itemOnHandler: suspend ItemOnNPC.() -> Unit = handler@{ val type = target.id.removeSuffix("_dummy") - if (player.fightStyle == type) { + if (player.fightStyle == type || type == "magic" && id.endsWith("_spellbook")) { return@handler } player.message("You can only use ${type.toTitleCase()} against this dummy.") @@ -39,7 +39,6 @@ val itemOnHandler: suspend ItemOnNPC.() -> Unit = handler@{ itemOnNPCApproach(npc = "melee_dummy", override = false, handler = itemOnHandler) itemOnNPCApproach(npc = "magic_dummy", override = false, handler = itemOnHandler) - val levelHandler: suspend CurrentLevelChanged.(NPC) -> Unit = handler@{ npc -> if (to > 10) { return@handler diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/wizards_tower/Sedridor.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/wizards_tower/Sedridor.kts index 9d549d451d..3bcaabd84f 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/wizards_tower/Sedridor.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/wizards_tower/Sedridor.kts @@ -38,6 +38,7 @@ npcOperate("Talk-to", "sedridor") { } npcOperate("Teleport", "sedridor") { + player["what_is_this_place_task"] = true EssenceMine.teleport(target, player) } @@ -214,6 +215,7 @@ suspend fun NPCOption.completed() { } fun ChoiceBuilder.teleportEssenceMine(): Unit = option("Can you teleport me to the Rune Essence Mine?") { + player["what_is_this_place_task"] = true EssenceMine.teleport(target, player) } diff --git a/game/src/main/resources/game.properties b/game/src/main/resources/game.properties index bcd1873946..781c724a0e 100644 --- a/game/src/main/resources/game.properties +++ b/game/src/main/resources/game.properties @@ -59,6 +59,7 @@ animationDefinitionsPath=./data/definitions/animations.yml graphicDefinitionsPath=./data/definitions/graphics.yml inventoryDefinitionsPath=./data/definitions/inventories.yml soundDefinitionsPath=./data/definitions/sounds.yml +questDefinitionsPath=./data/definitions/quests.yml renderEmoteDefinitionsPath=./data/definitions/render-emotes.yml midiDefinitionsPath=./data/definitions/midis.yml jingleDefinitionsPath=./data/definitions/jingles.yml @@ -68,6 +69,7 @@ prayerDefinitionsPath=./data/definitions/prayers.yml itemOnItemDefinitionsPath=./data/definitions/item-on-item.yml gearDefinitionsPath=./data/definitions/gear-sets.yml enumDefinitionsPath=./data/definitions/enums.yml +structDefinitionsPath=./data/definitions/structs.yml fontDefinitionsPath=./data/definitions/fonts.yml weaponStyleDefinitionsPath=./data/definitions/weapon-styles.yml weaponAnimationDefinitionsPath=./data/definitions/weapon-animations.yml diff --git a/game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt new file mode 100644 index 0000000000..61cbe7dd2b --- /dev/null +++ b/game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt @@ -0,0 +1,808 @@ +package world.gregs.voidps.world.activity.achievement + +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test +import world.gregs.voidps.FakeRandom +import world.gregs.voidps.engine.client.ui.chat.Colours +import world.gregs.voidps.engine.client.ui.chat.toTag +import world.gregs.voidps.engine.entity.character.move.running +import world.gregs.voidps.engine.entity.character.move.tele +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.item.Item +import world.gregs.voidps.engine.inv.add +import world.gregs.voidps.engine.inv.equipment +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.network.client.instruction.InteractInterfaceNPC +import world.gregs.voidps.network.client.instruction.Walk +import world.gregs.voidps.network.login.protocol.visual.update.player.EquipSlot +import world.gregs.voidps.type.Tile +import world.gregs.voidps.type.setRandom +import world.gregs.voidps.world.script.* +import kotlin.test.assertTrue + +internal class LumbridgeBeginnerTasksTest : WorldTest() { + + override var loadNpcs = true + + @Test + fun `On the Run`() = runTest { + val player = createPlayer("adventurer", emptyTile) + + player.running = true + player.instructions.send(Walk(emptyTile.x, emptyTile.y + 2)) + tick() + + assertTrue(player["on_the_run_task", false]) + } + + @Test + fun `A World in Microcosm`() = runTest { + val player = createPlayer("adventurer", emptyTile) + + player.instructions.send(Walk(emptyTile.x + 1, emptyTile.y + 1, minimap = true)) + tick() + + assertTrue(player["a_world_in_microcosm_task", false]) + } + + @Test + fun `Master of All I survey`() = runTest { + val player = createPlayer("adventurer", Tile(3207, 3224, 2)) + val ladder = objects[Tile(3207, 3223, 2), "lumbridge_castle_ladder"]!! + + player.objectOption(ladder, "Climb-up") + tick(3) + + assertTrue(player["master_of_all_i_survey_task", false]) + } + + @Test + fun `Raise the Roof`() = runTest { + val player = createPlayer("adventurer", Tile(3209, 3217, 3)) + val ladder = objects[Tile(3210, 3218, 3), "lumbridge_flag"]!! + + player.objectOption(ladder, "Raise") + tick(25) + + assertTrue(player["raise_the_roof_task", false]) + } + + @Test + fun `Take Your Pick`() { + setRandom(object : FakeRandom() { + override fun nextInt(until: Int) = if (until == 256) until else 0 + }) + val player = createPlayer("adventurer", Tile(3229, 3147)) + player.levels.set(Skill.Mining, 100) + val rocks = objects[Tile(3230, 3147), "copper_rocks_rock_1"]!! + player.inventory.add("bronze_pickaxe") + + player.objectOption(rocks, "Mine") + tick(9) + + assertTrue(player["take_your_pick_task", false]) + } + + @Test + fun `Adventurer's Log`() { + val player = createPlayer("adventurer", Tile(3233, 3215)) + player.levels.set(Skill.Woodcutting, 100) + val tree = objects[Tile(3233, 3216), "tree_4"]!! + player.inventory.add("bronze_hatchet") + + player.objectOption(tree, "Chop down") + tick(4) + + assertTrue(player["adventurers_log_task", false]) + } + + @Test + fun `Aren't they supposed to be twins`() { + val player = createPlayer("adventurer", Tile(3258, 3205)) + val fishingSpot = createNPC("fishing_spot_crayfish_lumbridge", Tile(3259, 3205)) + player.inventory.add("crayfish_cage") + + player.npcOption(fishingSpot, "Cage") + tick(7) + + assertTrue(player["arent_they_supposed_to_be_twins_task", false]) + } + + @Test + fun `Log-a-rhythm`() { + val player = createPlayer("adventurer", Tile(3235, 3220)) + player.levels.set(Skill.Firemaking, 100) + player.inventory.add("tinderbox", "logs") + + player.itemOnItem(0, 1) + tick(5) + + assertTrue(player["log_a_rhythm_task", false]) + } + + @Test + fun `Shellfish Roasting on an Open Fire`() { + val player = createPlayer("adventurer", Tile(3079, 3444)) + player.inventory.add("raw_crayfish") + val fire = objects[Tile(3079, 3445), "fire_orange"]!! + + player.itemOnObject(fire, 0, "") + tick(4) + + assertTrue(player["shellfish_roasting_on_an_open_fire_task", false]) + } + + @Test + fun `Heavy Metal`() { + setRandom(object : FakeRandom() { + override fun nextInt(until: Int) = if (until == 256) until else 0 + }) + val player = createPlayer("adventurer", Tile(3225, 3147)) + player.levels.set(Skill.Mining, 100) + val rocks = objects[Tile(3225, 3148), "tin_rocks_rock_1"]!! + player.inventory.add("bronze_pickaxe") + + player.objectOption(rocks, "Mine") + tick(9) + + assertTrue(player["heavy_metal_task", false]) + } + + @Test + fun `Bar One`() { + val player = createPlayer("adventurer", Tile(3227, 3255)) + player.levels.set(Skill.Smithing, 100) + val furnace = objects[Tile(3226, 3256), "furnace_lumbridge"]!! + player.inventory.add("copper_ore", "tin_ore") + + player.itemOnObject(furnace, 0, "") + tick() + player.interfaceOption("skill_creation_amount", "increment") + player.dialogueOption(id = "dialogue_skill_creation", component = "choice1") + tick(4) + + assertTrue(player["bar_one_task", false]) + } + + @Test + fun `Cutting Edge Technology`() { + val player = createPlayer("adventurer", Tile(3228, 3254)) + val anvil = objects[Tile(3229, 3254), "anvil_lumbridge"]!! + player.inventory.add("bronze_bar", "hammer") + + player.itemOnObject(anvil, 0, "") + tick() + player.interfaceOption("smithing", "dagger_1") + tick(3) + + assertTrue(player["cutting_edge_technology_task", false]) + } + + @Test + fun `Armed and Dangerous`() { + val player = createPlayer("adventurer") + player.inventory.add("bronze_dagger") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("bronze_dagger"), 0) + + assertTrue(player["armed_and_dangerous_task", false]) + } + + @Test + fun `On Your Way`() { + val player = createPlayer("adventurer") + player["a_world_in_microcosm_task"] = true + player["master_of_all_i_survey_task"] = true + player["raise_the_roof_task"] = true + player["take_your_pick_task"] = true + player["adventurers_log_task"] = true + player["arent_they_supposed_to_be_twins_task"] = true + player["log_a_rhythm_task"] = true + player["shellfish_roasting_on_an_open_fire_task"] = true + player["heavy_metal_task"] = true + player["bar_one_task"] = true + player["armed_and_dangerous_task"] = true + + assertTrue(player["on_your_way_task", false]) + } + + @Test + fun `You Can Bank on Us`() { + val player = createPlayer("adventurer", Tile(3208, 3220, 2)) + + val banker = npcs[Tile(3208, 3222, 2)].first { it.id.startsWith("banker") } + + player.npcOption(banker, "Talk-to") + tick(2) + player.dialogueContinue() + player.dialogueOption("line5") + player.dialogueContinue() + player.dialogueOption("line1") + player.dialogueContinue() + + assertTrue(player["you_can_bank_on_us_task", false]) + assertTrue(player.containsVarbit("task_reward_items", "red_dye")) + } + + @Test + fun `Hang on to Something`() { + val player = createPlayer("adventurer", Tile(3208, 3220, 2)) + player.inventory.add("coins", 1000) + val bank = objects[Tile(3208, 3221, 2), "bank_booth_lumbridge"]!! + + player.objectOption(bank, "Use-quickly") + tick(5) + player.interfaceOption("bank_side", "inventory", "Deposit-10", item = Item("coins"), slot = 0) + + assertTrue(player["hang_on_to_something_task", false]) + assertTrue(player.containsVarbit("task_reward_items", "magic_staff")) + } + + @Test + fun `Bovine Intervention`() { + setRandom(object : FakeRandom() { + override fun nextInt(until: Int) = until + }) + val player = createPlayer("adventurer", Tile(3257, 3260)) + val npc = npcs[Tile(3258, 3260)].first { it.id.startsWith("cow") } + + player.equipment.set(EquipSlot.Weapon.index, "dragon_longsword") + player.levels.set(Skill.Attack, 100) + player.levels.set(Skill.Strength, 100) + player.levels.set(Skill.Defence, 100) + + player.npcOption(npc, "Attack") + tick(10) + + assertTrue(player["bovine_intervention_task", false]) + } + + @Test + fun `Tan Your Hide`() { + val player = createPlayer("adventurer", Tile(3276, 3192)) + val npc = npcs[Tile(3276, 3193)].first { it.id == "ellis" } + + player.inventory.add("cowhide", "coins") + + player.npcOption(npc, "Trade") + tick() + player.interfaceOption("tanner", "cowhide", "Tan ${Colours.ORANGE.toTag()}1") + + assertTrue(player["tan_your_hide_task", false]) + } + + @Test + fun `Handi-crafts`() { + val player = createPlayer("adventurer", Tile(3208, 3220, 2)) + + player.inventory.add("leather", "needle", "thread") + + player.itemOnItem(0, 1) + tick() + player.dialogueOption(id = "dialogue_skill_creation", component = "choice1") + tick(2) + + assertTrue(player["handicrafts_task", false]) + } + + @Test + fun `Handy Dandy`() { + val player = createPlayer("adventurer") + player.inventory.add("leather_gloves") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("leather_gloves"), 0) + + assertTrue(player["handy_dandy_task", false]) + } + + @Test + fun `Just Can't Get the Staff`() { + val player = createPlayer("adventurer") + player.inventory.add("staff_of_air") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("staff_of_air"), 0) + + assertTrue(player["just_cant_get_the_staff_task", false]) + } + + @Test + fun `Click Your Heels Three Times`() { + val player = createPlayer("adventurer") + + player.interfaceOption("modern_spellbook", "lumbridge_home_teleport", "Cast") + + tick(19) + + assertTrue(player["click_your_heels_three_times_task", false]) + } + + @Test + fun `Reach Out and Touch Someone`() { + val player = createPlayer("adventurer") + player.inventory.add("shortbow") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("shortbow"), 0) + + assertTrue(player["reach_out_and_touch_someone_task", false]) + } + + @Test + fun `Death From Above`() = runTest { + val player = createPlayer("adventurer", Tile(3211, 3253)) + player.inventory.add("air_rune", "mind_rune") + + val npc = npcs[player.tile.zone].first { it.id == "magic_dummy" } + + player.instructions.send(InteractInterfaceNPC(npc.index, 192, 25, -1, -1)) + tick(1) + + assertTrue(player["death_from_above_task", false]) + } + + @Test + fun `Om Nom Nom Nom`() { + val player = createPlayer("adventurer") + player.levels.set(Skill.Constitution, 12) + player.inventory.add("crayfish") + + player.itemOption("Eat", "crayfish") + + assertTrue(player["om_nom_nom_nom_task", false]) + } + + @Test + fun `On the Level`() { + val player = createPlayer("adventurer") + + player.exp(Skill.Ranged, 1358.0) + + assertTrue(player["on_the_level_task", false]) + } + + @Test + fun `So That's What Ess Stands For`() { + val player = createPlayer("adventurer", Tile(2893, 4846)) + player.levels.set(Skill.Mining, 100) + player.inventory.add("bronze_pickaxe") + val essence = objects[Tile(2891, 4847), "rune_essence_rocks"]!! + + player.objectOption(essence, "Mine") + tick(9) + + assertTrue(player["so_thats_what_ess_stands_for_task", false]) + } + + @Test + fun `Air Craft`() { + val player = createPlayer("player", Tile(2844, 4832)) + player.levels.set(Skill.Runecrafting, 99) + player.inventory.add("rune_essence") + + val altar = objects[Tile(2843, 4833 ), "air_altar"]!! + player.objectOption(altar, "Craft-rune") + tick(2) + + assertTrue(player["air_craft_task", false]) + } + + @Test + fun `Greasing the Wheels of Commerce`() { + val player = createPlayer("shopper", Tile(3214, 3242)) + val npc = npcs[Tile(3214, 3243)].first { it.id == "shop_assistant_lumbridge"} + player.inventory.add("bronze_dagger", 1) + + player.npcOption(npc, "Trade") + tick() + player.interfaceOption("shop_side", "inventory", "Sell 1", item = Item("bronze_dagger"), slot = 0) + + assertTrue(player["greasing_the_wheels_of_commerce_task", false]) + } + + @Test + fun `I Wonder If It'll Sprout`() { + val player = createPlayer("adventurer") + player.inventory.add("bones") + + player.interfaceOption("inventory", "inventory", "Bury", 0, Item("bones"), 0) + + assertTrue(player["i_wonder_if_itll_sprout_task", false]) + } + + @Test + fun `Put Your Hands Together For`() { + val player = createPlayer("player") + + player.interfaceOption("prayer_list", "regular_prayers", optionIndex = 0, slot = 0) + + assertTrue(player["put_your_hands_together_for_task", false]) + } + + @Test + fun `Prayer Point Power`() { + val player = createPlayer("player", Tile(3244, 3207)) + player.levels.drain(Skill.Prayer, 1) + + val altar = objects[Tile(3243, 3206), "prayer_altar_lumbridge"]!! + player.objectOption(altar, "Pray") + tick() + + assertTrue(player["prayer_point_power_task", false]) + } + + @Test + fun `Not What We Mean By Irony`() { + val player = createPlayer("adventurer") + player.inventory.add("iron_dagger") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("iron_dagger"), 0) + + assertTrue(player["not_what_we_mean_by_irony_task", false]) + } + + @Test + fun `Alls Ferrous in Love and War`() { + val player = createPlayer("adventurer") + player.inventory.add("iron_boots") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("iron_boots"), 0) + + assertTrue(player["alls_ferrous_in_love_and_war_task", false]) + } + + @Test + fun `First Blood`() { + val player = createPlayer("adventurer") + + player.exp(Skill.Attack, 388.0) + player.exp(Skill.Defence, 388.0) + + assertTrue(player["first_blood_task", false]) + } + + @Test + fun `Temper Temper`() { + val player = createPlayer("adventurer") + player.levels.set(Skill.Attack, 5) + player.inventory.add("steel_sword") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("steel_sword"), 0) + + assertTrue(player["temper_temper_task", false]) + } + + @Test + fun `Steel Yourself For Combat`() { + val player = createPlayer("adventurer") + player.levels.set(Skill.Defence, 5) + player.inventory.add("steel_platebody") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("steel_platebody"), 0) + + assertTrue(player["steel_yourself_for_combat_task", false]) + } + + @Test + fun `Ammo Ammo Ammo`() { + val player = createPlayer("adventurer") + player.inventory.add("iron_arrow") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("iron_arrow"), 0) + + assertTrue(player["ammo_ammo_ammo_task", false]) + } + + @Test + fun `Take a Bow`() { + val player = createPlayer("adventurer") + player.inventory.add("shortbow") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("shortbow"), 0) + + assertTrue(player["take_a_bow_task", false]) + } + + @Test + fun `Don't Bury This One`() { + val player = createPlayer("adventurer") + + player.inventory.add("iron_hatchet") + + assertTrue(player["dont_bury_this_one_task", false]) + } + + @Test + fun `Mace Invaders`() { + val player = createPlayer("adventurer", Tile(3228, 3254)) + player.levels.set(Skill.Smithing, 2) + player.inventory.add("bronze_bar", "hammer") + + val anvil = objects[Tile(3229, 3254), "anvil_lumbridge"]!! + player.itemOnObject(anvil, 0, "") + tick() + player.interfaceOption("smithing", "mace_1") + tick(3) + + + assertTrue(player["mace_invaders_task", false]) + } + + @Test + fun `Capital Protection, What?`() { + val player = createPlayer("adventurer", Tile(3228, 3254)) + player.levels.set(Skill.Smithing, 7) + player.inventory.add("bronze_bar", "bronze_bar", "hammer") + + val anvil = objects[Tile(3229, 3254), "anvil_lumbridge"]!! + player.itemOnObject(anvil, 0, "") + tick() + player.interfaceOption("smithing", "full_helm_1") + tick(3) + + + assertTrue(player["capital_protection_what_task", false]) + } + + @Test + fun `Hack and Smash`() { + val player = createPlayer("adventurer") + + player.exp(Skill.Mining, 512.0) + + assertTrue(player["hack_and_smash_task", false]) + } + + @Test + fun `Shrimpin' Ain't Easy`() { + val player = createPlayer("adventurer", Tile(3245, 3155)) + player.levels.set(Skill.Fishing, 20) + val fishingSpot = createNPC("fishing_spot_small_net_bait_lumbridge", Tile(3246, 3155)) + player.inventory.add("small_fishing_net") + + player.npcOption(fishingSpot, "Net") + tick(7) + + assertTrue(player["shrimpin_aint_easy_task", false]) + } + + @Test + fun `The Fruit of the Sea`() { + val player = createPlayer("shopper", Tile(3194, 3254)) + val npc = npcs[Tile(3195, 3254)].first { it.id == "hank" } + player.inventory.add("raw_shrimps") + + player.npcOption(npc, "Trade") + tick() + player.interfaceOption("shop_side", "inventory", "Sell 1", item = Item("raw_shrimps"), slot = 0) + + assertTrue(player["the_fruit_of_the_sea_task", false]) + } + + @Test + fun `Made For Walking`() { + val player = createPlayer("adventurer", Tile(3208, 3220, 2)) + player.levels.set(Skill.Crafting, 7) + player.inventory.add("leather", "needle", "thread") + + player.itemOnItem(0, 1) + tick() + player.dialogueOption(id = "dialogue_skill_creation", component = "choice2") + tick(2) + + assertTrue(player["made_for_walking_task", false]) + } + + @Test + fun `Did Anyone Bring Any Toast`() { + val player = createPlayer("adventurer", Tile(3086, 3230)) + player.levels.set(Skill.Fishing, 5) + val fishingSpot = createNPC("fishing_spot_small_net_bait_draynor", Tile(3085, 3230)) + player.inventory.add("fishing_rod", "fishing_bait") + + player.npcOption(fishingSpot, "Bait") + tick(7) + + assertTrue(player["did_anyone_bring_any_toast_task", false]) + } + + @Test + fun `It's Not a Red One`() { + val player = createPlayer("adventurer", Tile(3079, 3444)) + player.levels.set(Skill.Cooking, 100) + player.inventory.add("raw_herring") + val fire = objects[Tile(3079, 3445), "fire_orange"]!! + + player.itemOnObject(fire, 0, "") + tick(4) + + assertTrue(player["its_not_a_red_one_task", false]) + } + + @Test + fun `Not So Confusing After All`() = runTest { + val player = createPlayer("adventurer", Tile(3211, 3253)) + player.levels.set(Skill.Magic, 3) + player.inventory.add("water_rune", 3) + player.inventory.add("earth_rune", 2) + player.inventory.add("body_rune") + + val npc = npcs[player.tile.zone].first { it.id == "magic_dummy" } + + player.instructions.send(InteractInterfaceNPC(npc.index, 192, 26, -1, -1)) + tick(1) + + assertTrue(player["not_so_confusing_after_all_task", false]) + } + + @Test + fun `Heart of Oak`() { + val player = createPlayer("adventurer") + player.levels.set(Skill.Ranged, 5) + player.inventory.add("oak_longbow") + + player.interfaceOption("inventory", "inventory", "Wield", 1, Item("oak_longbow"), 0) + + assertTrue(player["heart_of_oak_task", false]) + } + + @Test + fun `Get the Point`() { + setRandom(object : FakeRandom() { + override fun nextInt(from: Int, until: Int) = until / 2 + + override fun nextBits(bitCount: Int) = 100 + }) + val player = createPlayer("player", Tile(3206, 3205)) + val npc = npcs[Tile(3206, 3204)].first { it.id == "rat" } + + player.levels.set(Skill.Ranged, 50) + player.equipment.set(EquipSlot.Weapon.index, "magic_shortbow") + player.equipment.set(EquipSlot.Ammo.index, "steel_arrow", 100) + + player.npcOption(npc, "Attack") + tick(20) + + assertTrue(player["get_the_point_task", false]) + } + + @Test + fun `Berry Tasty`() { + val player = createPlayer("adventurer", Tile(3231, 3197)) + player.levels.set(Skill.Cooking, 10) + player.inventory.add("uncooked_berry_pie") + + val oven = objects[Tile(3230, 3196), "cooking_range_lumbridge"]!! + player.itemOnObject(oven, 0, "") + tick(4) + + assertTrue(player["berry_tasty_task", false]) + } + + @Test + fun `Dish water`() { + val player = createPlayer("adventurer", Tile(3231, 3197)) + player.inventory.add("beer") + + player.itemOption("Drink", "beer") + + assertTrue(player["dishwater_task", false]) + } + + @Test + fun `Quarter Centurion`() { + val player = createPlayer("adventurer") + + player.exp(Skill.Attack, 8740.0) + + assertTrue(player["quarter_centurion_task", false]) + } + + @Test + fun `Fledgeling Adventurer`() { + val player = createPlayer("adventurer") + + player["quest_points"] = 5 + + assertTrue(player["fledgeling_adventurer_task", false]) + } + + @Test + fun `Hail to the Duke, Baby`() { + val player = createPlayer("adventurer", Tile(3211, 3220, 1)) + val duke = npcs[Tile(3212, 3220, 1)].first { it.id == "duke_horacio" } + + player.npcOption(duke, "Talk-to") + tick() + + assertTrue(player["hail_to_the_duke_baby_task", false]) + } + + @Test + fun `Window Shopping`() { + val player = createPlayer("shopper", Tile(3215, 3243)) + val npc = npcs[Tile(3214, 3243)].first { it.id == "shop_assistant_lumbridge" } + + player.npcOption(npc, "Trade") + tick() + + assertTrue(player["window_shopping_task", false]) + } + + @Test + fun `Wait, That's Not a Sheep`() { + val player = createPlayer("adventurer") + + player.tele(3189, 3275) + tick() + + assertTrue(player["wait_thats_not_a_sheep_task", false]) + } + + @Test + fun `In the Countyard`() { + val player = createPlayer("adventurer", Tile(3109, 3330)) + + player.walk(Tile(3109, 3331)) + tick(2) + + assertTrue(player["in_the_countyard_task", false]) + } + + @Test + fun `Beware of Pigzilla`() { + val player = createPlayer("adventurer", Tile(3081, 3258)) + + player.walk(Tile(3081, 3257)) + tick(2) + + assertTrue(player["beware_of_pigzilla_task", false]) + } + + @Test + fun `Tower Power`() { + val player = createPlayer("adventurer", Tile(3104, 3161, 1)) + + val stairs = objects[Tile(3103, 3159, 1), "wizards_tower_staircase"]!! + player.objectOption(stairs, "Climb-up") + tick(2) + + assertTrue(player["tower_power_task", false]) + } + + @Test + fun `Tinkle the Ivories`() { + val player = createPlayer("adventurer", Tile(3243, 3213)) + + val stairs = objects[Tile(3243, 3214), "lumbridge_organ"]!! + player.objectOption(stairs, "Play") + tick() + + assertTrue(player["tinkle_the_ivories_task", false]) + } + + @Test + fun `Passing Out`() { + val player = createPlayer("adventurer", Tile(3267, 3227)) + + val guard = npcs[Tile(3267, 3226)].first { it.id == "border_guard_al_kharid" } + player.npcOption(guard, "Talk-to") + tick() + player.dialogueContinue(2) + player.dialogueOption("line1") + player.dialogueContinue() + + assertTrue(player["passing_out_task", false]) + } + + @Test + fun `What is This Place`() { + val player = createPlayer("adventurer", Tile(3104, 9571)) + + val guard = npcs[Tile(3103, 9571)].first { it.id == "sedridor" } + player.npcOption(guard, "Teleport") + tick(2) + + assertTrue(player["what_is_this_place_task", false]) + } + +} \ No newline at end of file diff --git a/game/src/test/kotlin/world/gregs/voidps/world/activity/skill/MiningTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/activity/skill/MiningTest.kt index 759822b554..f59287445c 100644 --- a/game/src/test/kotlin/world/gregs/voidps/world/activity/skill/MiningTest.kt +++ b/game/src/test/kotlin/world/gregs/voidps/world/activity/skill/MiningTest.kt @@ -31,5 +31,4 @@ internal class MiningTest : WorldTest() { assertNotEquals(rocks.id, objects.getLayer(tile, ObjectLayer.GROUND)?.id) } - } \ No newline at end of file diff --git a/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/combat/magic/spell/MagicSpellTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/combat/magic/spell/MagicSpellTest.kt index 5cb148b7ec..254f4190ad 100644 --- a/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/combat/magic/spell/MagicSpellTest.kt +++ b/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/combat/magic/spell/MagicSpellTest.kt @@ -6,17 +6,19 @@ import org.koin.core.context.startKoin import org.koin.core.context.stopKoin import org.koin.dsl.module import org.koin.test.KoinTest +import world.gregs.voidps.cache.definition.data.FontDefinition import world.gregs.voidps.cache.definition.data.InterfaceComponentDefinition import world.gregs.voidps.cache.definition.data.InterfaceDefinition import world.gregs.voidps.cache.definition.data.ItemDefinition import world.gregs.voidps.engine.client.ui.Interfaces +import world.gregs.voidps.engine.data.definition.FontDefinitions import world.gregs.voidps.engine.data.definition.InterfaceDefinitions import world.gregs.voidps.engine.data.definition.InventoryDefinitions import world.gregs.voidps.engine.data.definition.ItemDefinitions import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.entity.character.player.skill.level.PlayerLevels import world.gregs.voidps.engine.entity.item.Item -import world.gregs.voidps.engine.inv.* +import world.gregs.voidps.engine.inv.Inventories import world.gregs.voidps.engine.inv.restrict.NoRestrictions import world.gregs.voidps.engine.inv.stack.ItemStackingRule @@ -25,6 +27,7 @@ abstract class MagicSpellTest : KoinTest { private lateinit var itemDefinitions: ItemDefinitions private lateinit var inventoryDefinitions: InventoryDefinitions protected lateinit var interfaceDefinitions: InterfaceDefinitions + private lateinit var fontDefinitions: FontDefinitions private var information: Array = Array(16) { 0 } private val itemDefs = Array(100) { ItemDefinition.EMPTY } private val itemIds: MutableMap = mutableMapOf() @@ -45,10 +48,12 @@ abstract class MagicSpellTest : KoinTest { inventoryDefinitions.ids = emptyMap() itemDefinitions = ItemDefinitions(itemDefs) itemDefinitions.ids = itemIds + fontDefinitions = FontDefinitions(arrayOf(FontDefinition(0, (0..200).map { 1.toByte() }.toByteArray()))).apply { ids = mapOf("p12_full" to 0) } startKoin { modules(module { single { itemDefinitions } single { interfaceDefinitions } + single { fontDefinitions } }) } } @@ -76,7 +81,7 @@ abstract class MagicSpellTest : KoinTest { val (item, def) = items[index] information[8 + index * 2] = itemId information[9 + index * 2] = item.amount - addItemDef(if(def == ItemDefinition.EMPTY) ItemDefinition(stringId = item.id) else def) + addItemDef(if (def == ItemDefinition.EMPTY) ItemDefinition(stringId = item.id) else def) } } diff --git a/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/effect/HitpointRestorationTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/effect/HitpointRestorationTest.kt index 189e9f6ea4..68b903c092 100644 --- a/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/effect/HitpointRestorationTest.kt +++ b/game/src/test/kotlin/world/gregs/voidps/world/interact/entity/player/effect/HitpointRestorationTest.kt @@ -51,11 +51,11 @@ internal class HitpointRestorationTest : WorldTest() { fun `Hitpoints shouldn't restore if dead`() { val player = createPlayer("player") player.experience.set(Skill.Constitution, Level.experience(Skill.Constitution, 990)) - player.levels.set(Skill.Constitution, 990) + player.levels.set(Skill.Constitution, 980) val drained = player.levels.drain(Skill.Constitution, 990) + assertEquals(-980, drained) assertTrue(player.softTimers.contains("restore_hitpoints")) - assertEquals(-990, drained) assertEquals(0, player.levels.get(Skill.Constitution)) tick(11) assertFalse(player.softTimers.contains("restore_hitpoints")) diff --git a/game/src/test/kotlin/world/gregs/voidps/world/script/WorldTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/script/WorldTest.kt index 0b5c8e8e14..a6ae9268b4 100644 --- a/game/src/test/kotlin/world/gregs/voidps/world/script/WorldTest.kt +++ b/game/src/test/kotlin/world/gregs/voidps/world/script/WorldTest.kt @@ -12,6 +12,7 @@ import org.koin.dsl.module import org.koin.fileProperties import org.koin.test.KoinTest import world.gregs.voidps.FakeRandom +import world.gregs.voidps.Main import world.gregs.voidps.cache.Cache import world.gregs.voidps.cache.Index import world.gregs.voidps.cache.MemoryCache @@ -51,6 +52,8 @@ import world.gregs.voidps.script.loadScripts import world.gregs.voidps.type.Tile import world.gregs.voidps.type.setRandom import world.gregs.voidps.world.interact.world.spawn.loadItemSpawns +import world.gregs.voidps.world.interact.world.spawn.loadNpcSpawns +import world.gregs.voidps.world.interact.world.spawn.loadObjectSpawns import java.io.File import kotlin.system.measureTimeMillis @@ -73,6 +76,8 @@ abstract class WorldTest : KoinTest { val extraProperties: MutableMap = mutableMapOf() + open var loadNpcs: Boolean = false + fun tick(times: Int = 1) = runBlocking(Contexts.Game) { repeat(times) { GameLoop.tick++ @@ -125,7 +130,15 @@ abstract class WorldTest : KoinTest { return objects.add(id, tile, shape, rotation) } - fun createFloorItem(id: String, tile: Tile = Tile.EMPTY, amount: Int = 1, revealTicks: Int = FloorItems.NEVER, disappearTicks: Int = FloorItems.NEVER, charges: Int = 0, owner: Player? = null): FloorItem { + fun createFloorItem( + id: String, + tile: Tile = Tile.EMPTY, + amount: Int = 1, + revealTicks: Int = FloorItems.NEVER, + disappearTicks: Int = FloorItems.NEVER, + charges: Int = 0, + owner: Player? = null + ): FloorItem { return floorItems.add(tile, id, amount, revealTicks, disappearTicks, charges, owner) } @@ -133,6 +146,7 @@ abstract class WorldTest : KoinTest { @BeforeAll fun beforeAll() { + Main.name = "test" stopKoin() startKoin { printLogger(Level.ERROR) @@ -163,9 +177,11 @@ abstract class WorldTest : KoinTest { single { objectCollisionAdd } single { objectCollisionAdd } single { objectCollisionRemove } - single { Hunting(get(), get(), get(), get(), get(), get(), object : FakeRandom() { - override fun nextBits(bitCount: Int) = 0 - }) } + single { + Hunting(get(), get(), get(), get(), get(), get(), object : FakeRandom() { + override fun nextBits(bitCount: Int) = 0 + }) + } }) } loadScripts() @@ -209,6 +225,10 @@ abstract class WorldTest : KoinTest { @BeforeEach fun beforeEach() { loadItemSpawns(floorItems, get()) + if (loadNpcs) { + loadNpcSpawns(npcs) + } + loadObjectSpawns(objects) setRandom(FakeRandom()) } @@ -250,7 +270,7 @@ abstract class WorldTest : KoinTest { private val objectCollisionAdd: GameObjectCollisionAdd by lazy { GameObjectCollisionAdd(collisions) } private val objectCollisionRemove: GameObjectCollisionRemove by lazy { GameObjectCollisionRemove(collisions) } private val gameObjects: GameObjects by lazy { GameObjects(objectCollisionAdd, objectCollisionRemove, ZoneBatchUpdates(), objectDefinitions, storeUnused = true) } - private val mapDefinitions: MapDefinitions by lazy { MapDefinitions(CollisionDecoder( collisions), objectDefinitions, gameObjects, cache).loadCache() } + private val mapDefinitions: MapDefinitions by lazy { MapDefinitions(CollisionDecoder(collisions), objectDefinitions, gameObjects, cache).loadCache() } private val fontDefinitions: FontDefinitions by lazy { FontDefinitions(FontDecoder().load(cache)).load() } val emptyTile = Tile(2655, 4640) } diff --git a/game/src/test/resources/test.properties b/game/src/test/resources/test.properties index 9b8176999f..bdfecc8e09 100644 --- a/game/src/test/resources/test.properties +++ b/game/src/test/resources/test.properties @@ -25,6 +25,7 @@ animationDefinitionsPath=../data/definitions/animations.yml graphicDefinitionsPath=../data/definitions/graphics.yml inventoryDefinitionsPath=../data/definitions/inventories.yml soundDefinitionsPath=../data/definitions/sounds.yml +questDefinitionsPath=../data/definitions/quests.yml renderEmoteDefinitionsPath=../data/definitions/render-emotes.yml midiDefinitionsPath=../data/definitions/midis.yml jingleDefinitionsPath=../data/definitions/jingles.yml @@ -34,6 +35,7 @@ patrolDefinitionsPath=../data/definitions/patrols.yml prayerDefinitionsPath=../data/definitions/prayers.yml gearDefinitionsPath=../data/definitions/gear-sets.yml enumDefinitionsPath=../data/definitions/enums.yml +structDefinitionsPath=../data/definitions/structs.yml fontDefinitionsPath=../data/definitions/fonts.yml weaponStyleDefinitionsPath=../data/definitions/weapon-styles.yml weaponAnimationDefinitionsPath=../data/definitions/weapon-animations.yml diff --git a/network/src/main/kotlin/world/gregs/voidps/network/client/instruction/Walk.kt b/network/src/main/kotlin/world/gregs/voidps/network/client/instruction/Walk.kt index e709f6d7f6..7d242cd36e 100644 --- a/network/src/main/kotlin/world/gregs/voidps/network/client/instruction/Walk.kt +++ b/network/src/main/kotlin/world/gregs/voidps/network/client/instruction/Walk.kt @@ -2,4 +2,4 @@ package world.gregs.voidps.network.client.instruction import world.gregs.voidps.network.client.Instruction -data class Walk(val x: Int, val y: Int) : Instruction \ No newline at end of file +data class Walk(val x: Int, val y: Int, val minimap: Boolean = false) : Instruction \ No newline at end of file diff --git a/network/src/main/kotlin/world/gregs/voidps/network/client/instruction/WorldMapClick.kt b/network/src/main/kotlin/world/gregs/voidps/network/client/instruction/WorldMapClick.kt new file mode 100644 index 0000000000..f0bfbb5251 --- /dev/null +++ b/network/src/main/kotlin/world/gregs/voidps/network/client/instruction/WorldMapClick.kt @@ -0,0 +1,5 @@ +package world.gregs.voidps.network.client.instruction + +import world.gregs.voidps.network.client.Instruction + +data class WorldMapClick(val tile: Int) : Instruction \ No newline at end of file diff --git a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/Decoders.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/Decoders.kt index 778ea8f5a8..5124e18266 100644 --- a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/Decoders.kt +++ b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/Decoders.kt @@ -78,7 +78,7 @@ fun decoders(huffman: Huffman): Array { array[67] = HyperlinkDecoder() array[75] = LobbyOnlineStatusDecoder() array[30] = LobbyWorldListRefreshDecoder() - array[58] = WorldMapCloseDecoder() + array[58] = WorldMapClickDecoder() array[74] = ClanChatRankDecoder() array[77] = ReflectionResponseDecoder() array[76] = SecondaryTeleportDecoder() diff --git a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WalkMiniMapDecoder.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WalkMiniMapDecoder.kt index 6272bffcda..7c179a66cb 100644 --- a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WalkMiniMapDecoder.kt +++ b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WalkMiniMapDecoder.kt @@ -23,7 +23,7 @@ class WalkMiniMapDecoder : Decoder(18) { packet.readShort()//X in region? packet.readShort()//Y in region? packet.readByte()//63 - return Walk(x, y) + return Walk(x, y, minimap = true) } } \ No newline at end of file diff --git a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapClickDecoder.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapClickDecoder.kt new file mode 100644 index 0000000000..ff034cf4da --- /dev/null +++ b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapClickDecoder.kt @@ -0,0 +1,11 @@ +package world.gregs.voidps.network.login.protocol.decode + +import io.ktor.utils.io.core.* +import world.gregs.voidps.network.client.instruction.WorldMapClick +import world.gregs.voidps.network.login.protocol.Decoder + +class WorldMapClickDecoder : Decoder(4) { + + override suspend fun decode(packet: ByteReadPacket) = WorldMapClick(packet.readInt()) + +} \ No newline at end of file diff --git a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapCloseDecoder.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapCloseDecoder.kt deleted file mode 100644 index 6f2a4658ae..0000000000 --- a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapCloseDecoder.kt +++ /dev/null @@ -1,14 +0,0 @@ -package world.gregs.voidps.network.login.protocol.decode - -import io.ktor.utils.io.core.* -import world.gregs.voidps.network.client.Instruction -import world.gregs.voidps.network.login.protocol.Decoder - -class WorldMapCloseDecoder : Decoder(4) { - - override suspend fun decode(packet: ByteReadPacket): Instruction? { - packet.readInt() - return null - } - -} \ No newline at end of file diff --git a/network/src/test/kotlin/world/gregs/voidps/network/login/protocol/DecoderTest.kt b/network/src/test/kotlin/world/gregs/voidps/network/login/protocol/DecoderTest.kt index 9978de74af..0177fc8d4f 100644 --- a/network/src/test/kotlin/world/gregs/voidps/network/login/protocol/DecoderTest.kt +++ b/network/src/test/kotlin/world/gregs/voidps/network/login/protocol/DecoderTest.kt @@ -107,11 +107,11 @@ class DecoderTest { null, // 84 null, // 71 Walk(1234, 4321), // 35 - Walk(1234, 4321), // 82 + Walk(1234, 4321, minimap = true), // 82 null, // 49 null, // 8 null, // 52 - null, // 58 + WorldMapClick(tile = 12345), // 58 ).mapIndexed { index, expected -> val (id, data) = packets[index] dynamicTest("Test ${if (expected != null) expected::class.simpleName else "Packet $id"} decoder") { diff --git a/tools/src/main/kotlin/world/gregs/voidps/tools/cache/DumpSprites.kt b/tools/src/main/kotlin/world/gregs/voidps/tools/cache/DumpSprites.kt index 1ca78722fe..f0a634315c 100644 --- a/tools/src/main/kotlin/world/gregs/voidps/tools/cache/DumpSprites.kt +++ b/tools/src/main/kotlin/world/gregs/voidps/tools/cache/DumpSprites.kt @@ -14,14 +14,15 @@ object DumpSprites { val cache: Cache = CacheDelegate(property("cachePath")) val decoder = SpriteDecoder().load(cache) println(decoder.lastIndex) - File("./sprites/").mkdir() + val directory = File("./temp/sprites/") + directory.mkdir() for (i in decoder.indices) { val def = decoder.getOrNull(i) ?: continue println("Sprite $i ${def.sprites?.size}") val sprites = def.sprites ?: continue for ((index, sprite) in sprites.withIndex()) { if (sprite.width > 0 && sprite.height > 0) { - ImageIO.write(sprite.toBufferedImage(), "png", File("./sprites/${i}_${index}.png")) + ImageIO.write(sprite.toBufferedImage(), "png", directory.resolve("${i}_${index}.png")) } } }