From a00bce8c2fbbbcee0df7ceab61869cd09e505922 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 20 May 2024 15:20:51 +0100 Subject: [PATCH 01/48] Fix drop ids --- data/spawns/drops.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/spawns/drops.yml b/data/spawns/drops.yml index a297a7764..da5f3fc81 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 From 5bd78ad669ceeec797a3632b651412002001f8a0 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 21 May 2024 00:26:44 +0100 Subject: [PATCH 02/48] Start adding main and tab interfaces --- data/definitions/enums.yml | 16 ++- data/definitions/interfaces.yml | 26 ++++- data/definitions/parameters.yml | 92 +++++++-------- data/definitions/scripts.yml | 9 +- data/definitions/variables-client.yml | 28 ++++- data/definitions/variables-player-bit.yml | 77 ++++++++++++- data/map/areas.yml | 8 ++ .../world/activity/achievement/TaskList.kts | 107 ++++++++++++++++++ .../world/activity/achievement/TaskSystem.kts | 55 ++++++++- 9 files changed, 363 insertions(+), 55 deletions(-) create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskList.kts diff --git a/data/definitions/enums.yml b/data/definitions/enums.yml index 751c33d2e..50022717d 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/interfaces.yml b/data/definitions/interfaces.yml index e5a05c325..ca4bf51be 100644 --- a/data/definitions/interfaces.yml +++ b/data/definitions/interfaces.yml @@ -2319,6 +2319,28 @@ 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 + tasks: + id: 94 + options: + Summary: 0 + Pin: 1 dialogue_make_amount: id: 944 type: dialogue_box @@ -2540,9 +2562,11 @@ 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 warriors_guild: 1057 fade_out: id: 120 diff --git a/data/definitions/parameters.yml b/data/definitions/parameters.yml index 95a999ccc..d992797f1 100644 --- a/data/definitions/parameters.yml +++ b/data/definitions/parameters.yml @@ -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_selectable_1: 1282 +task_selectable_2: 1283 +task_selectable_3: 1284 +task_selectable_4: 1285 +task_selectable_5: 1286 +task_selectable_6: 1287 +task_members: 1290 +task_group: 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/scripts.yml b/data/definitions/scripts.yml index d3eaddd3e..f7346a1d4 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,7 @@ 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 diff --git a/data/definitions/variables-client.yml b/data/definitions/variables-client.yml index a28348503..90510cffa 100644 --- a/data/definitions/variables-client.yml +++ b/data/definitions/variables-client.yml @@ -369,4 +369,30 @@ 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_disable_popups: + id: 1429 + format: boolean + persist: true +task_unknown1: + id: 1428 + format: int + persist: true +task_unknown2: + id: 1416 + format: int + persist: true +task_unknown3: + id: 1425 + format: int + persist: true \ No newline at end of file diff --git a/data/definitions/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index d2a2b5e80..9b8b9bcd4 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -648,4 +648,79 @@ scrying_orb_wizard_distentor: id: 2318 format: boolean persist: true - transmit: false \ No newline at end of file + transmit: false +task_pin_1: + id: 8587 + format: int + persist: true +task_pin_2: + id: 8588 + format: int + persist: true +task_pin_3: + id: 8589 + format: int + persist: true +task_pin_4: + id: 8590 + format: int + persist: true +task_pin_5: + id: 8591 + format: int + persist: true +task_pin_6: + id: 8592 + format: int + persist: true +task_pins: + id: 8577 + format: bitwise + persist: true + values: [ 1, 2, 3, 4, 5, 6 ] +task_area: + id: 8575 + format: map + default: lumbridge_draynor + 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 + persist: true +task_list_area: + id: 8582 + format: map + persist: true + default: dnd_activities + values: + dnd_activities: 0 + lumbridge_draynor: 1 + varrock: 2 + falador: 3 + seers_village: 4 + ardougne: 5 + karamja: 6 + fremennik: 7 +task_hide_completed: + id: 8579 + format: boolean + persist: true +unknown1: + id: 8576 + format: int + persist: true +task_filter_sets: + id: 8580 + format: boolean + persist: true diff --git a/data/map/areas.yml b/data/map/areas.yml index 93f8a98d3..2e9791283 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 ] 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 000000000..db88cbeac --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskList.kts @@ -0,0 +1,107 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.client.sendScript +import world.gregs.voidps.engine.client.ui.event.interfaceOpen +import world.gregs.voidps.engine.client.ui.interfaceOption +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.player.Player +import world.gregs.voidps.engine.inject + +val variables: VariableDefinitions by inject() + +interfaceOpen("task_list") { player -> + refresh(player) + player.sendVariable("task_progress_overall") + player.sendVariable("task_hide_completed") + player.sendVariable("task_filter_sets") + player.sendVariable("task_disable_popups") +} + +interfaceOption("Select", "area_*", "task_list") { + player["task_list_area"] = component.removePrefix("area_") + refresh(player) +} + +/* + dnds=3002..3034 + unstable foundations=3500..3522 + varrock=256..345 + + */ +interfaceOption("Summary", "tasks", "task_list") { + player["selected_task"] = itemSlot / 4 +} + +interfaceOption("Pin", "tasks", "task_list") { + pin(player, itemSlot / 4) +} + +interfaceOption("Pin", "pin", "task_list") { + pin(player, player["selected_task", 0]) +} + +val enumDefinitions: EnumDefinitions by inject() +val structDefinitions: StructDefinitions by inject() + +fun pin(player: Player, id: Int) { + val areaId = areaId(player) + var start = enumDefinitions.get("task_area_start_indices").getInt(areaId) + var count = 0 + var taskIndex = -1 + while (start != -1) { + val struct = enumDefinitions.get("task_structs").getInt(start) + val definition = structDefinitions.getOrNull(struct) ?: break + start = definition["task_next_index", -1] + if (definition["task_members", 0] == 1 && !World.members) { // TODO test if members tasks are displayed for f2p or not + count++ + continue + } + if (count++ == id) { + taskIndex = definition["task_index", -1] + break + } + } + if (taskIndex == -1) { + return // Task not found + } + var index = -1 + for (i in 1..6) { + if (!player.containsVarbit("task_pins", i)) { + index = i + break + } + if (player["task_pin_${i}", -1] == taskIndex) { + return // Already pinned + } + } + + if (index == -1) { + return // Too many pins + } + player.addVarbit("task_pins", index) + player["task_pin_${index}"] = taskIndex +} + +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") { + player["task_disable_popups"] = !player["task_disable_popups", false] +} + +fun refresh(player: Player) { + player.sendVariable("task_list_area") + val int = areaId(player) + player.sendScript("task_main_list_populate", int, 999, 999) + player.interfaceOptions.unlockAll("task_list", "tasks", 0..100) +} + +fun areaId(player: Player) = variables.get("task_list_area")!!.values.toInt(player["task_list_area", "dnd_activities"]) \ 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 1c12bc5e7..82310e710 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,61 @@ package world.gregs.voidps.world.activity.achievement +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.entity.character.mode.move.enterArea +import world.gregs.voidps.engine.entity.character.mode.move.exitArea + +interfaceOpen("task_system") { player -> + for (i in 1..6) { + if(player.contains("task_pin_$i")) { + player.sendVariable("task_pin_${i}") + } else { + player["task_pin_${i}"] = 4091 + } + } + if (player.contains("task_dont_show_again")) { + player.sendVariable("task_dont_show_again") + } + if (!player.contains("task_progress_total")) { + player["task_progress_total"] = 0 + } else { + player.sendVariable("task_progress_total") + } + player.sendVariable("task_pins") +} + +enterArea("lumbridge") { + player["task_area"] = "lumbridge_draynor" + player["task_progress_current"] = 0 + player["task_progress_total"] = 124 +} + +exitArea("lumbridge") { + player["task_area"] = "empty" +} + +enterArea("draynor") { + player["task_area"] = "lumbridge_draynor" +} + +exitArea("draynor") { + player["task_area"] = "empty" +} + +interfaceOption("Task System", "task_system", "toplevel*") { + // Hacky - It shouldn't be open to begin with + player.interfaces.sendVisibility("task_system", "summary_overlay", false) +} + +interfaceOption("Close", "close_hint", "task_system") { + player.interfaces.sendVisibility(id, "message_overlay", false) +} + +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") -} +} \ No newline at end of file From 5532318636e2fb7bd70e65f385965c10e34eebd4 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 21 May 2024 00:27:07 +0100 Subject: [PATCH 03/48] Add string scripts to command --- .../voidps/world/command/debug/InterfaceCommands.kts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 b11d969e0..7af676692 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 { 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") { From d03a247f98f9ff6b00f2fa506db65a5ab6f8e970 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 21 May 2024 00:27:24 +0100 Subject: [PATCH 04/48] Fix sending interface visibility component ids --- .../kotlin/world/gregs/voidps/engine/client/ui/Interfaces.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 875818bcc..a83871532 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 } From 4b09cfca87872b39c422bc7b968a545fd721c401 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 21 May 2024 00:27:43 +0100 Subject: [PATCH 05/48] Change sprite dump directory --- .../kotlin/world/gregs/voidps/tools/cache/DumpSprites.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 1ca78722f..f0a634315 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")) } } } From c61e1d3dbe7eda3f8f4df19936151b97c3092696 Mon Sep 17 00:00:00 2001 From: GregHib Date: Tue, 21 May 2024 22:29:37 +0100 Subject: [PATCH 06/48] Add task pinning --- data/definitions/variables-player-bit.yml | 40 +++---- .../world/activity/achievement/TaskList.kts | 72 ++++++------ .../world/activity/achievement/TaskSystem.kts | 105 +++++++++++++++--- .../voidps/world/activity/quest/Quests.kts | 1 + 4 files changed, 143 insertions(+), 75 deletions(-) diff --git a/data/definitions/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index 9b8b9bcd4..b90b3fb1c 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -649,39 +649,36 @@ scrying_orb_wizard_distentor: format: boolean persist: true transmit: false -task_pin_1: +task_slot_1: id: 8587 format: int - persist: true -task_pin_2: +task_slot_2: id: 8588 format: int - persist: true -task_pin_3: +task_slot_3: id: 8589 format: int - persist: true -task_pin_4: +task_slot_4: id: 8590 format: int - persist: true -task_pin_5: +task_slot_5: id: 8591 format: int - persist: true -task_pin_6: +task_slot_6: id: 8592 format: int +task_pinned: + id: 8576 + format: int persist: true -task_pins: +task_pin_index: id: 8577 - format: bitwise + format: int persist: true - values: [ 1, 2, 3, 4, 5, 6 ] task_area: id: 8575 format: map - default: lumbridge_draynor + default: empty values: dnd_activities: 0 lumbridge_draynor: 1 @@ -702,7 +699,7 @@ task_list_area: id: 8582 format: map persist: true - default: dnd_activities + default: unstable_foundations values: dnd_activities: 0 lumbridge_draynor: 1 @@ -712,15 +709,18 @@ task_list_area: ardougne: 5 karamja: 6 fremennik: 7 + unstable_foundations: 60 + empty: 61 + elsewhere: 63 task_hide_completed: id: 8579 format: boolean persist: true -unknown1: - id: 8576 - format: int - persist: true task_filter_sets: id: 8580 format: boolean persist: true +task_introducing_explorer_jack: + id: 6494 + format: int + persist: true 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 index db88cbeac..415e3a528 100644 --- 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 @@ -1,12 +1,13 @@ 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.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.player.Player import world.gregs.voidps.engine.inject @@ -25,12 +26,6 @@ interfaceOption("Select", "area_*", "task_list") { refresh(player) } -/* - dnds=3002..3034 - unstable foundations=3500..3522 - varrock=256..345 - - */ interfaceOption("Summary", "tasks", "task_list") { player["selected_task"] = itemSlot / 4 } @@ -46,43 +41,27 @@ interfaceOption("Pin", "pin", "task_list") { val enumDefinitions: EnumDefinitions by inject() val structDefinitions: StructDefinitions by inject() -fun pin(player: Player, id: Int) { - val areaId = areaId(player) - var start = enumDefinitions.get("task_area_start_indices").getInt(areaId) +fun id(player: Player, index: Int, area: Int = areaId(player)): Int? { + var next = enumDefinitions.get("task_area_start_indices").getInt(area) var count = 0 - var taskIndex = -1 - while (start != -1) { - val struct = enumDefinitions.get("task_structs").getInt(start) + while (next != -1) { + val struct = enumDefinitions.get("task_structs").getInt(next) val definition = structDefinitions.getOrNull(struct) ?: break - start = definition["task_next_index", -1] - if (definition["task_members", 0] == 1 && !World.members) { // TODO test if members tasks are displayed for f2p or not - count++ - continue - } - if (count++ == id) { - taskIndex = definition["task_index", -1] - break - } - } - if (taskIndex == -1) { - return // Task not found - } - var index = -1 - for (i in 1..6) { - if (!player.containsVarbit("task_pins", i)) { - index = i - break - } - if (player["task_pin_${i}", -1] == taskIndex) { - return // Already pinned + if (count++ == index) { + return next } + next = definition["task_next_index", -1] } + return null +} - if (index == -1) { - return // Too many pins +fun index(player: Player, id: Int): Int { + for (i in 0 until 6) { + if (player["task_slot_${i}", -1] == id) { + return i + } } - player.addVarbit("task_pins", index) - player["task_pin_${index}"] = taskIndex + return 1 } interfaceOption("Filter-sets", "filter_sets", "task_list") { @@ -104,4 +83,19 @@ fun refresh(player: Player) { player.interfaceOptions.unlockAll("task_list", "tasks", 0..100) } -fun areaId(player: Player) = variables.get("task_list_area")!!.values.toInt(player["task_list_area", "dnd_activities"]) \ No newline at end of file +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 = id(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"] = index(player, id) + } +} \ 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 82310e710..96dad357e 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 @@ -3,17 +3,26 @@ package world.gregs.voidps.world.activity.achievement 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 + + +val variables: VariableDefinitions by inject() +val enumDefinitions: EnumDefinitions by inject() +val structDefinitions: StructDefinitions by inject() interfaceOpen("task_system") { player -> - for (i in 1..6) { - if(player.contains("task_pin_$i")) { - player.sendVariable("task_pin_${i}") - } else { - player["task_pin_${i}"] = 4091 - } - } + player.sendVariable("task_introducing_explorer_jack") + player.sendVariable("task_pin_index") + player.sendVariable("task_pinned") + refreshSlots(player) if (player.contains("task_dont_show_again")) { player.sendVariable("task_dont_show_again") } @@ -22,7 +31,6 @@ interfaceOpen("task_system") { player -> } else { player.sendVariable("task_progress_total") } - player.sendVariable("task_pins") } enterArea("lumbridge") { @@ -32,7 +40,7 @@ enterArea("lumbridge") { } exitArea("lumbridge") { - player["task_area"] = "empty" + player["task_area"] = "dnd_activities" } enterArea("draynor") { @@ -40,22 +48,87 @@ enterArea("draynor") { } exitArea("draynor") { - player["task_area"] = "empty" -} - -interfaceOption("Task System", "task_system", "toplevel*") { - // Hacky - It shouldn't be open to begin with - player.interfaces.sendVisibility("task_system", "summary_overlay", false) + 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["selected_task"] = index + player["task_pins"] = 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") -} \ No newline at end of file +} + +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"] = index(player, index) ?: return@interfaceOption + player["task_pin_index"] = index + } +} + +fun index(player: Player, index: Int, areaId: Int = areaId(player)): Int? { + var start = enumDefinitions.get("task_area_start_indices").getInt(areaId) + var count = 1 + while (start != -1) { + val struct = enumDefinitions.get("task_structs").getInt(start) + val definition = structDefinitions.getOrNull(struct) ?: break + val current = start + start = definition["task_next_index", -1] + if (definition["task_members", 0] == 1 && !World.members) { // TODO test if members tasks are displayed for f2p or not + count++ + continue + } + if (count == index) { + return current + } + count++ + } + return null +} + +variableSet("task_pin_index", "task_area") { player -> + refreshSlots(player) +} + +fun refreshSlots(player: Player) { + val areaId = areaId(player) + var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) + val pinSlot = player["task_pin_index", -1] + val pin = player["task_pinned", -1] + if (pinSlot != -1 && pin != -1) { + player["task_slot_${pinSlot}"] = pin + } + var count = 0 + var slot = 1 + while (next != -1 && slot < 7) { + val struct = enumDefinitions.get("task_structs").getInt(next) + val definition = structDefinitions.getOrNull(struct) ?: break + val current = next + next = definition["task_next_index", -1] + if (count++ == pinSlot - 1) { + slot++ + continue + } + if (definition["task_members", 0] == 1 && !World.members) { // TODO test if members tasks are displayed for f2p or not + continue + } + player["task_slot_${slot++}"] = current + // IF not completed and has requirements + } +} + +fun areaId(player: Player) = variables.get("task_area")!!.values.toInt(player["task_area", "empty"]) \ 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 97f0ddf51..61cfa7627 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 @@ -19,4 +19,5 @@ adminCommand("quests") { } player["quest_points"] = 7 player.refreshQuestJournal() + player["task_introducing_explorer_jack"] = 3 } \ No newline at end of file From b23c12119cffa4509f1f460db683a8256461eb5f Mon Sep 17 00:00:00 2001 From: GregHib Date: Wed, 22 May 2024 00:03:24 +0100 Subject: [PATCH 07/48] Add struct configs --- data/definitions/structs.yml | 0 .../engine/data/definition/StructDefinitions.kt | 11 +++++++++-- game/src/main/resources/game.properties | 1 + game/src/test/resources/test.properties | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 data/definitions/structs.yml diff --git a/data/definitions/structs.yml b/data/definitions/structs.yml new file mode 100644 index 000000000..e69de29bb 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 b34c59f06..5692252b4 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/game/src/main/resources/game.properties b/game/src/main/resources/game.properties index bcd187394..0a3875814 100644 --- a/game/src/main/resources/game.properties +++ b/game/src/main/resources/game.properties @@ -68,6 +68,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/resources/test.properties b/game/src/test/resources/test.properties index 9b8176999..99e70e53b 100644 --- a/game/src/test/resources/test.properties +++ b/game/src/test/resources/test.properties @@ -34,6 +34,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 From abf9482df7f0325de346c62ae0cc44c287c4a77e Mon Sep 17 00:00:00 2001 From: GregHib Date: Wed, 22 May 2024 16:38:59 +0100 Subject: [PATCH 08/48] Add quest configs --- .../cache/config/data/QuestDefinition.kt | 4 + data/definitions/quests.yml | 171 ++++++++++++++++++ .../gregs/voidps/engine/EngineModules.kt | 1 + .../data/definition/QuestDefinitions.kt | 25 +++ .../world/command/admin/AdminCommands.kts | 1 + game/src/main/resources/game.properties | 1 + game/src/test/resources/test.properties | 1 + 7 files changed, 204 insertions(+) create mode 100644 data/definitions/quests.yml create mode 100644 engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/QuestDefinitions.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 3555f8e70..38d48ddfa 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/data/definitions/quests.yml b/data/definitions/quests.yml new file mode 100644 index 000000000..dbd3c7f71 --- /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/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt index 0da765858..c19e69384 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/data/definition/QuestDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/QuestDefinitions.kt new file mode 100644 index 000000000..6a8afbbcb --- /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/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 7bd235dde..3be85f95c 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 @@ -361,6 +361,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/resources/game.properties b/game/src/main/resources/game.properties index 0a3875814..781c724a0 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 diff --git a/game/src/test/resources/test.properties b/game/src/test/resources/test.properties index 99e70e53b..bdfecc8e0 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 From 7f1ba60e04818b72b0983d4fb2d77da682d5a99f Mon Sep 17 00:00:00 2001 From: GregHib Date: Wed, 22 May 2024 19:53:16 +0100 Subject: [PATCH 09/48] Add manual server side fix for #540 --- .../voidps/cache/config/decoder/StructDecoder.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 b272e0274..d31666d4f 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,18 @@ 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 + val extras = definitions[1330].extras as MutableMap + extras["1296"] = 3 + extras["1297"] = 19 + extras["1298"] = 2 + extras["1299"] = 37 + return definitions + } + override fun StructDefinition.read(opcode: Int, buffer: Reader) { if (opcode == 249) { readParameters(buffer, parameters) From 8d553eff260307ebb202a2c434593ab09ea2defe Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 00:46:19 +0100 Subject: [PATCH 10/48] More manual server side fixes for #540 --- .../cache/config/decoder/StructDecoder.kt | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) 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 d31666d4f..79aff2960 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 @@ -17,11 +17,37 @@ class StructDecoder( override fun load(cache: Cache): Array { val definitions = super.load(cache) // Manually fix values see https://github.com/GregHib/void/issues/540 - val extras = definitions[1330].extras as MutableMap + 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 } From e13157357b370c03a056d41ea66245e07c9b72e1 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 00:47:55 +0100 Subject: [PATCH 11/48] Add all quest varbits from cs2 3227 --- data/definitions/quests.yml | 2 +- data/definitions/structs.yml | 423 ++++++++++ data/definitions/variables-player-bit.yml | 753 +++++++++++++++++- data/definitions/variables-player.yml | 199 ++++- .../world/activity/achievement/Tasks.kt | 419 ++++++++++ 5 files changed, 1792 insertions(+), 4 deletions(-) create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/Tasks.kt diff --git a/data/definitions/quests.yml b/data/definitions/quests.yml index dbd3c7f71..7ec81fc0a 100644 --- a/data/definitions/quests.yml +++ b/data/definitions/quests.yml @@ -153,7 +153,7 @@ curse_of_arrav: 156 fur_n_seek: 154 forgiveness_of_a_chaos_dwarf: 160 within_the_light: 161 -_temple_at_senntisten: 157 +temple_at_senntisten: 157 blood_runs_deep: 163 nomads_requiem: 162 rune_mechanics: 165 diff --git a/data/definitions/structs.yml b/data/definitions/structs.yml index e69de29bb..b6a0849f1 100644 --- a/data/definitions/structs.yml +++ b/data/definitions/structs.yml @@ -0,0 +1,423 @@ +# Ardougne Easy +the_essence_of_magic: 0 +yoink: 1 +silky_smooth: 2 +preaching_to_the_infected: 3 +playing_the_waiting_game: 4 +gone_fishing: 5 +boot_camp: 6 +a_cat_is_for_life: 7 +creator_and_destroyer: 8 +red_revolution: 9 +going_on_a_summer_holiday: 10 +breaking_and_entering: 11 +p_p_p_pick_up_some_prizes: 12 +a_gift_from_khazard: 13 +party_pooper: 14 +vial_deeds: 15 +star_seeker: 16 +dukes_of_khazard: 17 +dont_eat_the_pointy_bit: 18 +bargain_hunter: 19 +are_you_being_served: 20 +no_time_to_lose: 21 +theyre_long_and_pointy: 22 +# Ardougne Medium +a_visit_to_charlie: 23 +i_wonder_what_this_does: 24 +sandys_secret_getaway: 25 +i_know_a_shortcut: 26 +volatile_valuables: 27 +what_a_melon: 28 +ardougne_express: 50 +arriving_in_style: 30 +by_the_bucketload: 31 +meeting_history_again: 32 +fearless_fishing: 33 +water_logged: 34 +green_fingers: 35 +a_natural_thief: 36 +the_coal_train: 37 +are_you_chicken: 38 +# Ardougne Hard +brace_yourself: 39 +shadow_boxing: 40 +just_like_that: 41 +nice_view: 42 +youre_the_dirty_rascal: 43 +ourania_mania: 44 +not_on_my_watch: 45 +it_just_croaked: 46 +get_your_stinking_hands_off_me: 47 +vine_detta: 48 +living_on_a_prayer: 49 +who_wants_to_watch_the_watchtower: 29 +monkey_business: 51 +its_my_newt: 52 +a_taste_of_the_exotic: 53 +blood_bank_withdrawal: 54 +artillery_strike: 55 +# Ardougne Elite +catching_some_rays: 56 +abyssal_valet: 57 +you_could_just_knock: 58 +honestly_its_not_a_purse: 59 +# Lumbridge/Draynor Beginner +on_the_run: 363 +a_world_in_microcosm: 362 +master_of_all_i_survey: 64 +raise_the_roof: 65 +take_your_pick: 73 +adventurers_log: 412 +arent_they_supposed_to_be_twins: 365 +log_a_rhythm: 413 +shellfish_roasting_on_an_open_fire: 366 +heavy_metal: 358 +bar_one: 359 +cutting_edge_technology: 360 +armed_and_dangerous: 361 +on_your_way: 368 +you_can_bank_on_us: 369 +hang_on_to_something: 370 +bovine_intervention: 414 +tan_your_hide: 415 +handicrafts: 416 +handy_dandy: 367 +just_cant_get_the_staff: 371 +click_your_heels_three_times: 372 +come_and_have_a_go: 373 +reach_out_and_touch_someone: 374 +three_rounds_rapid_men: 375 +death_from_above: 376 +flour_power: 377 +a_labour_of_loaf: 378 +om_nom_nom_nom: 379 +on_the_level: 380 +so_thats_what_ess_stands_for: 381 +air_craft: 382 +greasing_the_wheels_of_commerce: 383 +must_be_funny_in_a_rich_mans_world: 384 +i_wonder_if_itll_sprout: 385 +put_your_hands_together_for: 386 +prayer_point_power: 387 +not_what_we_mean_by_irony: 388 +alls_ferrous_in_love_and_war: 389 +am_i_a_blademaster_yet: 390 +first_blood: 391 +temper_temper: 392 +steel_yourself_for_combat: 393 +ammo_ammo_ammo: 394 +take_a_bow: 395 +dont_bury_this_one: 396 +mace_invaders: 397 +capital_protection_what: 398 +clay_of_champions: 80 +just_add_water: 81 +very_potter: 82 +hotpot: 83 +hack_and_smash: 399 +shrimpin_aint_easy: 63 +the_fruit_of_the_sea: 79 +made_for_walking: 400 +did_anyone_bring_any_toast: 401 +its_not_a_red_one: 402 +not_so_confusing_after_all: 403 +absolutely_enchanting: 404 +heart_of_oak: 405 +get_the_point: 406 +berry_tasty: 407 +dishwater: 408 +cant_touch_this: 409 +quarter_centurion: 410 +fledgeling_adventurer: 411 +hail_to_the_duke_baby: 66 +doom: 62 +sage_advice: 69 +window_shopping: 67 +wait_thats_not_a_sheep: 78 +in_the_countyard: 75 +grinding_my_gears: 68 +beware_of_pigzilla: 77 +the_rules_of_engagement: 72 +tower_power: 76 +a_grave_consideration: 61 +tinkle_the_ivories: 70 +ring_my_bell: 74 +passing_out: 71 +# Lumbridge/Draynor Easy +what_is_this_place: 97 +artisan_crafting: 99 +bless_is_more: 100 +morgan_the_merrier: 101 +iron_on: 102 +and_it_was_this_big: 84 +belter_of_a_smelter: 86 +nowt_tool_look_at: 92 +you_doity_rat: 93 +it_was_dead_already: 94 +camping_trip: 95 +ratatouille: 96 +slippery_when_wet: 88 +i_cant_hear_dead_people: 91 +come_in_here_and_say_that: 87 +money_down_the_drayn: 98 +klept_old_man_ia: 89 +eye_on_the_prize: 90 +draaaaaiiiiiins: 85 +# Lumbridge/Draynor Medium +steel_justice: 108 +ease_of_access: 109 +everybody_loves_coal: 103 +weeping_willow: 106 +willow_the_wisp_of_smoke: 110 +a_meal_fit_for_a_duke: 104 +always_be_prepared: 107 +hi_ho_silver: 112 +lovely_with_a_squeeze_of_lemon: 105 +one_day_you_shall_be_a_fork: 113 +made_to_order: 114 +wheres_the_beef: 111 +# Falador Easy +amulet_of_weedspeak: 115 +the_good_stuff: 116 +sir_mitt: 117 +family_values: 118 +sniffing_out_the_mole: 119 +chinchompa_powered: 120 +fill_yer_bucket: 121 +elementary_medicine: 122 +its_not_wabbit_season: 123 +stand_and_deliver: 124 +making_my_mind_up: 125 +mudskip_the_light_fantastic: 127 +disarm_and_embark: 128 +going_along_with_the_fro: 126 +# Falador Medium +fruit_of_the_loom: 130 +is_it_so_hard_to_walk_round: 131 +its_nothing_personal: 134 +ice_the_icy: 135 +blinded_with_science: 136 +they_have_families_to_feed: 137 +stoic_sweetcorn_guardian: 138 +look_spiffy_for_tiffy: 141 +do_they_come_in_other_colours: 139 +these_arent_the_coins_youre_looking_for: 132 +fun_for_the_whole_family: 140 +# Falador Hard +a_knight_in_the_darkness: 151 +child_of_saradomin: 143 +mass_production: 144 +it_spoiled_my_view: 145 +i_heard_you_like_mudskips: 147 +it_matches_my_eyes: 142 +the_stonemasons: 146 +the_mogre_mash: 148 +why_oh_wyvern: 149 +banned_for_life: 150 +# Fremennik Easy +bring_the_antipoisons: 152 +why_wont_you_die: 153 +king_conifer: 154 +assaulted_goodies: 155 +oxymoron_incarnate: 156 +why_did_the_lobster_blush: 157 +hunting_the_hunter: 158 +peer_off_the_pier: 159 +a_familiar_feeling: 160 +endangered_species: 161 +# Fremennik Medium +fremennik_history_101: 162 +cool_story_bro: 163 +whos_a_good_boy: 164 +only_takes_a_little_vial: 165 +you_know_you_want_it: 166 +yak_attack: 170 +fremmental: 171 +fairy_mountaineering: 167 +you_really_dont_need_any_more_shoes: 168 +big_game_hunter: 169 +grand_theft_fish: 172 +# Fremennik Hard +defeating_deadly_dagannoths: 173 +dress_to_impress: 174 +the_graceful_barbarian: 175 +runes_on_the_moon: 176 +pyre_at_will: 177 +fish_fingers: 178 +easy_as_pie: 179 +how_to_maim_your_dragon: 180 +a_periodic_table: 181 +# Karamja Easy +im_lichen_this: 183 +golden_shores: 184 +put_to_port_in_port_sarim: 185 +avast_ardougne: 186 +show_that_you_cairn: 187 +fruity_catch: 188 +tzhaar_wars: 190 +its_a_jungle_ogre: 191 +# Karamja Medium +just_the_ticket: 192 +back_cran_door: 193 +dungeons_and_dragons: 194 +horseless_carriage: 195 +they_like_me_they_really_like_me: 196 +arachnophagia: 197 +romancing_the_stone: 198 +im_a_lumberjack_and_im_okay: 199 +i_sleep_all_night_and_i_work_all_day: 200 +to_catch_a_karambwan: 201 +thats_not_a_knife: 202 +falling_with_style: 203 +scourge_of_scurvy: 204 +hunters_of_the_horned_graahk: 205 +the_roots_of_all_evil: 206 +hotfooting_it: 207 +stairway_to_haven: 208 +thank_you_madam: 209 +shipping_out_from_the_shipyard: 210 +# Karamja Hard +flawless_victory: 211 +play_dead_doggy: 212 +id_be_kharazi_to_eat_this: 213 +at_one_with_nature: 214 +drop_it_like_its_hot: 215 +deadwing: 216 +quick_as_a_shot: 217 +yes_my_master: 219 +can_opener: 220 +# Seers' Village Easy +why: 222 +stir_galahad: 224 +la_morte_darthur: 225 +jute_alors: 223 +sinclair_swirling: 229 +grand_candle: 230 +a_seer_ing_light: 231 +mack_rolled: 232 +# Seers' Village Medium +fleeing_the_scene: 233 +its_a_slightly_magical_stick: 234 +king_coal: 235 +i_can_seer_my_house_from_here: 240 +its_only_a_model: 237 +arch_archer: 238 +what_no_cuddly_toy: 239 +familiar_fire_familiarity: 241 +at_least_it_doesnt_need_walking: 242 +all_your_bass: 243 +# Seers' Village Hard +at_home_on_the_range: 245 +the_short_of_it: 247 +prayer_of_attorney: 248 +beware_of_the_dog: 249 +twisted_fire_starter: 250 +alch_aholic: 251 +island_hopper: 252 +# Varrock Easy +strike_a_pose: 256 +essential_facilitator: 257 +doing_the_ironing: 258 +plank_you_very_much: 259 +making_learning_fun: 260 +jumping_off_point: 261 +lumbering_around: 262 +read_all_about_it: 263 +dog_and_bone: 264 +pot_stop: 265 +on_the_ragged_edge: 266 +relocation_relocation_relocation: 267 +it_belongs_in_a_museum: 268 +journey_to_the_centre_of_the_earth_altar: 269 +jackanory: 270 +limey: 271 +sherpas_delight: 272 +king_of_the_castle: 273 +stick_the_knife_in: 274 +# Varrock Medium +double_strength_weaksauce: 275 +champion: 276 +what_lies_below: 277 +with_a_ten_foot_pole: 278 +cant_make_an_omelette: 279 +point_of_en_tree: 280 +a_lick_of_paint: 282 +for_fast_transactions: 283 +you_wouldnt_like_me_when_im_angry: 284 +return_to_senntisten: 285 +promised_the_earth: 286 +royale_with_thieve: 287 +like_a_varrocket: 288 +challenge_vannaka: 289 +flatpack_backpack: 290 +master_scrumper: 291 +engage: 292 +faster_pussycat_kill_kill: 293 +dial_v_for_varrock: 294 +the_body_shop: 295 +# Varrock Hard +burning_bush: 296 +but_it_wont_warp_you_anywhere: 297 +lighten_up: 298 +put_your_smithing_hat_on: 299 +kudos_on_the_kudos: 300 +who_ate_all_the_pie: 301 +battle_of_the_elements: 302 +changing_rooms: 304 +keeping_tabs_on_varrock: 305 +hand_me_downs: 306 +waka_waka_waka: 307 +living_on_the_edge: 308 +intersceptre: 303 +# Karamja Elite +at_one_plus_fifty_five_with_nature: 324 +the_power_of_lava: 325 +boxing_clever: 326 +its_a_snap: 327 +crunchy_coating: 328 +walkies: 329 +tread_carefully: 330 +ten_in_a_row: 331 +# Seers' Village Elite +its_a_trap_no_wait_its_a_pie: 332 +make_a_bolt_for_it: 333 +the_long_of_it: 334 +plentypotionentiary: 335 +moon_raker: 336 +# Falador Elite +when_this_caverns_rockin: 309 +youd_best_come_a_cookin: 310 +concentration_is_key: 311 +i_swear_i_heard_it_scream: 312 +ive_changed_my_mind: 313 +a_string_and_a_flare: 314 +altar_ed_state: 315 +# Fremennik Elite +jaws_breaker: 316 +limber_lumber_jumper: 317 +astronomical: 318 +first_stryke: 319 +leap_of_faith: 320 +no_smoke_without_pyre: 321 +this_hasta_work: 322 +potting_with_otto: 323 +axell_grease: 417 +# Varrock Elite +stick_a_bork_in_him_hes_done: 337 +nomadness: 338 +double_jointed: 339 +it_all_adze_up: 340 +mind_your_back: 341 +red_red_pies_of_summer: 342 +splitting_headache: 343 +a_bolt_from_the_blue: 344 +a_ton_of_earth: 345 +# Lumbridge/Draynor Hard +a_body_in_the_sewers: 351 +building_up_strength: 352 +have_your_cake_and_eat_it: 353 +blast_and_hellfire: 354 +gods_give_me_strength: 355 +not_waving_but_drowning: 356 +are_yew_as_fired_up_as_i_am: 357 \ No newline at end of file diff --git a/data/definitions/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index b90b3fb1c..9da0691ef 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -430,9 +430,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 +584,7 @@ death_altar_ruins: blood_altar_ruins: id: 619 format: boolean -minigame_type: +minigame_format: id: 4540 format: map default: none @@ -724,3 +733,743 @@ task_introducing_explorer_jack: id: 6494 format: int persist: true +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 +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 +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 +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 +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 diff --git a/data/definitions/variables-player.yml b/data/definitions/variables-player.yml index 970e4098d..747e749e8 100644 --- a/data/definitions/variables-player.yml +++ b/data/definitions/variables-player.yml @@ -405,4 +405,201 @@ 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 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 000000000..e661ad905 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/Tasks.kt @@ -0,0 +1,419 @@ +package world.gregs.voidps.world.activity.achievement + +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 { + // Missing quests: 199, 200, 229 + // Missing skills: 302, 305 + // Extra skills: 3005, 3012 + 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.get(id, default)) + } + + + fun script_3223(player: Player, arg0: Int, arg1: Int): String { + var int2: Int + var str3: String? + str3 = "" + int2 = 0 + when (arg0) { + 147, 23, 294, 167, 249 -> if (arg1 == 1) { + str3 = "You must have access to the fairy ring network to complete this Task." + if (player["fairy_rings_unlocked", false]) { + int2 = 1 + } + } + 49 -> if (arg1 == 1) { + str3 = "You must unlock 500 music tracks in order to perform the Air Guitar emote." + if (player["unlocked_emote_air_guitar", false]) { + int2 = 1 + } + } + 59 -> if (arg1 == 2) { + str3 = "You must also have completed the Abyss miniquest." + if (player.questComplete("enter_the_abyss")) { + int2 = 1 + } + } + 107 -> if (arg1 == 1) { + str3 = "You must have progressed to a certain point in the Dragon Slayer quest." + if (player.getInt("dragon_slayer", "unstarted") >= 2 && player["dragon_slayer_received_shield", false] || player.questComplete("dragon_slayer")) { + int2 = 1 + } + } + 178 -> if (arg1 == 1) { + str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." + if (player["barbarian_training_fishing_unlocked", false]) { + int2 = 1 + } + } + 180 -> if (arg1 == 1) { + str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." + if (player["barbarian_training_pyre_unlocked", false]) { + int2 = 1 + } + } + 177 -> if (arg1 == 1) { + str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." + if (player["barbarian_training_pyre_unlocked", false]) { + int2 = 1 + } + } + 316 -> if (arg1 == 1) { + str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." + if (player["barbarian_training_fishing_unlocked", false]) { + int2 = 1 + } + } + 321 -> if (arg1 == 1) { + str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." + if (player["barbarian_training_pyre_unlocked", false]) { + int2 = 1 + } + } + 322 -> if (arg1 == 1) { + str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." + if (player["barbarian_training_hasta_unlocked", false]) { + int2 = 1 + } + } + 323 -> if (arg1 == 1) { + str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." + if (player["barbarian_training_mix_unlocked", false]) { + int2 = 1 + } + } + 175 -> if (arg1 == 1) { + str3 = "You must complete the Bar Crawl miniquest." + if (player.questComplete("bar_crawl_miniquest") || player["bar_crawl_started", false]) { + int2 = 1 + } + } + 331, 219 -> if (arg1 == 2) { + str3 = "You must have a total combat level of at least 100 to accept an assignment in Shilo Village." + if (player.summoningCombatLevel >= 100) { + int2 = 1 + } + } + 248 -> if (arg1 == 1) { + str3 = "You must have completed the Knight Waves in Camelot." + if (player["knights_waves", 0] == 8) { + int2 = 1 + } + } + 3011, 276 -> if (arg1 == 1) { + str3 = "You require 33 Quest Points to enter the Champions' Guild." + if (player["quest_points", 0] >= 33) { + int2 = 1 + } + } + 281 -> if (arg1 == 1) { + str3 = "You must unlock all four emotes by completing levels of the Stronghold of Security." + if (player["unlocked_emote_flap", false] && player["unlocked_emote_slap_head", false] && player["unlocked_emote_idea", false] && player["unlocked_emote_stomp", false]) { + int2 = 1 + } + } + 285 -> if (arg1 == 1) { + str3 = "You must learn the secret of the Senntisten necklace." + if (player["teleport_to_digsite_with_pendant", false]) { + int2 = 1 + } + } + 289 -> if (arg1 == 1) { + str3 = "You must have a total combat level of at least 40 to accept an assignment from Vannaka." + if (player.summoningCombatLevel >= 40) { + int2 = 1 + } + } + 300 -> if (arg1 == 1) { + str3 = "Completing quests will increase your access to Kudos with the Varrock Museum." + if (kudosCount(player) >= 153) { + int2 = 1 + } + } + 3000 -> if (arg1 == 2) { + if (minutes() >= player["varp_451", 0]) { + int2 = 1 + } + str3 = "You may gather the Tears of Guthix once every week." + } else if (arg1 == 3) { + if (player["quest_points", 0] >= player["varbit_456", 0] || player["total_experience", 0.0] >= player["varp_450", 0.0]) { + int2 = 1 + } + str3 = "You must have gained a Quest Point or 100,000 total experience to enter Juna's cavern." + } + 3013, 3001 -> if (arg1 == 1) { + str3 = "You must have a total combat level of at least 40 to fight for the Void Knights." + if (player.combatLevel >= 40) { + int2 = 1 + } + } + 3002 -> if (arg1 == 1) { + str3 = "You must have Larry or Chuck explain the purpose of penguin spying." + if (player["penguin_hide_and_seek_explained", false]) { + int2 = 1 + } + } else if (arg1 == 2) { + str3 = "You must have spied on fewer than ten penguins already this week." + if (player["penguins_found_weekly", 0] < 10) { + int2 = 1 + } + } else if (arg1 == 3) { + str3 = "You may spy on penguins if your total Penguin Points are less than the maximum of fifty." + if (player["penguin_points", 0] < 50) { + int2 = 1 + } + } + 12 -> if (arg1 == 1) { + str3 = "You must have Larry or Chuck explain the purpose of Penguin Hide and Seek." + if (player["penguin_hide_and_seek_explained", false]) { + int2 = 1 + } + } + 3003 -> if (arg1 == 1) { + str3 = "You may not chop down more than two evil trees per day." + if (player["nurture_evil_tree_stage", 0] < 2) { + int2 = 1 + } + } + 3007 -> if (arg1 == 1) { + str3 = "You may attempt the Agility, Magic and Ranged performances after a week has passed since your last show." + if (!player["circus_magic", false] || !player["circus_agility", false] || !player["circus_ranged", false]) { + int2 = 1 + } + } + 3008 -> if (arg1 == 2) { + str3 = "You must wait at least a day since you last faced Bork." + if (player["bork_defeated_day", 0] != days()) { + int2 = 1 + } + } + 3010 -> if (arg1 == 2) { + str3 = "At least a week must pass since you last faced the Skeletal Horror." + if (minutes() < player["varbit_6305", 0]) { + int2 = 1 + } + } + 3012 -> if (arg1 == 1) { + str3 = "You require 50 Runecrafting to enter the Runecrafters' Guild." + if (player.hasMax(Skill.Runecrafting, 50)) { + int2 = 1 + } + } + 3015 -> if (arg1 == 2) { + str3 = "You must have at least 65 Attack or Defence in order to take on a case." + if (player.hasMax(Skill.Attack, 65) || player.hasMax(Skill.Defence, 65)) { + int2 = 1 + } + } + 3031 -> if (arg1 == 1) { + str3 = "You must have a total combat level of at least 48 to fight in the Clan Wars." + if (player.summoningCombatLevel >= 48) { + int2 = 1 + } + } + 3034 -> if (arg1 == 1) { + str3 = "To enter the Warriors' Guild your Attack or Strength level must be 99, or your combined Attack and Strength levels must total 130 or more." + if (player.levels.getMax(Skill.Strength) + player.levels.getMax(Skill.Attack) >= 130 || player.hasMax(Skill.Attack, 99) || player.hasMax(Skill.Strength, 99)) { + int2 = 1 + } + } + else -> { + str3 = "" + int2 = 0 + } + } + if (int2 == 1) { + str3 = "$str3" + } + return str3 + } + + 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 From 370b5229d6d6fe436415e56860ffcc4b692f813b Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 00:48:37 +0100 Subject: [PATCH 12/48] Add combat summoning level support --- .../interact/entity/player/combat/CombatLevel.kts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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 d7e9848fa..9207bad9f 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 From 23149b2625f2e148a9e90f3c03c94131cffc00a7 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 00:49:09 +0100 Subject: [PATCH 13/48] Add boolean support to var command --- .../gregs/voidps/world/command/debug/InterfaceCommands.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7af676692..b4c75e2f1 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 @@ -93,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") { From 75f338ca02df6a026dbb92a042cd5c878b3b53db Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 01:02:37 +0100 Subject: [PATCH 14/48] Filter task tab by task requirements --- data/definitions/interfaces.yml | 1 + .../world/activity/achievement/TaskSystem.kts | 51 ++++++++++------- .../world/activity/achievement/Tasks.kt | 57 ++++++++++++++++++- 3 files changed, 88 insertions(+), 21 deletions(-) diff --git a/data/definitions/interfaces.yml b/data/definitions/interfaces.yml index ca4bf51be..4a0304820 100644 --- a/data/definitions/interfaces.yml +++ b/data/definitions/interfaces.yml @@ -2567,6 +2567,7 @@ task_system: hints: 36 summary_overlay: 122 message_overlay: 171 + ok: 130 warriors_guild: 1057 fade_out: id: 120 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 96dad357e..463c80782 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 @@ -69,6 +69,11 @@ interfaceOption("Open", "task_list", "task_system") { player.open("task_list") } +interfaceOption("OK", "ok", "task_system") { + player.interfaces.sendVisibility("task_system", "summary_overlay", false) + refreshSlots(player) +} + interfaceOption("Pin/Unpin Task", "task_*", "task_system") { val index = component.removePrefix("task_").toInt() if (player["task_pin_index", -1] == index) { @@ -107,28 +112,34 @@ variableSet("task_pin_index", "task_area") { player -> fun refreshSlots(player: Player) { val areaId = areaId(player) var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) - val pinSlot = player["task_pin_index", -1] - val pin = player["task_pinned", -1] - if (pinSlot != -1 && pin != -1) { - player["task_slot_${pinSlot}"] = pin - } - var count = 0 - var slot = 1 - while (next != -1 && slot < 7) { - val struct = enumDefinitions.get("task_structs").getInt(next) - val definition = structDefinitions.getOrNull(struct) ?: break - val current = next - next = definition["task_next_index", -1] - if (count++ == pinSlot - 1) { - slot++ - continue - } - if (definition["task_members", 0] == 1 && !World.members) { // TODO test if members tasks are displayed for f2p or not + for (i in 1..6) { + if (pinned(player, i)) { + player["task_slot_${i}"] = player["task_pinned", 4091] continue } - player["task_slot_${slot++}"] = current - // IF not completed and has requirements + next = nextTask(player, i, next) + player["task_slot_${i}"] = next } } -fun areaId(player: Player) = variables.get("task_area")!!.values.toInt(player["task_area", "empty"]) \ No newline at end of file +fun nextTask(player: Player, index: Int, id: Int): Int { + if (id == 4091) { + return id + } + val struct = enumDefinitions.get("task_structs").getInt(id) + val definition = structDefinitions.getOrNull(struct) ?: return 4091 + val next = definition["task_next_index", 4091] + if (!Tasks.hasRequirements(player, definition) || isCompleted(player, "${definition.stringId}_task") || player["task_pinned", -1] == if (index == 1) id else next) { + return nextTask(player, index, next) + } + return if (index == 1) id else next +} + +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"]) + +fun isCompleted(player: Player, id: String) = player[id, false] \ 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 index e661ad905..6979f14eb 100644 --- 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 @@ -1,5 +1,7 @@ package world.gregs.voidps.world.activity.achievement +import world.gregs.voidps.cache.config.data.StructDefinition +import world.gregs.voidps.engine.data.definition.QuestDefinitions 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 @@ -14,10 +16,63 @@ import java.util.Calendar.HOUR_OF_DAY import java.util.concurrent.TimeUnit object Tasks { + + 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 - fun hasRequirements(player: Player, id: Int): Boolean { + 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] From a28ff59c5f7a558b2256a576c4884785799523ef Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 01:46:27 +0100 Subject: [PATCH 15/48] Fix struct ids --- data/definitions/structs.yml | 909 +++++++++++++++++++---------------- 1 file changed, 496 insertions(+), 413 deletions(-) diff --git a/data/definitions/structs.yml b/data/definitions/structs.yml index b6a0849f1..7657e4e31 100644 --- a/data/definitions/structs.yml +++ b/data/definitions/structs.yml @@ -1,423 +1,506 @@ -# Ardougne Easy -the_essence_of_magic: 0 -yoink: 1 -silky_smooth: 2 -preaching_to_the_infected: 3 -playing_the_waiting_game: 4 -gone_fishing: 5 -boot_camp: 6 -a_cat_is_for_life: 7 -creator_and_destroyer: 8 -red_revolution: 9 -going_on_a_summer_holiday: 10 -breaking_and_entering: 11 -p_p_p_pick_up_some_prizes: 12 -a_gift_from_khazard: 13 -party_pooper: 14 -vial_deeds: 15 -star_seeker: 16 -dukes_of_khazard: 17 -dont_eat_the_pointy_bit: 18 -bargain_hunter: 19 -are_you_being_served: 20 -no_time_to_lose: 21 -theyre_long_and_pointy: 22 -# Ardougne Medium -a_visit_to_charlie: 23 -i_wonder_what_this_does: 24 -sandys_secret_getaway: 25 -i_know_a_shortcut: 26 -volatile_valuables: 27 -what_a_melon: 28 -ardougne_express: 50 -arriving_in_style: 30 -by_the_bucketload: 31 -meeting_history_again: 32 -fearless_fishing: 33 -water_logged: 34 -green_fingers: 35 -a_natural_thief: 36 -the_coal_train: 37 -are_you_chicken: 38 -# Ardougne Hard -brace_yourself: 39 -shadow_boxing: 40 -just_like_that: 41 -nice_view: 42 -youre_the_dirty_rascal: 43 -ourania_mania: 44 -not_on_my_watch: 45 -it_just_croaked: 46 -get_your_stinking_hands_off_me: 47 -vine_detta: 48 -living_on_a_prayer: 49 -who_wants_to_watch_the_watchtower: 29 -monkey_business: 51 -its_my_newt: 52 -a_taste_of_the_exotic: 53 -blood_bank_withdrawal: 54 -artillery_strike: 55 -# Ardougne Elite -catching_some_rays: 56 -abyssal_valet: 57 -you_could_just_knock: 58 -honestly_its_not_a_purse: 59 +# 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 -on_the_run: 363 -a_world_in_microcosm: 362 -master_of_all_i_survey: 64 -raise_the_roof: 65 -take_your_pick: 73 -adventurers_log: 412 -arent_they_supposed_to_be_twins: 365 -log_a_rhythm: 413 -shellfish_roasting_on_an_open_fire: 366 -heavy_metal: 358 -bar_one: 359 -cutting_edge_technology: 360 -armed_and_dangerous: 361 -on_your_way: 368 -you_can_bank_on_us: 369 -hang_on_to_something: 370 -bovine_intervention: 414 -tan_your_hide: 415 -handicrafts: 416 -handy_dandy: 367 -just_cant_get_the_staff: 371 -click_your_heels_three_times: 372 -come_and_have_a_go: 373 -reach_out_and_touch_someone: 374 -three_rounds_rapid_men: 375 -death_from_above: 376 -flour_power: 377 -a_labour_of_loaf: 378 -om_nom_nom_nom: 379 -on_the_level: 380 -so_thats_what_ess_stands_for: 381 -air_craft: 382 -greasing_the_wheels_of_commerce: 383 -must_be_funny_in_a_rich_mans_world: 384 -i_wonder_if_itll_sprout: 385 -put_your_hands_together_for: 386 -prayer_point_power: 387 -not_what_we_mean_by_irony: 388 -alls_ferrous_in_love_and_war: 389 -am_i_a_blademaster_yet: 390 -first_blood: 391 -temper_temper: 392 -steel_yourself_for_combat: 393 -ammo_ammo_ammo: 394 -take_a_bow: 395 -dont_bury_this_one: 396 -mace_invaders: 397 -capital_protection_what: 398 -clay_of_champions: 80 -just_add_water: 81 -very_potter: 82 -hotpot: 83 -hack_and_smash: 399 -shrimpin_aint_easy: 63 -the_fruit_of_the_sea: 79 -made_for_walking: 400 -did_anyone_bring_any_toast: 401 -its_not_a_red_one: 402 -not_so_confusing_after_all: 403 -absolutely_enchanting: 404 -heart_of_oak: 405 -get_the_point: 406 -berry_tasty: 407 -dishwater: 408 -cant_touch_this: 409 -quarter_centurion: 410 -fledgeling_adventurer: 411 -hail_to_the_duke_baby: 66 -doom: 62 -sage_advice: 69 -window_shopping: 67 -wait_thats_not_a_sheep: 78 -in_the_countyard: 75 -grinding_my_gears: 68 -beware_of_pigzilla: 77 -the_rules_of_engagement: 72 -tower_power: 76 -a_grave_consideration: 61 -tinkle_the_ivories: 70 -ring_my_bell: 74 -passing_out: 71 +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_task: 1250 +om_nom_nom_nom_task: 1540 +on_the_level_task: 1541 +rune_mysteries_task: 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: 97 -artisan_crafting: 99 -bless_is_more: 100 -morgan_the_merrier: 101 -iron_on: 102 -and_it_was_this_big: 84 -belter_of_a_smelter: 86 -nowt_tool_look_at: 92 -you_doity_rat: 93 -it_was_dead_already: 94 -camping_trip: 95 -ratatouille: 96 -slippery_when_wet: 88 -i_cant_hear_dead_people: 91 -come_in_here_and_say_that: 87 -money_down_the_drayn: 98 -klept_old_man_ia: 89 -eye_on_the_prize: 90 -draaaaaiiiiiins: 85 +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: 108 -ease_of_access: 109 -everybody_loves_coal: 103 -weeping_willow: 106 -willow_the_wisp_of_smoke: 110 -a_meal_fit_for_a_duke: 104 -always_be_prepared: 107 -hi_ho_silver: 112 -lovely_with_a_squeeze_of_lemon: 105 -one_day_you_shall_be_a_fork: 113 -made_to_order: 114 -wheres_the_beef: 111 +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: 115 -the_good_stuff: 116 -sir_mitt: 117 -family_values: 118 -sniffing_out_the_mole: 119 -chinchompa_powered: 120 -fill_yer_bucket: 121 -elementary_medicine: 122 -its_not_wabbit_season: 123 -stand_and_deliver: 124 -making_my_mind_up: 125 -mudskip_the_light_fantastic: 127 -disarm_and_embark: 128 -going_along_with_the_fro: 126 +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: 130 -is_it_so_hard_to_walk_round: 131 -its_nothing_personal: 134 -ice_the_icy: 135 -blinded_with_science: 136 -they_have_families_to_feed: 137 -stoic_sweetcorn_guardian: 138 -look_spiffy_for_tiffy: 141 -do_they_come_in_other_colours: 139 -these_arent_the_coins_youre_looking_for: 132 -fun_for_the_whole_family: 140 +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: 151 -child_of_saradomin: 143 -mass_production: 144 -it_spoiled_my_view: 145 -i_heard_you_like_mudskips: 147 -it_matches_my_eyes: 142 -the_stonemasons: 146 -the_mogre_mash: 148 -why_oh_wyvern: 149 -banned_for_life: 150 +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: 152 -why_wont_you_die: 153 -king_conifer: 154 -assaulted_goodies: 155 -oxymoron_incarnate: 156 -why_did_the_lobster_blush: 157 -hunting_the_hunter: 158 -peer_off_the_pier: 159 -a_familiar_feeling: 160 -endangered_species: 161 +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: 162 -cool_story_bro: 163 -whos_a_good_boy: 164 -only_takes_a_little_vial: 165 -you_know_you_want_it: 166 -yak_attack: 170 -fremmental: 171 -fairy_mountaineering: 167 -you_really_dont_need_any_more_shoes: 168 -big_game_hunter: 169 -grand_theft_fish: 172 +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: 173 -dress_to_impress: 174 -the_graceful_barbarian: 175 -runes_on_the_moon: 176 -pyre_at_will: 177 -fish_fingers: 178 -easy_as_pie: 179 -how_to_maim_your_dragon: 180 -a_periodic_table: 181 -# Karamja Easy -im_lichen_this: 183 -golden_shores: 184 -put_to_port_in_port_sarim: 185 -avast_ardougne: 186 -show_that_you_cairn: 187 -fruity_catch: 188 -tzhaar_wars: 190 -its_a_jungle_ogre: 191 -# Karamja Medium -just_the_ticket: 192 -back_cran_door: 193 -dungeons_and_dragons: 194 -horseless_carriage: 195 -they_like_me_they_really_like_me: 196 -arachnophagia: 197 -romancing_the_stone: 198 -im_a_lumberjack_and_im_okay: 199 -i_sleep_all_night_and_i_work_all_day: 200 -to_catch_a_karambwan: 201 -thats_not_a_knife: 202 -falling_with_style: 203 -scourge_of_scurvy: 204 -hunters_of_the_horned_graahk: 205 -the_roots_of_all_evil: 206 -hotfooting_it: 207 -stairway_to_haven: 208 -thank_you_madam: 209 -shipping_out_from_the_shipyard: 210 -# Karamja Hard -flawless_victory: 211 -play_dead_doggy: 212 -id_be_kharazi_to_eat_this: 213 -at_one_with_nature: 214 -drop_it_like_its_hot: 215 -deadwing: 216 -quick_as_a_shot: 217 -yes_my_master: 219 -can_opener: 220 -# Seers' Village Easy -why: 222 -stir_galahad: 224 -la_morte_darthur: 225 -jute_alors: 223 -sinclair_swirling: 229 -grand_candle: 230 -a_seer_ing_light: 231 -mack_rolled: 232 -# Seers' Village Medium -fleeing_the_scene: 233 -its_a_slightly_magical_stick: 234 -king_coal: 235 -i_can_seer_my_house_from_here: 240 -its_only_a_model: 237 -arch_archer: 238 -what_no_cuddly_toy: 239 -familiar_fire_familiarity: 241 -at_least_it_doesnt_need_walking: 242 -all_your_bass: 243 -# Seers' Village Hard -at_home_on_the_range: 245 -the_short_of_it: 247 -prayer_of_attorney: 248 -beware_of_the_dog: 249 -twisted_fire_starter: 250 -alch_aholic: 251 -island_hopper: 252 -# Varrock Easy -strike_a_pose: 256 -essential_facilitator: 257 -doing_the_ironing: 258 -plank_you_very_much: 259 -making_learning_fun: 260 -jumping_off_point: 261 -lumbering_around: 262 -read_all_about_it: 263 -dog_and_bone: 264 -pot_stop: 265 -on_the_ragged_edge: 266 -relocation_relocation_relocation: 267 -it_belongs_in_a_museum: 268 -journey_to_the_centre_of_the_earth_altar: 269 -jackanory: 270 -limey: 271 -sherpas_delight: 272 -king_of_the_castle: 273 -stick_the_knife_in: 274 -# Varrock Medium -double_strength_weaksauce: 275 -champion: 276 -what_lies_below: 277 -with_a_ten_foot_pole: 278 -cant_make_an_omelette: 279 -point_of_en_tree: 280 -a_lick_of_paint: 282 -for_fast_transactions: 283 -you_wouldnt_like_me_when_im_angry: 284 -return_to_senntisten: 285 -promised_the_earth: 286 -royale_with_thieve: 287 -like_a_varrocket: 288 -challenge_vannaka: 289 -flatpack_backpack: 290 -master_scrumper: 291 -engage: 292 -faster_pussycat_kill_kill: 293 -dial_v_for_varrock: 294 -the_body_shop: 295 -# Varrock Hard -burning_bush: 296 -but_it_wont_warp_you_anywhere: 297 -lighten_up: 298 -put_your_smithing_hat_on: 299 -kudos_on_the_kudos: 300 -who_ate_all_the_pie: 301 -battle_of_the_elements: 302 -changing_rooms: 304 -keeping_tabs_on_varrock: 305 -hand_me_downs: 306 -waka_waka_waka: 307 -living_on_the_edge: 308 -intersceptre: 303 -# Karamja Elite -at_one_plus_fifty_five_with_nature: 324 -the_power_of_lava: 325 -boxing_clever: 326 -its_a_snap: 327 -crunchy_coating: 328 -walkies: 329 -tread_carefully: 330 -ten_in_a_row: 331 -# Seers' Village Elite -its_a_trap_no_wait_its_a_pie: 332 -make_a_bolt_for_it: 333 -the_long_of_it: 334 -plentypotionentiary: 335 -moon_raker: 336 -# Falador Elite -when_this_caverns_rockin: 309 -youd_best_come_a_cookin: 310 -concentration_is_key: 311 -i_swear_i_heard_it_scream: 312 -ive_changed_my_mind: 313 -a_string_and_a_flare: 314 -altar_ed_state: 315 +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: 316 -limber_lumber_jumper: 317 -astronomical: 318 -first_stryke: 319 -leap_of_faith: 320 -no_smoke_without_pyre: 321 -this_hasta_work: 322 -potting_with_otto: 323 -axell_grease: 417 -# Varrock Elite -stick_a_bork_in_him_hes_done: 337 -nomadness: 338 -double_jointed: 339 -it_all_adze_up: 340 -mind_your_back: 341 -red_red_pies_of_summer: 342 -splitting_headache: 343 -a_bolt_from_the_blue: 344 -a_ton_of_earth: 345 -# Lumbridge/Draynor Hard -a_body_in_the_sewers: 351 -building_up_strength: 352 -have_your_cake_and_eat_it: 353 -blast_and_hellfire: 354 -gods_give_me_strength: 355 -not_waving_but_drowning: 356 -are_yew_as_fired_up_as_i_am: 357 \ No newline at end of file +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 \ No newline at end of file From afa2ff2f36804d76a592ece21ca1cc412daceda7 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 01:46:40 +0100 Subject: [PATCH 16/48] Add all task varbits --- data/definitions/variables-player-bit.yml | 1654 ++++++++++++++++++--- 1 file changed, 1426 insertions(+), 228 deletions(-) diff --git a/data/definitions/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index 9da0691ef..5994192e8 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -729,10 +729,881 @@ task_filter_sets: id: 8580 format: boolean persist: true -task_introducing_explorer_jack: - id: 6494 +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: boolean + persist: true +# 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 @@ -1057,6 +1928,7 @@ passing_out_task: id: 4959 format: boolean persist: true +# Lumbridge/Draynor Easy what_is_this_place_task: id: 4985 format: boolean @@ -1133,6 +2005,7 @@ draaaaaiiiiiins_task: id: 4973 format: boolean persist: true +# Lumbridge/Draynor Medium steel_justice_task: id: 4997 format: boolean @@ -1181,295 +2054,620 @@ wheres_the_beef_task: id: 5998 format: boolean persist: true -a_body_in_the_sewers_task: - id: 8180 +# 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 -building_up_strength_task: - id: 8181 +party_pooper_task: + id: 6612 format: boolean persist: true -have_your_cake_and_eat_it_task: - id: 8188 +vial_deeds_task: + id: 6613 format: boolean persist: true -blast_and_hellfire_task: - id: 8191 +star_seeker_task: + id: 6614 format: boolean persist: true -gods_give_me_strength_task: - id: 8192 +dukes_of_khazard_task: + id: 6615 format: boolean persist: true -not_waving_but_drowning_task: - id: 8193 +dont_eat_the_pointy_bit_task: + id: 6616 format: boolean persist: true -are_yew_as_fired_up_as_i_am_task: - id: 8194 +bargain_hunter_task: + id: 6617 format: boolean persist: true -tower_of_life: - id: 3337 - format: map +are_you_being_served_task: + id: 6618 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 18 -wolf_whistle: - id: 4302 - format: map +no_time_to_lose_task: + id: 6619 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 110 -fairy_rings_unlocked: - id: 2328 +theyre_long_and_pointy_task: + id: 6620 format: boolean persist: true -kenniths_concerns: - id: 4505 - format: map +# Ardougne Medium +a_visit_to_charlie_task: + id: 6622 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 100 -enlightened_journey: - id: 2866 - format: map +i_wonder_what_this_does_task: + id: 6623 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 200 -hand_in_the_sand: - id: 1527 - format: map +sandys_secret_getaway_task: + id: 6624 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 160 -meeting_history: - id: 5075 - format: map +i_know_a_shortcut_task: + id: 6625 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 20 -lunar_diplomacy: - id: 2448 - format: map +volatile_valuables_task: + id: 6626 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 190 -back_to_my_roots: - id: 4055 - format: map +what_a_melon_task: + id: 6627 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 65 -catapult_construction: - id: 4396 - format: map +ardougne_express_task: + id: 6650 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 60 -dragon_slayer_received_shield: - id: 3746 +arriving_in_style_task: + id: 6629 format: boolean persist: true -garden_of_tranquillity: - id: 961 - format: map +by_the_bucketload_task: + id: 6630 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 60 -wanted: - id: 1051 - format: map +meeting_history_again_task: + id: 6631 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 10 -rat_catchers: - id: 1404 - format: map +fearless_fishing_task: + id: 6632 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 127 -recruitment_drive: - id: 657 - format: map +water_logged_task: + id: 6633 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 2 -temple_at_senntisten: - id: 6775 - format: map +green_fingers_task: + id: 6634 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 90 -slug_menace: - id: 2610 - format: map +a_natural_thief_task: + id: 6635 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 14 -bar_crawl_started: - id: 3378 +the_coal_train_task: + id: 6636 format: boolean persist: true -barbarian_training_fishing_unlocked: - id: 3757 +are_you_chicken_task: + id: 6637 format: boolean persist: true -barbarian_training_mix_unlocked: - id: 3761 +# Ardougne Hard +brace_yourself_task: + id: 6639 format: boolean persist: true -barbarian_training_hasta_unlocked: - id: 3763 +shadow_boxing_task: + id: 6640 format: boolean persist: true -barbarian_training_pyre_unlocked: - id: 3764 +just_like_that_task: + id: 6641 format: boolean persist: true -royal_trouble: - id: 2140 - format: map +nice_view_task: + id: 6642 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 30 -blood_runs_deep: - id: 6883 - format: map +youre_the_dirty_rascal_task: + id: 6643 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 147 -while_guthix_sleeps: - id: 5491 - format: map +ourania_mania_task: + id: 6644 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 910 -elemental_workshop_i: - id: 2067 - format: map +not_on_my_watch_task: + id: 6645 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 1 -knights_waves: - id: 3909 - format: int +it_just_croaked_task: + id: 6646 + format: boolean persist: true -what_lies_below: - id: 3523 - format: map +get_your_stinking_hands_off_me_task: + id: 6647 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 150 -souls_bane: - id: 2011 - format: map +vine_detta_task: + id: 6648 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 13 -teleport_to_digsite_with_pendant: - id: 3639 +living_on_a_prayer_task: + id: 6649 format: boolean persist: true -desert_treasure: - id: 358 - format: map +who_wants_to_watch_the_watchtower_task: + id: 6628 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 15 -nomads_requiem: - id: 6962 - format: map +monkey_business_task: + id: 6651 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 12 -all_fired_up: - id: 5133 - format: map +its_my_newt_task: + id: 6652 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 90 -nurture_evil_tree_stage: - id: 1545 +a_taste_of_the_exotic_task: + id: 6653 format: boolean persist: true -circus_magic: - id: 5251 +blood_bank_withdrawal_task: + id: 6654 format: boolean persist: true -circus_agility: - id: 5252 +artillery_strike_task: + id: 6655 format: boolean persist: true -circus_ranged: - id: 5253 +# Ardougne Elite +catching_some_rays_task: + id: 6658 format: boolean persist: true -fur_n_seek: - id: 6307 - format: map +abyssal_valet_task: + id: 6659 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 12 -skeletal_horror_respawn_minute: - id: 6305 - format: int +you_could_just_knock_task: + id: 6660 + format: boolean persist: true -kings_ransom: - id: 3888 - format: map +honestly_its_not_a_purse_task: + id: 6661 + format: boolean persist: true - default: unstarted - values: - unstarted: 0 - completed: 90 +almost_made_in_ardougne_task: + id: 6662 + format: boolean + persist: true \ No newline at end of file From 650daeb550fe53cc84a4b2b500b271178297ea2f Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 12:15:44 +0100 Subject: [PATCH 17/48] Fix task pinning --- .../world/activity/achievement/TaskList.kts | 14 +++-- .../world/activity/achievement/TaskSystem.kts | 52 ++++++++++--------- 2 files changed, 37 insertions(+), 29 deletions(-) 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 index 415e3a528..b0b3f053e 100644 --- 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 @@ -41,12 +41,16 @@ interfaceOption("Pin", "pin", "task_list") { val enumDefinitions: EnumDefinitions by inject() val structDefinitions: StructDefinitions by inject() -fun id(player: Player, index: Int, area: Int = areaId(player)): Int? { +fun index(player: Player, index: Int, area: Int = areaId(player)): Int? { var next = enumDefinitions.get("task_area_start_indices").getInt(area) var count = 0 while (next != -1) { val struct = enumDefinitions.get("task_structs").getInt(next) val definition = structDefinitions.getOrNull(struct) ?: break + if (player["task_hide_completed", false] && isCompleted(player, definition.stringId)) { + count++ + continue + } if (count++ == index) { return next } @@ -55,7 +59,9 @@ fun id(player: Player, index: Int, area: Int = areaId(player)): Int? { return null } -fun index(player: Player, id: Int): Int { +fun isCompleted(player: Player, id: String) = player.contains(id) && player[id, false] + +fun find(player: Player, id: Int): Int { for (i in 0 until 6) { if (player["task_slot_${i}", -1] == id) { return i @@ -90,12 +96,12 @@ variableSet("task_pin_index") { player -> 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 = id(player, index) ?: return + val id = index(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"] = index(player, id) + player["task_pin_index"] = find(player, id) } } \ 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 463c80782..4fa7a9876 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 @@ -86,21 +86,24 @@ interfaceOption("Pin/Unpin Task", "task_*", "task_system") { } fun index(player: Player, index: Int, areaId: Int = areaId(player)): Int? { - var start = enumDefinitions.get("task_area_start_indices").getInt(areaId) + var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) var count = 1 - while (start != -1) { - val struct = enumDefinitions.get("task_structs").getInt(start) + while (next != -1) { + val struct = enumDefinitions.get("task_structs").getInt(next) val definition = structDefinitions.getOrNull(struct) ?: break - val current = start - start = definition["task_next_index", -1] - if (definition["task_members", 0] == 1 && !World.members) { // TODO test if members tasks are displayed for f2p or not + if (player["task_hide_completed", false] && isCompleted(player, definition.stringId) || definition["task_members", 0] == 1 && !World.members) { count++ continue } if (count == index) { - return current + return next + } + if (player["task_pin_index", -1] == count) { + count++ + continue } count++ + next = definition["task_next_index", -1] } return null } @@ -109,30 +112,29 @@ variableSet("task_pin_index", "task_area") { player -> refreshSlots(player) } +variableSet("*_task", to = true) { player -> + refreshSlots(player) +} + fun refreshSlots(player: Player) { val areaId = areaId(player) var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) - for (i in 1..6) { - if (pinned(player, i)) { - player["task_slot_${i}"] = player["task_pinned", 4091] + var i = 1 + while (i < 7 && next != 4091) { + val struct = enumDefinitions.get("task_structs").getInt(next) + val definition = structDefinitions.getOrNull(struct) ?: break + val pinned = pinned(player, i) + if (player["task_pinned", -1] == next && !pinned || !Tasks.hasRequirements(player, definition) || isCompleted(player, definition.stringId)) { + next = definition["task_next_index", 4091] continue } - next = nextTask(player, i, next) - player["task_slot_${i}"] = next - } -} - -fun nextTask(player: Player, index: Int, id: Int): Int { - if (id == 4091) { - return id - } - val struct = enumDefinitions.get("task_structs").getInt(id) - val definition = structDefinitions.getOrNull(struct) ?: return 4091 - val next = definition["task_next_index", 4091] - if (!Tasks.hasRequirements(player, definition) || isCompleted(player, "${definition.stringId}_task") || player["task_pinned", -1] == if (index == 1) id else next) { - return nextTask(player, index, next) + if (pinned) { + player["task_slot_${i++}"] = player["task_pinned", 4091] + } else { + player["task_slot_${i++}"] = next + next = definition["task_next_index", 4091] + } } - return if (index == 1) id else next } fun pinned(player: Player, index: Int): Boolean { From 35b7d0fc46e6e49235c2d1d1e44af06b00a75e07 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 23 May 2024 12:16:15 +0100 Subject: [PATCH 18/48] Add first task --- .../voidps/world/activity/achievement/LumbridgeTasks.kts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts new file mode 100644 index 000000000..095825be2 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts @@ -0,0 +1,8 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.entity.character.mode.move.move +import world.gregs.voidps.engine.entity.character.move.running + +move({ player.visuals.runStep != -1 && player.running && !player["on_the_run_task", false] }) { + player["on_the_run_task"] = true +} \ No newline at end of file From 365495c410c02eb44659091fff9fabc95f87ac5a Mon Sep 17 00:00:00 2001 From: GregHib Date: Fri, 24 May 2024 21:05:09 +0100 Subject: [PATCH 19/48] Add task popup, display completed/total tasks, wipe pinned task on ok --- data/definitions/interface-types.yml | 6 ++- data/definitions/interfaces.yml | 5 ++ data/definitions/variables-client.yml | 24 ++++----- .../activity/achievement/LumbridgeTasks.kts | 6 +++ .../world/activity/achievement/TaskList.kts | 39 ++++++++++++-- .../world/activity/achievement/TaskSystem.kts | 53 +++++++++++++++---- 6 files changed, 106 insertions(+), 27 deletions(-) diff --git a/data/definitions/interface-types.yml b/data/definitions/interface-types.yml index 494822436..55f15e88c 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 4a0304820..73f1c7b9b 100644 --- a/data/definitions/interfaces.yml +++ b/data/definitions/interfaces.yml @@ -2550,6 +2550,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 diff --git a/data/definitions/variables-client.yml b/data/definitions/variables-client.yml index 90510cffa..cf20ec789 100644 --- a/data/definitions/variables-client.yml +++ b/data/definitions/variables-client.yml @@ -380,19 +380,19 @@ task_dont_show_again: id: 1421 format: boolean persist: true -task_disable_popups: - id: 1429 - format: boolean - persist: true -task_unknown1: - id: 1428 +task_popup: + id: 1425 format: int - persist: true -task_unknown2: - id: 1416 +task_previous_popup: + id: 1426 format: int - persist: true -task_unknown3: - id: 1425 +task_fade_in_cycle: + id: 1427 format: int +task_popup_summary: + id: 1428 + format: boolean +task_disable_popups: + id: 1429 + format: boolean persist: true \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts index 095825be2..2ced8dc27 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts @@ -1,7 +1,13 @@ package world.gregs.voidps.world.activity.achievement +import world.gregs.voidps.engine.client.ui.open 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.playerSpawn + +playerSpawn { player -> + player.open("task_popup") +} move({ player.visuals.runStep != -1 && player.running && !player["on_the_run_task", false] }) { player["on_the_run_task"] = true 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 index b0b3f053e..344c58107 100644 --- 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 @@ -9,16 +9,22 @@ 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.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 +} + interfaceOpen("task_list") { player -> refresh(player) player.sendVariable("task_progress_overall") player.sendVariable("task_hide_completed") player.sendVariable("task_filter_sets") - player.sendVariable("task_disable_popups") } interfaceOption("Select", "area_*", "task_list") { @@ -79,14 +85,20 @@ interfaceOption("Filter-done", "filter_done", "task_list") { } interfaceOption("Turn-off", "toggle_popups", "task_list") { - player["task_disable_popups"] = !player["task_disable_popups", false] + val disable = !player["task_disable_popups", false] + player["task_disable_popups"] = disable + if (disable) { + player.set("task_popup", 0) + player.set("task_previous_popup", 0) + } } fun refresh(player: Player) { player.sendVariable("task_list_area") - val int = areaId(player) - player.sendScript("task_main_list_populate", int, 999, 999) + val id = areaId(player) + player.sendScript("task_main_list_populate", id, 999, 999) player.interfaceOptions.unlockAll("task_list", "tasks", 0..100) + count(player) } variableSet("task_pin_index") { player -> @@ -104,4 +116,23 @@ fun pin(player: Player, index: Int) { player["task_pinned"] = id player["task_pin_index"] = find(player, id) } +} + +fun count(player: Player) { + val area = areaId(player) + var next = enumDefinitions.get("task_area_start_indices").getInt(area) + var total = 0 + var completed = 0 + val structs = enumDefinitions.get("task_structs") + while (next != -1 && next != 450) { + val struct = structs.getInt(next) + val definition = structDefinitions.getOrNull(struct) ?: break + if (isCompleted(player, definition.stringId)) { + completed++ + } + total++ + next = definition["task_next_index", -1] + } + player["task_progress_current"] = completed + player["task_progress_total"] = total } \ 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 4fa7a9876..7232805c9 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 @@ -12,7 +12,7 @@ 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() @@ -58,7 +58,6 @@ interfaceOption("Close", "close_hint", "task_system") { interfaceOption("Select Task", "task_*", "task_system") { val index = component.removePrefix("task_").toInt() player["selected_task"] = index - player["task_pins"] = index } interfaceOption("Toggle", "dont_show", "task_system") { @@ -71,6 +70,11 @@ interfaceOption("Open", "task_list", "task_system") { interfaceOption("OK", "ok", "task_system") { player.interfaces.sendVisibility("task_system", "summary_overlay", false) + val selected = player["selected_task", -1] + if (selected != -1 && selected == player["task_pin_index", -1]) { + player.clear("task_pinned") + player.clear("task_pin_index") + } refreshSlots(player) } @@ -112,29 +116,37 @@ variableSet("task_pin_index", "task_area") { player -> refreshSlots(player) } -variableSet("*_task", to = true) { player -> - refreshSlots(player) -} - fun refreshSlots(player: Player) { val areaId = areaId(player) var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) var i = 1 - while (i < 7 && next != 4091) { + var completed = 0 + var total = 0 + while (next != 4091 && next != 450) { val struct = enumDefinitions.get("task_structs").getInt(next) val definition = structDefinitions.getOrNull(struct) ?: break + total++ val pinned = pinned(player, i) - if (player["task_pinned", -1] == next && !pinned || !Tasks.hasRequirements(player, definition) || isCompleted(player, definition.stringId)) { + if (player["task_pinned", -1] == next && !pinned || !Tasks.hasRequirements(player, definition)) { + next = definition["task_next_index", 4091] + continue + } + if (isCompleted(player, definition.stringId)) { + completed++ next = definition["task_next_index", 4091] continue } if (pinned) { player["task_slot_${i++}"] = player["task_pinned", 4091] } else { - player["task_slot_${i++}"] = next + if (i < 7) { + player["task_slot_${i++}"] = next + } next = definition["task_next_index", 4091] } } + player["task_progress_total"] = total + player["task_progress_current"] = completed } fun pinned(player: Player, index: Int): Boolean { @@ -144,4 +156,25 @@ fun pinned(player: Player, index: Int): Boolean { fun areaId(player: Player) = variables.get("task_area")!!.values.toInt(player["task_area", "empty"]) -fun isCompleted(player: Player, id: String) = player[id, false] \ No newline at end of file +fun isCompleted(player: Player, id: String) = player[id, false] + +interfaceOption("Details", "details", "task_popup") { + player["task_popup_summary"] = true + player["tab"] = Tab.TaskSystem.name +} + +variableSet("*_task", from = false, to = true) { player -> + completeTask(player, key) +} + +variableSet("*_task", from = null, to = true) { player -> + completeTask(player, key) +} + +fun completeTask(player: Player, id: String) { + val definition = structDefinitions.get(id) + val index = definition["task_index", -1] + player["task_popup"] = index + player.inc("task_progress_overall") + refreshSlots(player) +} \ No newline at end of file From 519c754728cbfe91a314cc1c67f217658a819284 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 14:47:55 +0100 Subject: [PATCH 20/48] Add task complete messages, explorer jack and ring reward --- data/definitions/animations.yml | 3 +- data/definitions/graphics.yml | 3 +- data/definitions/npcs.yml | 7 +- data/definitions/variables-custom.yml | 118 +++++++++++++++++- data/spawns/npc-spawns.yml | 1 + .../activity/achievement/ExplorerJack.kts | 101 +++++++++++++++ .../activity/achievement/ExplorersRing.kts | 29 +++++ .../activity/achievement/LumbridgeTasks.kts | 8 +- .../world/activity/achievement/TaskSystem.kts | 40 +++++- .../entity/player/display/GameFrame.kts | 1 + 10 files changed, 299 insertions(+), 12 deletions(-) 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 diff --git a/data/definitions/animations.yml b/data/definitions/animations.yml index 9ac40d1f9..d8603c8cd 100644 --- a/data/definitions/animations.yml +++ b/data/definitions/animations.yml @@ -1696,4 +1696,5 @@ 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 diff --git a/data/definitions/graphics.yml b/data/definitions/graphics.yml index 32c062e00..ffd541a39 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/npcs.yml b/data/definitions/npcs.yml index 3bc5d9d72..84bcc9f53 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/variables-custom.yml b/data/definitions/variables-custom.yml index 578fa3c76..a9f27d882 100644 --- a/data/definitions/variables-custom.yml +++ b/data/definitions/variables-custom.yml @@ -339,4 +339,120 @@ 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 ] diff --git a/data/spawns/npc-spawns.yml b/data/spawns/npc-spawns.yml index 59c1e962a..e0796491f 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/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 000000000..0115a484a --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorerJack.kts @@ -0,0 +1,101 @@ +package world.gregs.voidps.world.activity.achievement + +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.entity.World +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.chat.inventoryFull +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.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["talk_to_explorer_jack_task", false]) { + npc("Ah! Welcome to ${World.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() + } + val finished = false + if (finished) { + 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.")// FIXME + 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["talk_to_explorer_jack_task"] = true +} + +suspend fun NPCOption.claim(inventoryId: String) { + npc("I'll just fill your $inventoryId with what you need, then.") + val inventory = player.inventories.inventory(inventoryId) + inventory.transaction { + add("coins", 1234) + } + when(inventory.transaction.error) { + is TransactionError.Full -> player.inventoryFull() + TransactionError.None -> { + player.message("You receive 12345 coins.") + npc("There you go.") + } + else -> { + } + } +} \ 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 000000000..9b7ddbff6 --- /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/LumbridgeTasks.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts index 2ced8dc27..6973706a7 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts @@ -1,14 +1,8 @@ package world.gregs.voidps.world.activity.achievement -import world.gregs.voidps.engine.client.ui.open 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.playerSpawn -playerSpawn { player -> - player.open("task_popup") -} - -move({ player.visuals.runStep != -1 && player.running && !player["on_the_run_task", false] }) { +move({ player.running && !player["on_the_run_task", false] }) { player["on_the_run_task"] = true } \ 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 7232805c9..97cd5f7b3 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,5 +1,7 @@ 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.interfaceOpen import world.gregs.voidps.engine.client.ui.interfaceOption import world.gregs.voidps.engine.client.ui.open @@ -11,6 +13,7 @@ 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.entity.character.player.skill.Skill import world.gregs.voidps.engine.inject import world.gregs.voidps.world.interact.entity.player.display.Tab @@ -175,6 +178,41 @@ fun completeTask(player: Player, id: String) { val definition = structDefinitions.get(id) val index = definition["task_index", -1] player["task_popup"] = index - player.inc("task_progress_overall") + val totalLevel = Skill.all.sumOf { if (it == Skill.Constitution) player.levels.getMax(it) / 10 else player.levels.getMax(it) } + if (totalLevel < 10) { + player.message("You have completed the Task '${definition["task_name", ""]}'!") + } else { + val areaName = enumDefinitions.get("task_area_names").getString(definition["task_area", 0]) + val difficultyName = enumDefinitions.get("task_difficulties").getString(definition["task_difficulty", 0]) + player.message("You have completed the Task '${definition["task_name", ""]}' in the $difficultyName $areaName set!") + } + 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 area = definition["task_area", 0] + val areaName = when(area) { + 1 -> "Lumbridge and Draynor" + 2 -> "Varrock" + 3 -> "Falador" + 4 -> "Seers' Village" + 5 -> "Ardougne" + 6 -> "Karamja" + 7 -> "Fremennik" + else -> "D&Ds and Activities" + } + val difficulty = definition["task_difficulty", 0] + val difficultyName = enumDefinitions.get("task_difficulties").getString(difficulty) + player.message("Congratulations! You have completed all of the $difficultyName Tasks in the $areaName") + 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.") + } } \ No newline at end of file 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 10bffcbd9..b98c34a9b 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", From 9bfb551ea69587a0241607c6430fa634abefbbd8 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 15:36:41 +0100 Subject: [PATCH 21/48] Extract task looping --- .../world/activity/achievement/TaskList.kts | 43 ++++-------- .../world/activity/achievement/TaskSystem.kts | 70 +++++++------------ .../world/activity/achievement/Tasks.kt | 30 ++++++++ 3 files changed, 70 insertions(+), 73 deletions(-) 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 index 344c58107..2307b493c 100644 --- 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 @@ -5,8 +5,6 @@ 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.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.character.player.Player import world.gregs.voidps.engine.entity.playerSpawn @@ -44,25 +42,16 @@ interfaceOption("Pin", "pin", "task_list") { pin(player, player["selected_task", 0]) } -val enumDefinitions: EnumDefinitions by inject() -val structDefinitions: StructDefinitions by inject() - -fun index(player: Player, index: Int, area: Int = areaId(player)): Int? { - var next = enumDefinitions.get("task_area_start_indices").getInt(area) +fun indexOfSlot(player: Player, slot: Int): Int? { var count = 0 - while (next != -1) { - val struct = enumDefinitions.get("task_structs").getInt(next) - val definition = structDefinitions.getOrNull(struct) ?: break - if (player["task_hide_completed", false] && isCompleted(player, definition.stringId)) { - count++ - continue - } - if (count++ == index) { - return next + return Tasks.forEach(areaId(player)) { + count++ + val incomplete = !player["task_hide_completed", false] || !isCompleted(player, definition.stringId) + if (incomplete && count - 1 == slot) { + return@forEach index } - next = definition["task_next_index", -1] + null } - return null } fun isCompleted(player: Player, id: String) = player.contains(id) && player[id, false] @@ -88,8 +77,8 @@ interfaceOption("Turn-off", "toggle_popups", "task_list") { val disable = !player["task_disable_popups", false] player["task_disable_popups"] = disable if (disable) { - player.set("task_popup", 0) - player.set("task_previous_popup", 0) + player["task_popup"] = 0 + player["task_previous_popup"] = 0 } } @@ -98,7 +87,7 @@ fun refresh(player: Player) { val id = areaId(player) player.sendScript("task_main_list_populate", id, 999, 999) player.interfaceOptions.unlockAll("task_list", "tasks", 0..100) - count(player) + refreshCompletedCount(player) } variableSet("task_pin_index") { player -> @@ -108,7 +97,7 @@ variableSet("task_pin_index") { player -> 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 = index(player, index) ?: return + val id = indexOfSlot(player, index) ?: return if (player["task_pinned", -1] == id) { player.clear("task_pinned") player.clear("task_pin_index") @@ -118,20 +107,14 @@ fun pin(player: Player, index: Int) { } } -fun count(player: Player) { - val area = areaId(player) - var next = enumDefinitions.get("task_area_start_indices").getInt(area) +fun refreshCompletedCount(player: Player) { var total = 0 var completed = 0 - val structs = enumDefinitions.get("task_structs") - while (next != -1 && next != 450) { - val struct = structs.getInt(next) - val definition = structDefinitions.getOrNull(struct) ?: break + Tasks.forEach(areaId(player)) { if (isCompleted(player, definition.stringId)) { completed++ } total++ - next = definition["task_next_index", -1] } player["task_progress_current"] = completed player["task_progress_total"] = total 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 97cd5f7b3..286140699 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 @@ -29,17 +29,11 @@ interfaceOpen("task_system") { player -> if (player.contains("task_dont_show_again")) { player.sendVariable("task_dont_show_again") } - if (!player.contains("task_progress_total")) { - player["task_progress_total"] = 0 - } else { - player.sendVariable("task_progress_total") - } + player.sendVariable("task_progress_total") } enterArea("lumbridge") { player["task_area"] = "lumbridge_draynor" - player["task_progress_current"] = 0 - player["task_progress_total"] = 124 } exitArea("lumbridge") { @@ -87,32 +81,29 @@ interfaceOption("Pin/Unpin Task", "task_*", "task_system") { player.clear("task_pinned") player.clear("task_pin_index") } else { - player["task_pinned"] = index(player, index) ?: return@interfaceOption + player["task_pinned"] = indexOfSlot(player, index) ?: return@interfaceOption player["task_pin_index"] = index } } -fun index(player: Player, index: Int, areaId: Int = areaId(player)): Int? { - var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) +fun indexOfSlot(player: Player, slot: Int): Int? { var count = 1 - while (next != -1) { - val struct = enumDefinitions.get("task_structs").getInt(next) - val definition = structDefinitions.getOrNull(struct) ?: break - if (player["task_hide_completed", false] && isCompleted(player, definition.stringId) || definition["task_members", 0] == 1 && !World.members) { - count++ - continue + return Tasks.forEach(areaId(player)) { + count++ + val hideCompleted = player["task_hide_completed", false] && isCompleted(player, definition.stringId) + val hideMembers = definition["task_members", 0] == 1 && !World.members + if (hideCompleted || hideMembers) { + return@forEach null } - if (count == index) { - return next + if (count - 1 == slot) { + return@forEach this.index } - if (player["task_pin_index", -1] == count) { - count++ - continue + val skipPinned = player["task_pin_index", -1] == count + if (skipPinned) { + skip = true } - count++ - next = definition["task_next_index", -1] + null } - return null } variableSet("task_pin_index", "task_area") { player -> @@ -120,33 +111,26 @@ variableSet("task_pin_index", "task_area") { player -> } fun refreshSlots(player: Player) { - val areaId = areaId(player) - var next = enumDefinitions.get("task_area_start_indices").getInt(areaId) - var i = 1 + var slot = 1 var completed = 0 var total = 0 - while (next != 4091 && next != 450) { - val struct = enumDefinitions.get("task_structs").getInt(next) - val definition = structDefinitions.getOrNull(struct) ?: break + Tasks.forEach(areaId(player)) { total++ - val pinned = pinned(player, i) - if (player["task_pinned", -1] == next && !pinned || !Tasks.hasRequirements(player, definition)) { - next = definition["task_next_index", 4091] - continue + val pinned = pinned(player, slot) + if (player["task_pinned", -1] == index && !pinned || !Tasks.hasRequirements(player, definition)) { + return@forEach null } if (isCompleted(player, definition.stringId)) { completed++ - next = definition["task_next_index", 4091] - continue + return@forEach null } if (pinned) { - player["task_slot_${i++}"] = player["task_pinned", 4091] - } else { - if (i < 7) { - player["task_slot_${i++}"] = next - } - next = definition["task_next_index", 4091] + player["task_slot_${slot++}"] = player["task_pinned", 4091] + skip = true + } else if (slot < 7) { + player["task_slot_${slot++}"] = index } + null } player["task_progress_total"] = total player["task_progress_current"] = completed @@ -194,7 +178,7 @@ fun completeTask(player: Player, id: String) { val maximum = player["task_progress_total", -1] if (before != after && after == maximum) { val area = definition["task_area", 0] - val areaName = when(area) { + val areaName = when (area) { 1 -> "Lumbridge and Draynor" 2 -> "Varrock" 3 -> "Falador" 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 index 6979f14eb..a80db19b8 100644 --- 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 @@ -1,7 +1,9 @@ package world.gregs.voidps.world.activity.achievement import world.gregs.voidps.cache.config.data.StructDefinition +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 @@ -17,6 +19,34 @@ import java.util.concurrent.TimeUnit object Tasks { + 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] From ddd589bdc1c26916b577b28eb9faada400e19899 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 18:25:54 +0100 Subject: [PATCH 22/48] Add message wrap around --- .../world/gregs/voidps/engine/client/EncodeExtensions.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 0e1f3ab30..6e62e901e 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() { From c3f720cf91c39421c6983ddfd6ca707b442b2807 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 18:26:23 +0100 Subject: [PATCH 23/48] Rename bot variables --- .../world/gregs/voidps/bot/BotSpawns.kts | 2 +- .../world/gregs/voidps/bot/DecisionMaking.kts | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) 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 20890d55b..2255c8e9b 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 6b4e67367..862c2fb00 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 From 6c13051608db3168f350c0dcfdb3676195c15644 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 18:27:13 +0100 Subject: [PATCH 24/48] Add boolean support to script command --- .../gregs/voidps/world/command/debug/InterfaceCommands.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b4c75e2f1..dde1eae80 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 @@ -73,7 +73,7 @@ adminCommand("setting") { adminCommand("script") { val parts = content.split(" ") - val remainder = parts.subList(1, parts.size).map { it.toIntOrNull() ?: it } + 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()) From e95574448a455bb4a005d690bf7979a991267cc3 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 18:28:09 +0100 Subject: [PATCH 25/48] Add initial explorer jack task --- data/definitions/scripts.yml | 3 + data/definitions/variables-player-bit.yml | 6 +- data/definitions/variables-player.yml | 4 +- .../activity/achievement/ExplorerJack.kts | 30 ++++++--- .../world/activity/achievement/TaskList.kts | 12 ++-- .../world/activity/achievement/TaskSystem.kts | 64 +++++++++---------- .../world/activity/achievement/Tasks.kt | 11 ++++ .../voidps/world/activity/quest/Quests.kts | 2 +- 8 files changed, 82 insertions(+), 50 deletions(-) diff --git a/data/definitions/scripts.yml b/data/definitions/scripts.yml index f7346a1d4..7d9ef3771 100644 --- a/data/definitions/scripts.yml +++ b/data/definitions/scripts.yml @@ -25,3 +25,6 @@ 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/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index 5994192e8..aa1df7d81 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -996,8 +996,12 @@ kings_ransom: # D&Ds / Activities None introducing_explorer_jack_task: id: 6494 - format: boolean + format: map persist: true + default: unstarted + values: + unstarted: 0 + completed: 3 # Varrock Easy strike_a_pose_task: id: 3986 diff --git a/data/definitions/variables-player.yml b/data/definitions/variables-player.yml index 747e749e8..85f84826c 100644 --- a/data/definitions/variables-player.yml +++ b/data/definitions/variables-player.yml @@ -132,11 +132,11 @@ unstable_foundations: id: 281 persist: true format: map - default: complete + default: completed values: unstarted: 0 incomplete: 1 - complete: 1000 + completed: 1000 skill_stat_flash: id: 1179 persist: true 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 index 0115a484a..7ca70f7e3 100644 --- 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 @@ -1,14 +1,17 @@ package world.gregs.voidps.world.activity.achievement import world.gregs.voidps.engine.client.message -import world.gregs.voidps.engine.entity.World +import world.gregs.voidps.engine.client.sendScript 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.getProperty 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 @@ -18,13 +21,12 @@ 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["talk_to_explorer_jack_task", false]) { - npc("Ah! Welcome to ${World.name}, lad. My name's Explorer jack. I'm an explorer by trade, and I'm one of the Taskmasters around these parts") + if (player["introducing_explorer_jack_task", "uncompleted"] == "uncompleted") { + npc("Ah! Welcome to ${getProperty("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() } - val finished = false - if (finished) { + 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?") @@ -71,7 +73,7 @@ npcOperate("Talk-to", "explorer_jack") { 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.")// FIXME + 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 */ } @@ -80,7 +82,10 @@ 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["talk_to_explorer_jack_task"] = true + player["introducing_explorer_jack_task"] = "completed" + player["unstable_foundations"] = "completed" + player.sendScript("task_list_button_hide", 0) + player.interfaces.sendVisibility("task_system", "ok", true) } suspend fun NPCOption.claim(inventoryId: String) { @@ -89,7 +94,7 @@ suspend fun NPCOption.claim(inventoryId: String) { inventory.transaction { add("coins", 1234) } - when(inventory.transaction.error) { + when (inventory.transaction.error) { is TransactionError.Full -> player.inventoryFull() TransactionError.None -> { player.message("You receive 12345 coins.") @@ -98,4 +103,13 @@ suspend fun NPCOption.claim(inventoryId: String) { 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/TaskList.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/TaskList.kts index 2307b493c..965419aff 100644 --- 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 @@ -31,7 +31,7 @@ interfaceOption("Select", "area_*", "task_list") { } interfaceOption("Summary", "tasks", "task_list") { - player["selected_task"] = itemSlot / 4 + player["task_selected"] = itemSlot / 4 } interfaceOption("Pin", "tasks", "task_list") { @@ -39,14 +39,14 @@ interfaceOption("Pin", "tasks", "task_list") { } interfaceOption("Pin", "pin", "task_list") { - pin(player, player["selected_task", 0]) + pin(player, player["task_selected", 0]) } fun indexOfSlot(player: Player, slot: Int): Int? { var count = 0 return Tasks.forEach(areaId(player)) { count++ - val incomplete = !player["task_hide_completed", false] || !isCompleted(player, definition.stringId) + val incomplete = !player["task_hide_completed", false] || !Tasks.isCompleted(player, definition.stringId) if (incomplete && count - 1 == slot) { return@forEach index } @@ -54,8 +54,6 @@ fun indexOfSlot(player: Player, slot: Int): Int? { } } -fun isCompleted(player: Player, id: String) = player.contains(id) && player[id, false] - fun find(player: Player, id: Int): Int { for (i in 0 until 6) { if (player["task_slot_${i}", -1] == id) { @@ -111,10 +109,12 @@ fun refreshCompletedCount(player: Player) { var total = 0 var completed = 0 Tasks.forEach(areaId(player)) { - if (isCompleted(player, definition.stringId)) { + if (Tasks.isCompleted(player, definition.stringId)) { completed++ + player.sendVariable(definition.stringId) } total++ + null } player["task_progress_current"] = completed player["task_progress_total"] = total 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 286140699..32b14aff5 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 @@ -13,7 +13,6 @@ 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.entity.character.player.skill.Skill import world.gregs.voidps.engine.inject import world.gregs.voidps.world.interact.entity.player.display.Tab @@ -22,14 +21,22 @@ val enumDefinitions: EnumDefinitions by inject() val structDefinitions: StructDefinitions by inject() interfaceOpen("task_system") { player -> - player.sendVariable("task_introducing_explorer_jack") 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") } - player.sendVariable("task_progress_total") + if (player.contains("task_progress_overall")) { + player.sendVariable("task_progress_overall") + } else { + player["task_progress_overall"] = 0 + player["task_pinned"] = 3520 // Talk to explorer jack + player["task_pin_index"] = 1 + player["task_selected"] = 1 + player["unstable_foundations"] = "incomplete" + } } enterArea("lumbridge") { @@ -54,7 +61,7 @@ interfaceOption("Close", "close_hint", "task_system") { interfaceOption("Select Task", "task_*", "task_system") { val index = component.removePrefix("task_").toInt() - player["selected_task"] = index + player["task_selected"] = index } interfaceOption("Toggle", "dont_show", "task_system") { @@ -67,10 +74,11 @@ interfaceOption("Open", "task_list", "task_system") { interfaceOption("OK", "ok", "task_system") { player.interfaces.sendVisibility("task_system", "summary_overlay", false) - val selected = player["selected_task", -1] + 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) } @@ -90,7 +98,7 @@ fun indexOfSlot(player: Player, slot: Int): Int? { var count = 1 return Tasks.forEach(areaId(player)) { count++ - val hideCompleted = player["task_hide_completed", false] && isCompleted(player, definition.stringId) + val hideCompleted = player["task_hide_completed", false] && Tasks.isCompleted(player, definition.stringId) val hideMembers = definition["task_members", 0] == 1 && !World.members if (hideCompleted || hideMembers) { return@forEach null @@ -120,7 +128,7 @@ fun refreshSlots(player: Player) { if (player["task_pinned", -1] == index && !pinned || !Tasks.hasRequirements(player, definition)) { return@forEach null } - if (isCompleted(player, definition.stringId)) { + if (Tasks.isCompleted(player, definition.stringId)) { completed++ return@forEach null } @@ -143,32 +151,33 @@ fun pinned(player: Player, index: Int): Boolean { fun areaId(player: Player) = variables.get("task_area")!!.values.toInt(player["task_area", "empty"]) -fun isCompleted(player: Player, id: String) = player[id, false] +/* + Task completion + */ interfaceOption("Details", "details", "task_popup") { player["task_popup_summary"] = true player["tab"] = Tab.TaskSystem.name } -variableSet("*_task", from = false, to = true) { player -> - completeTask(player, key) -} - -variableSet("*_task", from = null, to = true) { player -> - completeTask(player, key) +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 totalLevel = Skill.all.sumOf { if (it == Skill.Constitution) player.levels.getMax(it) / 10 else player.levels.getMax(it) } - if (totalLevel < 10) { - player.message("You have completed the Task '${definition["task_name", ""]}'!") - } else { - val areaName = enumDefinitions.get("task_area_names").getString(definition["task_area", 0]) - val difficultyName = enumDefinitions.get("task_difficulties").getString(definition["task_difficulty", 0]) + 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) @@ -177,20 +186,11 @@ fun completeTask(player: Player, id: String) { val after = player["task_progress_current", 0] val maximum = player["task_progress_total", -1] if (before != after && after == maximum) { - val area = definition["task_area", 0] - val areaName = when (area) { + val prettyName = when (area) { 1 -> "Lumbridge and Draynor" - 2 -> "Varrock" - 3 -> "Falador" - 4 -> "Seers' Village" - 5 -> "Ardougne" - 6 -> "Karamja" - 7 -> "Fremennik" - else -> "D&Ds and Activities" + else -> areaName } - val difficulty = definition["task_difficulty", 0] - val difficultyName = enumDefinitions.get("task_difficulties").getString(difficulty) - player.message("Congratulations! You have completed all of the $difficultyName Tasks in the $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" 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 index a80db19b8..d77532b99 100644 --- 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 @@ -1,6 +1,8 @@ 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 @@ -19,6 +21,15 @@ 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 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 61cfa7627..aae5cd72b 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", @@ -19,5 +20,4 @@ adminCommand("quests") { } player["quest_points"] = 7 player.refreshQuestJournal() - player["task_introducing_explorer_jack"] = 3 } \ No newline at end of file From f28944609f3994afa485e030e871e3ba2c7862dd Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 19:10:05 +0100 Subject: [PATCH 26/48] Add task set filtering --- data/definitions/parameters.yml | 2 +- .../voidps/world/activity/achievement/TaskList.kts | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/data/definitions/parameters.yml b/data/definitions/parameters.yml index d992797f1..1bc9f8180 100644 --- a/data/definitions/parameters.yml +++ b/data/definitions/parameters.yml @@ -377,7 +377,7 @@ task_selectable_4: 1285 task_selectable_5: 1286 task_selectable_6: 1287 task_members: 1290 -task_group: 1292 +task_set: 1292 task_sprite_offset: 1293 task_skill_1: 1294 task_level_1: 1295 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 index 965419aff..068b868a0 100644 --- 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 @@ -45,9 +45,13 @@ interfaceOption("Pin", "pin", "task_list") { fun indexOfSlot(player: Player, slot: Int): Int? { var count = 0 return Tasks.forEach(areaId(player)) { - count++ - val incomplete = !player["task_hide_completed", false] || !Tasks.isCompleted(player, definition.stringId) - if (incomplete && count - 1 == slot) { + 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 From 2fc524d5a3e83ecad457d4cafea002c735cd1828 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 19:22:48 +0100 Subject: [PATCH 27/48] Fix quest complete checks --- data/definitions/structs.yml | 4 ++-- .../voidps/world/activity/achievement/TaskList.kts | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/data/definitions/structs.yml b/data/definitions/structs.yml index 7657e4e31..24ec2ce37 100644 --- a/data/definitions/structs.yml +++ b/data/definitions/structs.yml @@ -249,10 +249,10 @@ three_rounds_rapid_men_task: 1536 death_from_above_task: 1537 flour_power_task: 1538 a_labour_of_loaf_task: 1539 -cooks_assistant_task: 1250 +cooks_assistant: 1250 om_nom_nom_nom_task: 1540 on_the_level_task: 1541 -rune_mysteries_task: 1251 +rune_mysteries: 1251 so_thats_what_ess_stands_for_task: 1542 air_craft_task: 1543 greasing_the_wheels_of_commerce_task: 1544 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 index 068b868a0..177583b28 100644 --- 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 @@ -16,13 +16,20 @@ playerSpawn { player -> player.sendVariable("task_disable_popups") player["task_popup"] = 0 player["task_previous_popup"] = 0 + Tasks.forEach(areaId(player)) { + if (Tasks.isCompleted(player, definition.stringId)) { + player.sendVariable(definition.stringId) + } + null + } + player.sendVariable("task_progress_overall") + player.sendVariable("task_hide_completed") + player.sendVariable("task_filter_sets") } interfaceOpen("task_list") { player -> + player.interfaceOptions.unlockAll("task_list", "tasks", 0..492) refresh(player) - player.sendVariable("task_progress_overall") - player.sendVariable("task_hide_completed") - player.sendVariable("task_filter_sets") } interfaceOption("Select", "area_*", "task_list") { @@ -88,7 +95,6 @@ fun refresh(player: Player) { player.sendVariable("task_list_area") val id = areaId(player) player.sendScript("task_main_list_populate", id, 999, 999) - player.interfaceOptions.unlockAll("task_list", "tasks", 0..100) refreshCompletedCount(player) } From 43ba646ca6c39a50b93f59b52e18d450bb13308f Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 19:30:26 +0100 Subject: [PATCH 28/48] Check overall progress dynamically --- data/definitions/variables-player-bit.yml | 1 - data/definitions/variables-player.yml | 2 +- .../voidps/world/activity/achievement/TaskList.kts | 14 +++++++++----- .../world/activity/achievement/TaskSystem.kts | 5 +---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/data/definitions/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index aa1df7d81..faae85e3f 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -703,7 +703,6 @@ task_area: task_progress_overall: id: 8601 format: int - persist: true task_list_area: id: 8582 format: map diff --git a/data/definitions/variables-player.yml b/data/definitions/variables-player.yml index 85f84826c..f95294ddd 100644 --- a/data/definitions/variables-player.yml +++ b/data/definitions/variables-player.yml @@ -132,7 +132,7 @@ unstable_foundations: id: 281 persist: true format: map - default: completed + default: unstarted values: unstarted: 0 incomplete: 1 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 index 177583b28..e1206029f 100644 --- 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 @@ -16,13 +16,17 @@ playerSpawn { player -> player.sendVariable("task_disable_popups") player["task_popup"] = 0 player["task_previous_popup"] = 0 - Tasks.forEach(areaId(player)) { - if (Tasks.isCompleted(player, definition.stringId)) { - player.sendVariable(definition.stringId) + var total = 0 + for (area in 0 until 8) { + Tasks.forEach(area) { + if (Tasks.isCompleted(player, definition.stringId)) { + player.sendVariable(definition.stringId) + total++ + } + null } - null } - player.sendVariable("task_progress_overall") + player["task_progress_overall"] = total player.sendVariable("task_hide_completed") player.sendVariable("task_filter_sets") } 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 32b14aff5..086d4c356 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 @@ -28,10 +28,7 @@ interfaceOpen("task_system") { player -> if (player.contains("task_dont_show_again")) { player.sendVariable("task_dont_show_again") } - if (player.contains("task_progress_overall")) { - player.sendVariable("task_progress_overall") - } else { - player["task_progress_overall"] = 0 + if (player["unstable_foundations", "unstarted"] == "unstarted") { player["task_pinned"] = 3520 // Talk to explorer jack player["task_pin_index"] = 1 player["task_selected"] = 1 From 0a1e1b7cf856b041c51886d1e7d1b40398c3dc3a Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 25 May 2024 22:49:33 +0100 Subject: [PATCH 29/48] Start adding lumbridge beginner tasks --- data/definitions/objects.yml | 3 + data/definitions/variables-custom.yml | 18 + data/definitions/variables-player-bit.yml | 8 - data/definitions/variables-player.yml | 3 + data/map/teleports.yml | 2 +- .../client/instruction/handle/WalkHandler.kt | 3 + .../gregs/voidps/engine/inv/ItemChanged.kt | 8 + .../activity/achievement/ExplorerJack.kts | 12 +- .../achievement/LumbridgeBeginnerTasks.kts | 308 ++++++++++++++++++ .../activity/achievement/LumbridgeTasks.kts | 8 - .../world/activity/skill/ItemOnItems.kts | 6 + .../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/interact/entity/combat/Target.kt | 3 + .../world/interact/entity/death/NPCDeath.kts | 8 +- .../world/interact/entity/npc/Banker.kts | 3 +- .../interact/entity/npc/shop/ShopSell.kts | 4 +- .../entity/player/combat/consume/Eating.kts | 4 +- .../entity/player/display/tab/Emotes.kts | 13 +- .../voidps/world/map/al_kharid/Ellis.kts | 2 + .../world/map/lumbridge/LumbridgeFlag.kts | 1 + .../voidps/network/client/instruction/Walk.kt | 2 +- .../protocol/decode/WalkMiniMapDecoder.kt | 2 +- 26 files changed, 395 insertions(+), 36 deletions(-) create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasks.kts delete mode 100644 game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts diff --git a/data/definitions/objects.yml b/data/definitions/objects.yml index 6c12488b0..3f6dcd9f1 100644 --- a/data/definitions/objects.yml +++ b/data/definitions/objects.yml @@ -11836,3 +11836,6 @@ 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." \ No newline at end of file diff --git a/data/definitions/variables-custom.yml b/data/definitions/variables-custom.yml index a9f27d882..438a19381 100644 --- a/data/definitions/variables-custom.yml +++ b/data/definitions/variables-custom.yml @@ -456,3 +456,21 @@ 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 \ No newline at end of file diff --git a/data/definitions/variables-player-bit.yml b/data/definitions/variables-player-bit.yml index faae85e3f..c11465a54 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 diff --git a/data/definitions/variables-player.yml b/data/definitions/variables-player.yml index f95294ddd..3da4a6762 100644 --- a/data/definitions/variables-player.yml +++ b/data/definitions/variables-player.yml @@ -603,3 +603,6 @@ prince_ali_rescue: values: unstarted: 0 completed: 110 +task_reward_items: + id: 1959 + format: int diff --git a/data/map/teleports.yml b/data/map/teleports.yml index 3cc0d9b50..4bd47264e 100644 --- a/data/map/teleports.yml +++ b/data/map/teleports.yml @@ -3660,7 +3660,7 @@ level: 1 delta: level: -1 -- id: 36771 +- id: lumbridge_castle_ladder option: Climb-up tile: x: 3207 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 c418874a1..5da343c94 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/inv/ItemChanged.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/inv/ItemChanged.kt index 405e12d59..27d2004b2 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/world/activity/achievement/ExplorerJack.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/ExplorerJack.kts index 7ca70f7e3..e82e87ebb 100644 --- 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 @@ -2,11 +2,11 @@ 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.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.getProperty import world.gregs.voidps.engine.inv.add import world.gregs.voidps.engine.inv.inventory import world.gregs.voidps.engine.inv.transact.TransactionError @@ -22,7 +22,7 @@ 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 ${getProperty("name")}, lad. My name's Explorer jack. I'm an explorer by trade, and I'm one of the Taskmasters around these parts") + 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() } @@ -91,14 +91,18 @@ suspend fun NPCOption.whatIsTaskSystem() { suspend fun NPCOption.claim(inventoryId: String) { npc("I'll just fill your $inventoryId with what you need, then.") val inventory = player.inventories.inventory(inventoryId) + var coins = 1234 inventory.transaction { - add("coins", 1234) + add("coins", coins) } when (inventory.transaction.error) { is TransactionError.Full -> player.inventoryFull() TransactionError.None -> { - player.message("You receive 12345 coins.") + player.message("You receive $coins coins.") npc("There you go.") + if (coins > 100) { + player["must_be_funny_in_a_rich_mans_world_task"] = true + } } else -> { } 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 000000000..0c8701870 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasks.kts @@ -0,0 +1,308 @@ +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.move +import world.gregs.voidps.engine.entity.character.move.previousTile +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.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.obj.teleportLand +import world.gregs.voidps.world.interact.entity.player.combat.prayer.prayerStart + +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("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.softTimers.contains("firemaking") && !player["log_a_rhythm_task", false]) { + player["burnt_regular_log"] = true + } +} + +timerStop("firemaking") { player -> + val regular: Boolean = player.remove("burnt_regular_log") ?: return@timerStop + if (regular) { + val fire = objects.getShape(player.previousTile, 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"] = 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 + } + } + EquipSlot.Weapon.index -> { + if (item.id.contains("iron")) { + player["not_what_we_mean_by_irony_task"] = true + } else if (item.id.contains("steel")) { + player["steel_yourself_for_combat_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") + } + } + } + } + } + EquipSlot.Ammo.index -> if (item.id == "steel_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", from = 9, to = 10) { player -> + player["on_your_way_task"] = true +} + +itemAdded(inventory = "bank") { player -> + player["hang_on_to_something_task"] = true +} + +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]) { + val total = Skill.all.sumOf { if (it == Skill.Constitution) player.levels.getMax(it) / 10 else player.levels.getMax(it) } + if (total == 10) { + player["on_the_level_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 + } +} + +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, to = 5) { player -> + if (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, to = 5) { player -> + 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 + } +} + +itemAdded("raw_shrimps", inventory = "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 + } +} + +combatAttack(spell = "confuse") { player -> + player["not_so_confusing_after_all_task"] = true +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts deleted file mode 100644 index 6973706a7..000000000 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeTasks.kts +++ /dev/null @@ -1,8 +0,0 @@ -package world.gregs.voidps.world.activity.achievement - -import world.gregs.voidps.engine.entity.character.mode.move.move -import world.gregs.voidps.engine.entity.character.move.running - -move({ player.running && !player["on_the_run_task", false] }) { - player["on_the_run_task"] = true -} \ No newline at end of file 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 839160768..056009e21 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/crafting/Pottery.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/skill/crafting/Pottery.kts index f3e65433e..e48db682d 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 d82f5acc8..a86519877 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 aee02c5fd..55bab2fe8 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 abe6eed72..9efa0cec8 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 4a02567b0..3bbae4a78 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/interact/entity/combat/Target.kt b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/combat/Target.kt index ade9dcc08..177081643 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 a42d6109f..ba0105c6c 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 732a035a6..e8305ff99 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 @@ -47,6 +47,7 @@ suspend fun CharacterContext.menu() { option("I'd like to see my Returned Items box.", block = { player.open("returned_items") }) option("What is this place?") { npc("This is a branch of the Bank of $name. We have branches in many towns.") + player["you_can_bank_on_us_task"] = true 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.") 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 763670efc..705a891da 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 @@ -72,6 +72,8 @@ fun sell(player: Player, item: Item, amount: Int) { } } TransactionError.Invalid -> player.message("You can't sell this item to this shop.") - else -> {} + else -> { + player["greasing_the_wheels_of_commerce_task"] = true + } } } \ 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 13384978b..258b7ac8a 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/display/tab/Emotes.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Emotes.kts index d01dec36a..ac4fe2ca6 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 ff2586a54..5d4a4c252 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 @@ -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/lumbridge/LumbridgeFlag.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeFlag.kts index 3420c64c0..e3d9599a7 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/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 e709f6d7f..7d242cd36 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/login/protocol/decode/WalkMiniMapDecoder.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WalkMiniMapDecoder.kt index 6272bffcd..7c179a66c 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 From 679b1f00e2ba4befd3aa0135b645cbdd13a53a7c Mon Sep 17 00:00:00 2001 From: GregHib Date: Sun, 26 May 2024 17:57:30 +0100 Subject: [PATCH 30/48] Add remaining lumbridge beginner tasks --- data/definitions/animations.yml | 1 + data/definitions/jingles.yml | 3 +- data/definitions/midis.yml | 3 +- data/definitions/objects.yml | 8 +++- data/map/areas.yml | 20 +++++++- .../achievement/LumbridgeBeginnerTasks.kts | 48 ++++++++++++++++++- .../world/interact/entity/npc/Banker.kts | 3 +- .../interact/entity/npc/shop/OpenShop.kt | 8 +++- .../player/combat/consume/drink/Ale.kts | 1 + .../voidps/world/map/al_kharid/Tollgate.kts | 3 +- .../world/map/lumbridge/DukeHoracio.kts | 1 + .../world/map/lumbridge/LumbridgeChurch.kts | 19 ++++++++ 12 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/LumbridgeChurch.kts diff --git a/data/definitions/animations.yml b/data/definitions/animations.yml index d8603c8cd..799f6e603 100644 --- a/data/definitions/animations.yml +++ b/data/definitions/animations.yml @@ -1698,3 +1698,4 @@ wolves_hit: 6557 wolves_attack: 6559 wolves_death: 6558 run_replenish: 9988 +play_organ: 3675 diff --git a/data/definitions/jingles.yml b/data/definitions/jingles.yml index 92ef26998..e6857f6e3 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 b2683f474..e79058c70 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/objects.yml b/data/definitions/objects.yml index 3f6dcd9f1..0e3275c0b 100644 --- a/data/definitions/objects.yml +++ b/data/definitions/objects.yml @@ -11838,4 +11838,10 @@ ourania_altar: examine: "An altar upon which to craft runes." lumbridge_castle_ladder: id: 36771 - examine: "I can climb up this." \ No newline at end of file + examine: "I can climb up this." +lumbridge_organ: + id: 36978 + examine: "A church organ." +lumbridge_church_bell: + id: 36976 + examine: "I can ring this." diff --git a/data/map/areas.yml b/data/map/areas.yml index 2e9791283..16742f468 100644 --- a/data/map/areas.yml +++ b/data/map/areas.yml @@ -627,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: 3 + tags: [ multi_combat ] draynor_village_multi_area: area: x: [ 3112, 3136, 3136, 3104, 3104, 3112 ] @@ -1028,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/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 index 0c8701870..7af9dec36 100644 --- 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 @@ -3,6 +3,7 @@ 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.previousTile import world.gregs.voidps.engine.entity.character.move.running @@ -22,8 +23,10 @@ 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.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 @@ -135,6 +138,9 @@ itemChange("worn_equipment") { player -> player.clear("equip_crossbow") } } + if (item.id == "oak_shortbow" || item.id == "oak_longbow") { + player["heart_of_oak_task"] = true + } } } } @@ -190,10 +196,12 @@ itemReplaced(to = "bread", inventory = "inventory") { player -> } maxLevelChange { player -> - if (!player["on_the_level_task", false]) { + 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 else player.levels.getMax(it) } if (total == 10) { player["on_the_level_task"] = true + } else if (total == 25) { + player["quarter_centurion_task"] = true } } } @@ -303,6 +311,44 @@ itemReplaced("raw_herring", "herring", "inventory") { player -> } } +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 = "ranged") { player -> + if (player.ammo == "steel_arrow") { + player["get_the_point_task"] = true + } +} + +variableSet("quest_points") { player -> + if (from != null && to != null && (from as Int) < 4 && 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/interact/entity/npc/Banker.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/Banker.kts index e8305ff99..6e7f3bf55 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 @@ -47,13 +47,14 @@ suspend fun CharacterContext.menu() { option("I'd like to see my Returned Items box.", block = { player.open("returned_items") }) option("What is this place?") { npc("This is a branch of the Bank of $name. We have branches in many towns.") - player["you_can_bank_on_us_task"] = true 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.") + player["you_can_bank_on_us_task"] = true } 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.") + player["you_can_bank_on_us_task"] = true } } } 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 15f700217..08d30e8c2 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,22 @@ 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 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/player/combat/consume/drink/Ale.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/combat/consume/drink/Ale.kts index dd550a7cf..a9d257578 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/map/al_kharid/Tollgate.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Tollgate.kts index 606f3b51d..a2b012820 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 d15762a3b..39c9b1e23 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 000000000..13c7c7ea4 --- /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 From 310f53e83cec5f7a1b2fc2edb5c83a31adfab4fd Mon Sep 17 00:00:00 2001 From: GregHib Date: Sun, 26 May 2024 19:19:21 +0100 Subject: [PATCH 31/48] Add experience lamp dialogue and antique lamp --- data/definitions/interfaces.yml | 32 ++++++++- data/definitions/variables-player.yml | 67 ++++++++++--------- .../activity/achievement/AntiqueLamp.kts | 16 +++++ .../interact/dialogue/ExperienceLamp.kts | 15 +++++ .../interact/dialogue/type/ExpSkillLamp.kt | 17 +++++ .../world/interact/dialogue/type/LevelUp.kts | 2 +- 6 files changed, 115 insertions(+), 34 deletions(-) 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/interact/dialogue/ExperienceLamp.kts create mode 100644 game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/type/ExpSkillLamp.kt diff --git a/data/definitions/interfaces.yml b/data/definitions/interfaces.yml index 73f1c7b9b..93be4ecc8 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 diff --git a/data/definitions/variables-player.yml b/data/definitions/variables-player.yml index 3da4a6762..c16ed4a6b 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,7 +127,7 @@ rune_mysteries: research_package: 3 package_delivered: 4 research_notes: 5 - completed: 6 + completed: 6 unstable_foundations: id: 281 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 @@ -606,3 +606,6 @@ prince_ali_rescue: task_reward_items: id: 1959 format: int +stat_advance_selected_skill: + id: 261 + format: int 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 000000000..3b3b912e3 --- /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/interact/dialogue/ExperienceLamp.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/dialogue/ExperienceLamp.kts new file mode 100644 index 000000000..2b1c2a650 --- /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 000000000..479c8e80f --- /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 b55e64cc9..e78dfa71d 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)) } } From 2744bd1809e7667c73f075d79728e09e75ad5ff5 Mon Sep 17 00:00:00 2001 From: GregHib Date: Sun, 26 May 2024 20:49:12 +0100 Subject: [PATCH 32/48] Start adding task unit tests --- .../achievement/LumbridgeBeginnerTasksTest.kt | 90 +++++++++++++++++++ .../voidps/world/activity/skill/MiningTest.kt | 1 - 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt 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 000000000..5683de753 --- /dev/null +++ b/game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt @@ -0,0 +1,90 @@ +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.entity.character.move.running +import world.gregs.voidps.engine.entity.character.player.skill.Skill +import world.gregs.voidps.engine.inv.add +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.network.client.instruction.Walk +import world.gregs.voidps.type.Tile +import world.gregs.voidps.type.setRandom +import world.gregs.voidps.world.script.WorldTest +import world.gregs.voidps.world.script.objectOption +import kotlin.test.assertTrue + +internal class LumbridgeBeginnerTasksTest : WorldTest() { + + @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]) + } +} \ 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 759822b55..f59287445 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 From 3a431a51bdfb8ef6c9d2ee0775776a0c9298e435 Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 27 May 2024 21:09:22 +0100 Subject: [PATCH 33/48] Fix using spells on magic dummy --- .../voidps/world/map/lumbridge/combat_hall/CombatDummy.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 089d33e89..e2ae0a1cd 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 From c0f0793f03b4c71509e2f1d381ec3b152b585c4a Mon Sep 17 00:00:00 2001 From: GregHib Date: Mon, 27 May 2024 21:32:35 +0100 Subject: [PATCH 34/48] Add more integration tests, fix ellis tanning --- data/definitions/objects.yml | 3 + .../achievement/LumbridgeBeginnerTasks.kts | 14 +- .../world/command/admin/AdminCommands.kts | 5 +- .../interact/entity/npc/shop/OpenShop.kt | 2 + .../interact/entity/npc/shop/ShopOpen.kts | 5 +- .../voidps/world/map/al_kharid/Ellis.kts | 2 +- .../achievement/LumbridgeBeginnerTasksTest.kt | 287 +++++++++++++++++- .../gregs/voidps/world/script/WorldTest.kt | 6 + 8 files changed, 311 insertions(+), 13 deletions(-) diff --git a/data/definitions/objects.yml b/data/definitions/objects.yml index 0e3275c0b..c6f7b3665 100644 --- a/data/definitions/objects.yml +++ b/data/definitions/objects.yml @@ -11845,3 +11845,6 @@ lumbridge_organ: lumbridge_church_bell: id: 36976 examine: "I can ring this." +fire_barbarian_village: + id: 5499 + examine: "Hot!" 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 index 7af9dec36..de48bccd3 100644 --- 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 @@ -5,7 +5,6 @@ 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.previousTile 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 @@ -19,6 +18,7 @@ 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 @@ -50,7 +50,7 @@ itemAdded("logs", inventory = "inventory") { player -> } } -itemAdded("crayfish", inventory = "inventory") { player -> +itemAdded("raw_crayfish", inventory = "inventory") { player -> if (player.softTimers.contains("fishing")) { player["arent_they_supposed_to_be_twins_task"] = true } @@ -59,15 +59,17 @@ itemAdded("crayfish", inventory = "inventory") { player -> val objects: GameObjects by inject() itemRemoved("logs", inventory = "inventory") { player -> - if (player.softTimers.contains("firemaking") && !player["log_a_rhythm_task", false]) { + 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(player.previousTile, ObjectShape.CENTRE_PIECE_STRAIGHT) + val fire = objects.getShape(tile, ObjectShape.CENTRE_PIECE_STRAIGHT) if (fire != null && fire.id.startsWith("fire_")) { player["log_a_rhythm_task"] = true } @@ -94,7 +96,7 @@ itemAdded("bronze_bar", inventory = "inventory") { player -> itemAdded("bronze_dagger", inventory = "inventory") { player -> if (player.softTimers.contains("smithing")) { - player["cutting_edge_technology"] = true + player["cutting_edge_technology_task"] = true } } @@ -197,7 +199,7 @@ itemReplaced(to = "bread", inventory = "inventory") { player -> 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 else player.levels.getMax(it) } + 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) { 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 3be85f95c..b2cc28b72 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") { 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 08d30e8c2..74adba932 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 @@ -8,6 +8,8 @@ import world.gregs.voidps.engine.event.Events data class OpenShop(val id: String): Event { override val size = 2 + override val notification: Boolean = true + override fun parameter(dispatcher: EventDispatcher, index: Int) = when(index) { 0 -> "open_shop" 1 -> id 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 ae6c6eac1..4359cfabb 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/map/al_kharid/Ellis.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ellis.kts index 5d4a4c252..0e319fb79 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 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 index 5683de753..73a9993b3 100644 --- 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 @@ -3,15 +3,21 @@ 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.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.WorldTest -import world.gregs.voidps.world.script.objectOption +import world.gregs.voidps.world.script.* import kotlin.test.assertTrue internal class LumbridgeBeginnerTasksTest : WorldTest() { @@ -87,4 +93,281 @@ internal class LumbridgeBeginnerTasksTest : WorldTest() { assertTrue(player["adventurers_log_task", false]) } + + @Test + fun `Aren't they supposed to be twins`() { + val player = createPlayer("adventurer", Tile(3258, 3205)) + player.levels.set(Skill.Fishing, 20) + 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.levels.set(Skill.Cooking, 100) + player.inventory.add("raw_crayfish") + val fire = createObject("fire_orange", Tile(3079, 3445)) + + 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)) + player.levels.set(Skill.Smithing, 100) + val furnace = objects[Tile(3229, 3254), "anvil_lumbridge"]!! + player.inventory.add("bronze_bar", "hammer") + + player.itemOnObject(furnace, 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]) + } + + @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]) + } + + @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]) + } } \ No newline at end of file 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 0b5c8e8e1..9675bde57 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 @@ -133,6 +136,7 @@ abstract class WorldTest : KoinTest { @BeforeAll fun beforeAll() { + Main.name = "test" stopKoin() startKoin { printLogger(Level.ERROR) @@ -209,6 +213,8 @@ abstract class WorldTest : KoinTest { @BeforeEach fun beforeEach() { loadItemSpawns(floorItems, get()) + loadNpcSpawns(npcs) + loadObjectSpawns(objects) setRandom(FakeRandom()) } From 1c2cc1d489e2a7ecee64739d5895d4889bc9af6d Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 15:21:51 +0100 Subject: [PATCH 35/48] Add shop buy and sell events --- .../interact/entity/npc/shop/BoughtItem.kt | 23 +++++++++++++++++++ .../interact/entity/npc/shop/ShopBuy.kts | 6 ++++- .../interact/entity/npc/shop/ShopSell.kts | 7 +++--- .../interact/entity/npc/shop/SoldItem.kt | 23 +++++++++++++++++++ 4 files changed, 54 insertions(+), 5 deletions(-) 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 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 000000000..0cbdfa75a --- /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/ShopBuy.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopBuy.kts index cfc6fbb0a..97eb3253b 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/ShopSell.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/ShopSell.kts index 705a891da..b59b97413 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,8 +73,6 @@ fun sell(player: Player, item: Item, amount: Int) { } } TransactionError.Invalid -> player.message("You can't sell this item to this shop.") - else -> { - player["greasing_the_wheels_of_commerce_task"] = true - } + 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 000000000..ac098c955 --- /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 From 8c718bd9da36e42bc11048a01524b4e46857842e Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 16:58:30 +0100 Subject: [PATCH 36/48] Add tests for remaining tasks --- data/definitions/objects.yml | 3 + data/map/teleports.yml | 4 +- .../achievement/LumbridgeBeginnerTasks.kts | 31 +- .../world/activity/skill/cooking/Cooking.kts | 1 + .../world/map/wizards_tower/Sedridor.kts | 2 + .../achievement/LumbridgeBeginnerTasksTest.kt | 443 +++++++++++++++++- 6 files changed, 466 insertions(+), 18 deletions(-) diff --git a/data/definitions/objects.yml b/data/definitions/objects.yml index c6f7b3665..5889911a5 100644 --- a/data/definitions/objects.yml +++ b/data/definitions/objects.yml @@ -11848,3 +11848,6 @@ lumbridge_church_bell: 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/map/teleports.yml b/data/map/teleports.yml index 4bd47264e..0c1ad7b2f 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 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 index de48bccd3..6ae3774c8 100644 --- 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 @@ -23,6 +23,7 @@ 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 @@ -107,13 +108,15 @@ itemChange("worn_equipment") { player -> 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["steel_yourself_for_combat_task"] = true + player["temper_temper_task"] = true } val id = item.def["weapon_style", -1] when (val style = styleDefinitions.get(id).stringId) { @@ -146,7 +149,7 @@ itemChange("worn_equipment") { player -> } } } - EquipSlot.Ammo.index -> if (item.id == "steel_arrow") { + EquipSlot.Ammo.index -> if (item.id == "iron_arrow") { player["ammo_ammo_ammo_task"] = true } } @@ -158,8 +161,10 @@ itemChange("worn_equipment", EquipSlot.Weapon.index) { player -> } } -variableSet("task_progress_overall", from = 9, to = 10) { player -> - player["on_your_way_task"] = true +variableSet("task_progress_overall") { player -> + if (from is Int && to is Int && (from as Int) < 10 && (to as Int) >= 10) { + player["on_your_way_task"] = true + } } itemAdded(inventory = "bank") { player -> @@ -226,6 +231,10 @@ itemAdded("air_rune", inventory = "inventory") { player -> } } +itemSold { player -> + player["greasing_the_wheels_of_commerce_task"] = true +} + prayerStart { player -> player["put_your_hands_together_for_task"] = true } @@ -247,8 +256,8 @@ npcDeath("giant_rat*") { npc -> } } -maxLevelChange(Skill.Attack, Skill.Defence, to = 5) { player -> - if (player.levels.getMax(Skill.Attack) == 5 && player.levels.getMax(Skill.Defence) == 5) { +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 } } @@ -281,8 +290,10 @@ itemAdded("empty_pot", inventory = "inventory") { player -> } } -maxLevelChange(Skill.Mining, to = 5) { player -> - player["hack_and_smash_task"] = true +maxLevelChange(Skill.Mining) { player -> + if (from < 5 && to >= 5) { + player["hack_and_smash_task"] = true + } } itemAdded("raw_shrimps", inventory = "inventory") { player -> @@ -291,7 +302,7 @@ itemAdded("raw_shrimps", inventory = "inventory") { player -> } } -itemAdded("raw_shrimps", inventory = "lumbridge_fishing_supplies") { player -> +itemSold("raw_shrimps", "lumbridge_fishing_supplies") { player -> player["the_fruit_of_the_sea_task"] = true } @@ -323,7 +334,7 @@ combatAttack(spell = "confuse") { player -> player["not_so_confusing_after_all_task"] = true } -combatAttack(type = "ranged") { player -> +combatAttack(type = "range") { player -> if (player.ammo == "steel_arrow") { player["get_the_point_task"] = true } 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 bbb27ec98..46db4ac75 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/map/wizards_tower/Sedridor.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/wizards_tower/Sedridor.kts index 9d549d451..3bcaabd84 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/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt index 73a9993b3..a66e6039b 100644 --- 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 @@ -6,6 +6,7 @@ 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 @@ -97,7 +98,6 @@ internal class LumbridgeBeginnerTasksTest : WorldTest() { @Test fun `Aren't they supposed to be twins`() { val player = createPlayer("adventurer", Tile(3258, 3205)) - player.levels.set(Skill.Fishing, 20) val fishingSpot = createNPC("fishing_spot_crayfish_lumbridge", Tile(3259, 3205)) player.inventory.add("crayfish_cage") @@ -122,9 +122,8 @@ internal class LumbridgeBeginnerTasksTest : WorldTest() { @Test fun `Shellfish Roasting on an Open Fire`() { val player = createPlayer("adventurer", Tile(3079, 3444)) - player.levels.set(Skill.Cooking, 100) player.inventory.add("raw_crayfish") - val fire = createObject("fire_orange", Tile(3079, 3445)) + val fire = objects[Tile(3079, 3445), "fire_orange"]!! player.itemOnObject(fire, 0, "") tick(4) @@ -167,11 +166,10 @@ internal class LumbridgeBeginnerTasksTest : WorldTest() { @Test fun `Cutting Edge Technology`() { val player = createPlayer("adventurer", Tile(3228, 3254)) - player.levels.set(Skill.Smithing, 100) - val furnace = objects[Tile(3229, 3254), "anvil_lumbridge"]!! + val anvil = objects[Tile(3229, 3254), "anvil_lumbridge"]!! player.inventory.add("bronze_bar", "hammer") - player.itemOnObject(furnace, 0, "") + player.itemOnObject(anvil, 0, "") tick() player.interfaceOption("smithing", "dagger_1") tick(3) @@ -370,4 +368,437 @@ internal class LumbridgeBeginnerTasksTest : WorldTest() { 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 From e277b15f4eff25203183d22069cb81bdc11f6fec Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 17:05:20 +0100 Subject: [PATCH 37/48] Fix area's not including all levels --- .../gregs/voidps/engine/data/definition/AreaDefinitions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 48d527ddb..fedd3e6a4 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) From d5df422a90fa7adec9d68fefab11f2d25e458b7c Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 17:05:34 +0100 Subject: [PATCH 38/48] Fixes --- .../world/gregs/voidps/engine/client/variable/VariableSet.kt | 2 ++ .../world/activity/achievement/LumbridgeBeginnerTasks.kts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) 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 81e2886c6..765f568df 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/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 index 6ae3774c8..664469dfd 100644 --- 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 @@ -162,7 +162,7 @@ itemChange("worn_equipment", EquipSlot.Weapon.index) { player -> } variableSet("task_progress_overall") { player -> - if (from is Int && to is Int && (from as Int) < 10 && (to as Int) >= 10) { + if ((from == null || from is Int && (from as Int) < 10) && to is Int && (to as Int) >= 10) { player["on_your_way_task"] = true } } @@ -341,7 +341,7 @@ combatAttack(type = "range") { player -> } variableSet("quest_points") { player -> - if (from != null && to != null && (from as Int) < 4 && to as Int >= 4) { + if ((from == null || from is Int && (from as Int) < 4) && to != null && to is Int && to as Int >= 4) { player["fledgeling_adventurer_task"] = true } } From dcec40456d6a3ae24481984b934b3fad236bc746 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 17:15:33 +0100 Subject: [PATCH 39/48] Fix wizards tower top floor level --- data/map/areas.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/map/areas.yml b/data/map/areas.yml index 16742f468..0066a426a 100644 --- a/data/map/areas.yml +++ b/data/map/areas.yml @@ -631,7 +631,7 @@ wizards_tower_top_floor: area: x: [ 3094, 3125 ] y: [ 3144, 3176 ] - level: 3 + level: 2 tags: [ multi_combat ] draynor_village_multi_area: area: From 00aee9ffd5ee4ce49ddf6b1619a5826b52251151 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 19:06:50 +0100 Subject: [PATCH 40/48] Add world map functionality --- data/definitions/interfaces.yml | 6 +++ data/definitions/parameters.yml | 8 ++-- data/definitions/structs.yml | 5 ++- data/definitions/variables-client-string.yml | 7 +++- data/definitions/variables-client.yml | 32 ++++++++++---- data/definitions/variables-player-bit.yml | 29 ++++++++++++- data/definitions/variables-player.yml | 5 +++ .../client/instruction/InstructionHandlers.kt | 2 + .../handle/WorldMapClickHandler.kt | 19 +++++++++ .../entity/player/display/map/WorldMap.kts | 42 ++++++++++++++++++- .../client/instruction/WorldMapClick.kt | 5 +++ .../voidps/network/login/protocol/Decoders.kt | 2 +- .../protocol/decode/WorldMapClickDecoder.kt | 11 +++++ .../protocol/decode/WorldMapCloseDecoder.kt | 14 ------- 14 files changed, 157 insertions(+), 30 deletions(-) create mode 100644 engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WorldMapClickHandler.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/data/definitions/interfaces.yml b/data/definitions/interfaces.yml index 93be4ecc8..d6e4ab330 100644 --- a/data/definitions/interfaces.yml +++ b/data/definitions/interfaces.yml @@ -2186,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 diff --git a/data/definitions/parameters.yml b/data/definitions/parameters.yml index 1bc9f8180..beccd6e56 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 diff --git a/data/definitions/structs.yml b/data/definitions/structs.yml index 24ec2ce37..4c0dc1489 100644 --- a/data/definitions/structs.yml +++ b/data/definitions/structs.yml @@ -503,4 +503,7 @@ 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 \ No newline at end of file +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 6d46dde42..d87bb6dc4 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 cf20ec789..d52fec3e2 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 @@ -395,4 +389,28 @@ task_popup_summary: task_disable_popups: id: 1429 format: boolean - persist: true \ No newline at end of file + 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-player-bit.yml b/data/definitions/variables-player-bit.yml index c11465a54..ee2fe7464 100644 --- a/data/definitions/variables-player-bit.yml +++ b/data/definitions/variables-player-bit.yml @@ -2665,4 +2665,31 @@ honestly_its_not_a_purse_task: almost_made_in_ardougne_task: id: 6662 format: boolean - persist: true \ No newline at end of file + 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 c16ed4a6b..b88e69e75 100644 --- a/data/definitions/variables-player.yml +++ b/data/definitions/variables-player.yml @@ -609,3 +609,8 @@ task_reward_items: stat_advance_selected_skill: id: 261 format: int +world_map_marker_custom: + id: 1159 + format: int + persist: true + 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 4c20fe36c..6d8a27d42 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/WorldMapClickHandler.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/instruction/handle/WorldMapClickHandler.kt new file mode 100644 index 000000000..1c48bd2d6 --- /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/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 b78918a0c..d6d4e679d 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/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 000000000..f0bfbb525 --- /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 778ea8f5a..5124e1826 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/WorldMapClickDecoder.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/WorldMapClickDecoder.kt new file mode 100644 index 000000000..ff034cf4d --- /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 6f2a4658a..000000000 --- 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 From 76aabc3c856b4ef14c436081a0ab0ff9059547c1 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 20:38:12 +0100 Subject: [PATCH 41/48] Add task hint world map marking and fix tab pinning --- data/definitions/interfaces.yml | 4 +++ data/definitions/parameters.yml | 12 ++++---- .../engine/data/definition/EnumDefinitions.kt | 6 ++++ .../world/activity/achievement/TaskList.kts | 18 +++++++++++ .../world/activity/achievement/TaskSystem.kts | 30 ++++++++++++++----- 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/data/definitions/interfaces.yml b/data/definitions/interfaces.yml index d6e4ab330..966f1e663 100644 --- a/data/definitions/interfaces.yml +++ b/data/definitions/interfaces.yml @@ -2372,6 +2372,7 @@ task_list: hint_2: 4 hint_3: 6 hint_4: 8 + hint_5: 10 tasks: id: 94 options: @@ -2609,6 +2610,9 @@ task_system: 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/parameters.yml b/data/definitions/parameters.yml index beccd6e56..a403f08ff 100644 --- a/data/definitions/parameters.yml +++ b/data/definitions/parameters.yml @@ -370,12 +370,12 @@ task_hint_4: 1277 task_hint_5: 1278 task_hint_6: 1279 task_text_rol: 1280 -task_selectable_1: 1282 -task_selectable_2: 1283 -task_selectable_3: 1284 -task_selectable_4: 1285 -task_selectable_5: 1286 -task_selectable_6: 1287 +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 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 dedf18944..1e3cd73de 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/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 index e1206029f..98b9283ec 100644 --- 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 @@ -4,7 +4,9 @@ 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 @@ -132,4 +134,20 @@ fun refreshCompletedCount(player: Player) { } 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 086d4c356..b487224f1 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 @@ -94,18 +94,20 @@ interfaceOption("Pin/Unpin Task", "task_*", "task_system") { fun indexOfSlot(player: Player, slot: Int): Int? { var count = 1 return Tasks.forEach(areaId(player)) { - count++ - val hideCompleted = player["task_hide_completed", false] && Tasks.isCompleted(player, definition.stringId) + val hideCompleted = Tasks.isCompleted(player, definition.stringId) val hideMembers = definition["task_members", 0] == 1 && !World.members if (hideCompleted || hideMembers) { return@forEach null } - if (count - 1 == slot) { - return@forEach this.index + if (count == player["task_pin_index", -1]) { + val pinned = player["task_pinned", 4091] + if (count == slot) { + return@forEach pinned + } + skip = pinned != index } - val skipPinned = player["task_pin_index", -1] == count - if (skipPinned) { - skip = true + if (count++ == slot) { + return@forEach index } null } @@ -196,4 +198,18 @@ fun completeTask(player: Player, id: String) { } 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") } \ No newline at end of file From 2f37a1dc2f78758de9be6db3f82bd261b1b546a3 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 21:33:12 +0100 Subject: [PATCH 42/48] Show no tasks when run out --- .../world/activity/achievement/TaskSystem.kts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 b487224f1..6791fdbb5 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 @@ -2,6 +2,7 @@ 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 @@ -139,6 +140,11 @@ fun refreshSlots(player: Player) { } null } + if (slot < 7) { + for (i in slot..6) { + player["task_slot_${i}"] = 4091 + } + } player["task_progress_total"] = total player["task_progress_current"] = completed } @@ -212,4 +218,12 @@ interfaceOption("Hint", "hint_*", "task_system") { 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 From 29b67f3d8281ac1928c10fa351eec9553304dd03 Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 22:56:31 +0100 Subject: [PATCH 43/48] Fix tests --- .../world/gregs/voidps/network/login/protocol/DecoderTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9978de74a..0177fc8d4 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") { From 75d4c22fd8ee38f5d1c0a5e9cac872bfae16417a Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 23:17:49 +0100 Subject: [PATCH 44/48] Fix invalid inject code --- .../world/gregs/voidps/world/community/trade/lend/Loan.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 38e4eab8d..906ba4b52 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)) { From c0ed634d92f5604bffcdd85d886d49e6858c238d Mon Sep 17 00:00:00 2001 From: GregHib Date: Thu, 30 May 2024 23:50:28 +0100 Subject: [PATCH 45/48] Fix missing font defs --- .../gregs/voidps/world/activity/achievement/Tasks.kt | 2 +- .../entity/player/combat/magic/spell/MagicSpellTest.kt | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) 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 index d77532b99..ab89d78ad 100644 --- 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 @@ -166,7 +166,7 @@ object Tasks { } private fun Player.getInt(id: String, default: String): Int { - return get().get(id)!!.values.toInt(this.get(id, default)) + return get().get(id)!!.values.toInt(this[id, default]) } 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 5cb148b7e..254f4190a 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) } } From 1e3b0b7fd643831c10efdf9edbae2d1f73f5c6f5 Mon Sep 17 00:00:00 2001 From: GregHib Date: Fri, 31 May 2024 00:39:37 +0100 Subject: [PATCH 46/48] Fix hitpoint test --- .../interact/entity/player/effect/HitpointRestorationTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 189e9f6ea..68b903c09 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")) From 84c56740575310002ec068f2d90fc04e3810dcc2 Mon Sep 17 00:00:00 2001 From: GregHib Date: Fri, 31 May 2024 00:52:43 +0100 Subject: [PATCH 47/48] Fix npcs messing with tests --- .../achievement/LumbridgeBeginnerTasksTest.kt | 2 ++ .../gregs/voidps/world/script/WorldTest.kt | 26 ++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) 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 index a66e6039b..3bfcc7eb3 100644 --- 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 @@ -23,6 +23,8 @@ import kotlin.test.assertTrue internal class LumbridgeBeginnerTasksTest : WorldTest() { + override var loadNpcs = true + @Test fun `On the Run`() = runTest { val player = createPlayer("adventurer", emptyTile) 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 9675bde57..a6ae9268b 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 @@ -76,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++ @@ -128,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) } @@ -167,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() @@ -213,7 +225,9 @@ abstract class WorldTest : KoinTest { @BeforeEach fun beforeEach() { loadItemSpawns(floorItems, get()) - loadNpcSpawns(npcs) + if (loadNpcs) { + loadNpcSpawns(npcs) + } loadObjectSpawns(objects) setRandom(FakeRandom()) } @@ -256,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) } From 52ec82efeb643bc513f90ad37935004bf469a6cb Mon Sep 17 00:00:00 2001 From: GregHib Date: Sat, 22 Jun 2024 15:56:11 +0100 Subject: [PATCH 48/48] Add explorer jack item rewards --- data/definitions/variables-custom.yml | 4 +- data/definitions/variables-player.yml | 4 +- .../activity/achievement/ExplorerJack.kts | 28 ++- .../achievement/LumbridgeBeginnerTasks.kts | 5 +- .../world/activity/achievement/Tasks.kt | 219 ------------------ .../world/interact/entity/npc/Banker.kts | 11 +- .../achievement/LumbridgeBeginnerTasksTest.kt | 2 + 7 files changed, 47 insertions(+), 226 deletions(-) diff --git a/data/definitions/variables-custom.yml b/data/definitions/variables-custom.yml index 438a19381..ce0eb2d3d 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: @@ -473,4 +473,4 @@ equip_longbow: format: boolean equip_crossbow: persist: true - format: boolean \ No newline at end of file + format: boolean diff --git a/data/definitions/variables-player.yml b/data/definitions/variables-player.yml index b88e69e75..a0bf9b934 100644 --- a/data/definitions/variables-player.yml +++ b/data/definitions/variables-player.yml @@ -605,7 +605,9 @@ prince_ali_rescue: completed: 110 task_reward_items: id: 1959 - format: int + format: bitwise + persist: true + values: [ magic_staff, red_dye ] stat_advance_selected_skill: id: 261 format: int 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 index e82e87ebb..c539cc5ea 100644 --- 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 @@ -2,11 +2,14 @@ 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 @@ -88,18 +91,41 @@ suspend fun NPCOption.whatIsTaskSystem() { 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) - var coins = 1234 + 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 } 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 index 664469dfd..ce2c28400 100644 --- 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 @@ -168,7 +168,10 @@ variableSet("task_progress_overall") { player -> } itemAdded(inventory = "bank") { player -> - player["hang_on_to_something_task"] = true + 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 -> 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 index ab89d78ad..2bfdc4054 100644 --- 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 @@ -169,225 +169,6 @@ object Tasks { return get().get(id)!!.values.toInt(this[id, default]) } - - fun script_3223(player: Player, arg0: Int, arg1: Int): String { - var int2: Int - var str3: String? - str3 = "" - int2 = 0 - when (arg0) { - 147, 23, 294, 167, 249 -> if (arg1 == 1) { - str3 = "You must have access to the fairy ring network to complete this Task." - if (player["fairy_rings_unlocked", false]) { - int2 = 1 - } - } - 49 -> if (arg1 == 1) { - str3 = "You must unlock 500 music tracks in order to perform the Air Guitar emote." - if (player["unlocked_emote_air_guitar", false]) { - int2 = 1 - } - } - 59 -> if (arg1 == 2) { - str3 = "You must also have completed the Abyss miniquest." - if (player.questComplete("enter_the_abyss")) { - int2 = 1 - } - } - 107 -> if (arg1 == 1) { - str3 = "You must have progressed to a certain point in the Dragon Slayer quest." - if (player.getInt("dragon_slayer", "unstarted") >= 2 && player["dragon_slayer_received_shield", false] || player.questComplete("dragon_slayer")) { - int2 = 1 - } - } - 178 -> if (arg1 == 1) { - str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." - if (player["barbarian_training_fishing_unlocked", false]) { - int2 = 1 - } - } - 180 -> if (arg1 == 1) { - str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." - if (player["barbarian_training_pyre_unlocked", false]) { - int2 = 1 - } - } - 177 -> if (arg1 == 1) { - str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." - if (player["barbarian_training_pyre_unlocked", false]) { - int2 = 1 - } - } - 316 -> if (arg1 == 1) { - str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." - if (player["barbarian_training_fishing_unlocked", false]) { - int2 = 1 - } - } - 321 -> if (arg1 == 1) { - str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." - if (player["barbarian_training_pyre_unlocked", false]) { - int2 = 1 - } - } - 322 -> if (arg1 == 1) { - str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." - if (player["barbarian_training_hasta_unlocked", false]) { - int2 = 1 - } - } - 323 -> if (arg1 == 1) { - str3 = "You must begin the relevant section of Otto Godblessed's barbarian training." - if (player["barbarian_training_mix_unlocked", false]) { - int2 = 1 - } - } - 175 -> if (arg1 == 1) { - str3 = "You must complete the Bar Crawl miniquest." - if (player.questComplete("bar_crawl_miniquest") || player["bar_crawl_started", false]) { - int2 = 1 - } - } - 331, 219 -> if (arg1 == 2) { - str3 = "You must have a total combat level of at least 100 to accept an assignment in Shilo Village." - if (player.summoningCombatLevel >= 100) { - int2 = 1 - } - } - 248 -> if (arg1 == 1) { - str3 = "You must have completed the Knight Waves in Camelot." - if (player["knights_waves", 0] == 8) { - int2 = 1 - } - } - 3011, 276 -> if (arg1 == 1) { - str3 = "You require 33 Quest Points to enter the Champions' Guild." - if (player["quest_points", 0] >= 33) { - int2 = 1 - } - } - 281 -> if (arg1 == 1) { - str3 = "You must unlock all four emotes by completing levels of the Stronghold of Security." - if (player["unlocked_emote_flap", false] && player["unlocked_emote_slap_head", false] && player["unlocked_emote_idea", false] && player["unlocked_emote_stomp", false]) { - int2 = 1 - } - } - 285 -> if (arg1 == 1) { - str3 = "You must learn the secret of the Senntisten necklace." - if (player["teleport_to_digsite_with_pendant", false]) { - int2 = 1 - } - } - 289 -> if (arg1 == 1) { - str3 = "You must have a total combat level of at least 40 to accept an assignment from Vannaka." - if (player.summoningCombatLevel >= 40) { - int2 = 1 - } - } - 300 -> if (arg1 == 1) { - str3 = "Completing quests will increase your access to Kudos with the Varrock Museum." - if (kudosCount(player) >= 153) { - int2 = 1 - } - } - 3000 -> if (arg1 == 2) { - if (minutes() >= player["varp_451", 0]) { - int2 = 1 - } - str3 = "You may gather the Tears of Guthix once every week." - } else if (arg1 == 3) { - if (player["quest_points", 0] >= player["varbit_456", 0] || player["total_experience", 0.0] >= player["varp_450", 0.0]) { - int2 = 1 - } - str3 = "You must have gained a Quest Point or 100,000 total experience to enter Juna's cavern." - } - 3013, 3001 -> if (arg1 == 1) { - str3 = "You must have a total combat level of at least 40 to fight for the Void Knights." - if (player.combatLevel >= 40) { - int2 = 1 - } - } - 3002 -> if (arg1 == 1) { - str3 = "You must have Larry or Chuck explain the purpose of penguin spying." - if (player["penguin_hide_and_seek_explained", false]) { - int2 = 1 - } - } else if (arg1 == 2) { - str3 = "You must have spied on fewer than ten penguins already this week." - if (player["penguins_found_weekly", 0] < 10) { - int2 = 1 - } - } else if (arg1 == 3) { - str3 = "You may spy on penguins if your total Penguin Points are less than the maximum of fifty." - if (player["penguin_points", 0] < 50) { - int2 = 1 - } - } - 12 -> if (arg1 == 1) { - str3 = "You must have Larry or Chuck explain the purpose of Penguin Hide and Seek." - if (player["penguin_hide_and_seek_explained", false]) { - int2 = 1 - } - } - 3003 -> if (arg1 == 1) { - str3 = "You may not chop down more than two evil trees per day." - if (player["nurture_evil_tree_stage", 0] < 2) { - int2 = 1 - } - } - 3007 -> if (arg1 == 1) { - str3 = "You may attempt the Agility, Magic and Ranged performances after a week has passed since your last show." - if (!player["circus_magic", false] || !player["circus_agility", false] || !player["circus_ranged", false]) { - int2 = 1 - } - } - 3008 -> if (arg1 == 2) { - str3 = "You must wait at least a day since you last faced Bork." - if (player["bork_defeated_day", 0] != days()) { - int2 = 1 - } - } - 3010 -> if (arg1 == 2) { - str3 = "At least a week must pass since you last faced the Skeletal Horror." - if (minutes() < player["varbit_6305", 0]) { - int2 = 1 - } - } - 3012 -> if (arg1 == 1) { - str3 = "You require 50 Runecrafting to enter the Runecrafters' Guild." - if (player.hasMax(Skill.Runecrafting, 50)) { - int2 = 1 - } - } - 3015 -> if (arg1 == 2) { - str3 = "You must have at least 65 Attack or Defence in order to take on a case." - if (player.hasMax(Skill.Attack, 65) || player.hasMax(Skill.Defence, 65)) { - int2 = 1 - } - } - 3031 -> if (arg1 == 1) { - str3 = "You must have a total combat level of at least 48 to fight in the Clan Wars." - if (player.summoningCombatLevel >= 48) { - int2 = 1 - } - } - 3034 -> if (arg1 == 1) { - str3 = "To enter the Warriors' Guild your Attack or Strength level must be 99, or your combined Attack and Strength levels must total 130 or more." - if (player.levels.getMax(Skill.Strength) + player.levels.getMax(Skill.Attack) >= 130 || player.hasMax(Skill.Attack, 99) || player.hasMax(Skill.Strength, 99)) { - int2 = 1 - } - } - else -> { - str3 = "" - int2 = 0 - } - } - if (int2 == 1) { - str3 = "$str3" - } - return str3 - } - private fun minutes() = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis()) private fun days(): Int { 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 6e7f3bf55..1387955e7 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 @@ -50,11 +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.") - player["you_can_bank_on_us_task"] = true + 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.") - player["you_can_bank_on_us_task"] = true + achievement() } } } @@ -71,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/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt b/game/src/test/kotlin/world/gregs/voidps/world/activity/achievement/LumbridgeBeginnerTasksTest.kt index 3bfcc7eb3..61cbe7dd2 100644 --- 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 @@ -222,6 +222,7 @@ internal class LumbridgeBeginnerTasksTest : WorldTest() { player.dialogueContinue() assertTrue(player["you_can_bank_on_us_task", false]) + assertTrue(player.containsVarbit("task_reward_items", "red_dye")) } @Test @@ -235,6 +236,7 @@ internal class LumbridgeBeginnerTasksTest : WorldTest() { 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