diff --git a/README.md b/README.md index 7d3d31640..6d80675ca 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ ## Quick setup -1. Make sure you have java 19 or above installed. (`java --version` on command line) +1. Make sure you have [java 19 or above installed](https://adoptium.net/temurin/releases/?package=jre). (`java --version` on command line) 2. Extract the [latest void.zip released bundle](https://github.com/GregHib/void/releases) into a directory. 3. Extract the [latest pre-modified game files cache.zip](https://mega.nz/folder/ZMN2AQaZ#4rJgfzbVW0_mWsr1oPLh1A) into `/void/data/cache/`. 4. Run either the `run-server.bat` on Windows, or `run-server.sh` on Linux. diff --git a/data/definitions/animations.yml b/data/definitions/animations.yml index 799f6e603..1201b85a9 100644 --- a/data/definitions/animations.yml +++ b/data/definitions/animations.yml @@ -384,6 +384,11 @@ emote_flap: ticks: 3 walk: false run: false +emote_enhanced_flap: + id: 3859 + ticks: 3 + walk: false + run: false emote_slap_head: id: 4275 ticks: 3 @@ -685,7 +690,7 @@ emote_recite_prayer: walk: false run: false emote_chicken_dance: - id: 6400 + id: 1835 ticks: 8 walk: false run: false @@ -734,6 +739,101 @@ emote_trample_snow: ticks: 8 walk: false run: false +emote_candy_cane_spin: + id: 12664 + ticks: 2 + walk: false + run: false +emote_salty_claws_hat_dance: + id: 329 + ticks: 2 + walk: false + run: false +emote_golden_hammer_spin: + id: 15149 + ticks: 7 + walk: false + run: false +emote_golden_hammer_brandish: + id: 15150 + ticks: 4 + walk: false + run: false +emote_10th_anniversary_cake: + id: 6292 + ticks: 8 + walk: false + run: false +emote_marionette_jump: + id: 3003 + ticks: 8 + walk: false + run: false +emote_marionette_walk: + id: 3004 + ticks: 10 + walk: false + run: false +emote_marionette_bow: + id: 3005 + ticks: 4 + walk: false + run: false +emote_marionette_dance: + id: 3006 + ticks: 10 + walk: false + run: false +emote_magnifying_glass_sleuth: + id: 2936 + ticks: 8 + walk: false + run: false +emote_chocatrice_cape: + id: 8903 + ticks: 6 + walk: false + run: false +emote_squirrel_ears: + id: 12265 + ticks: 6 + walk: false + run: false +emote_toy_horsey_brown: + id: 918 + ticks: 4 + walk: false + run: false +emote_toy_horsey_white: + id: 919 + ticks: 4 + walk: false + run: false +emote_toy_horsey_black: + id: 920 + ticks: 4 + walk: false + run: false +emote_toy_horsey_grey: + id: 921 + ticks: 4 + walk: false + run: false +rubber_chicken_whack: + id: 1833 + ticks: 2 + walk: false + run: false +easter_carrot_whack: + id: 11547 + ticks: 2 + walk: false + run: false +play_with_eek: + id: 12490 + ticks: 6 + walk: false + run: false rest_legs_out: id: 2716 ticks: 4 diff --git a/data/definitions/diango-codes.yml b/data/definitions/diango-codes.yml new file mode 100644 index 000000000..ff1864449 --- /dev/null +++ b/data/definitions/diango-codes.yml @@ -0,0 +1,3 @@ +flagstaff: + variable: flagstaff_runefest + add: [ flagstaff_of_festivities ] \ No newline at end of file diff --git a/data/definitions/graphics.yml b/data/definitions/graphics.yml index ffd541a39..8ebbb980c 100644 --- a/data/definitions/graphics.yml +++ b/data/definitions/graphics.yml @@ -1,3 +1,4 @@ +play_with_eek: 2178 traiborn_bone_spell: 777 demon_slayer_spell: id: 782 @@ -178,7 +179,23 @@ emote_dung_master_gravecreeper: 2778 emote_dung_master_flesh_spoiler: 2779 emote_dung_master_cursebearer: 2780 emote_reindeer: 859 +emote_reindeer_2: 263 emote_snow_globe_flurry: 1284 +emote_golden_hammer_spin: 2953 +emote_red_marionette_jump: 507 +emote_red_marionette_walk: 508 +emote_red_marionette_bow: 509 +emote_red_marionette_dance: 510 +emote_blue_marionette_jump: 511 +emote_blue_marionette_walk: 512 +emote_blue_marionette_bow: 513 +emote_blue_marionette_dance: 514 +emote_green_marionette_jump: 515 +emote_green_marionette_walk: 516 +emote_green_marionette_bow: 517 +emote_green_marionette_dance: 518 +emote_chocatrice_cape: 1566 +emote_squirrel_ears: 2145 level_up: 199 home_tele_1: 775 home_tele_2: 800 diff --git a/data/definitions/interfaces.yml b/data/definitions/interfaces.yml index 966f1e663..6a043a01a 100644 --- a/data/definitions/interfaces.yml +++ b/data/definitions/interfaces.yml @@ -1306,6 +1306,11 @@ trade_side: dialogue_tutorial_text: id: 372 type: dialogue_box +morph: + id: 375 + type: overlay_tab + components: + unmorph: 3 slayer_rewards_learn: 378 wilderness_skull: id: 381 @@ -1704,6 +1709,16 @@ emotes: puppet_master: 50 taskmaster: 51 seal_of_approval: 52 +diangos_item_retrieval: + id: 468 + type: main_screen + components: + items: + id: 2 + inventory: diangos_item_retrieval + options: + Claim: 0 + Examine: 9 barbarian_assult_rewards: 473 barbarian_assult_horn: 484 barbarian_assult_attacker: 485 diff --git a/data/definitions/inventories.yml b/data/definitions/inventories.yml index 95c3319bd..3e5826eba 100644 --- a/data/definitions/inventories.yml +++ b/data/definitions/inventories.yml @@ -29,6 +29,7 @@ horviks_armour_shop: - mithril_platebody: 10 al_kharid_general_store: id: 3 + shop: true defaults: - empty_pot: 30 - jug: 10 @@ -41,8 +42,9 @@ al_kharid_general_store: - hammer: 10 - newcomer_map: 10 - security_book: 10 -inventory_4: +edgeville_general_store: id: 4 + shop: true defaults: - empty_pot: 30 - jug: 10 @@ -164,6 +166,7 @@ zekes_superior_scimitars: - mithril_scimitar: 10 louies_armoured_legs_bazaar: id: 12 + shop: true defaults: - bronze_platelegs: 10 - iron_platelegs: 10 @@ -171,8 +174,9 @@ louies_armoured_legs_bazaar: - black_platelegs: 10 - mithril_platelegs: 10 - adamant_platelegs: 10 -karamja_general_store: +varrock_general_store: id: 13 + shop: true defaults: - empty_pot: 30 - jug: 10 @@ -210,6 +214,7 @@ cassies_shield_shop: - mithril_sq_shield: 10 ranaels_super_skirt_store: id: 16 + shop: true defaults: - bronze_plateskirt: 10 - iron_plateskirt: 10 @@ -380,6 +385,7 @@ gerrants_fishy_business: - raw_swordfish: 0 rimmington_general_store: id: 31 + shop: true defaults: - empty_pot: 30 - jug: 10 @@ -420,6 +426,7 @@ scavvos_rune_store: - studded_leather_coif: 10 falador_general_store: id: 34 + shop: true defaults: - empty_pot: 30 - jug: 10 @@ -1361,8 +1368,9 @@ inventory_135: id: 135 defaults: - rotten_tomato: 100 -inventory_137: +diangos_toy_store: id: 137 + shop: true defaults: - toy_horsey_brown: 10 - toy_horsey_white: 10 @@ -1470,8 +1478,9 @@ canifis_general_store: - hammer: 10 - sample_bottle: 10 - knife: 10 -inventory_146: +dommiks_crafting_store: id: 146 + shop: true defaults: - chisel: 10 - ring_mould: 10 @@ -3459,8 +3468,9 @@ void_knight_general_store: - hammer: 10 - bronze_hatchet: 10 - field_ration: 50 -inventory_391: +karamja_general_store: id: 391 + shop: true defaults: - empty_pot: 30 - jug: 10 @@ -4457,40 +4467,69 @@ inventory_452: - hunter_cape_2: 1 - quest_point_cape_2: 1 - more: 1 -inventory_453: +diangos_item_retrieval: id: 453 - defaults: - - reindeer_hat_2: 1 - - jack_lantern_mask_2: 1 - - skeleton_boots_2: 1 - - skeleton_gloves_2: 1 - - skeleton_leggings_2: 1 - - skeleton_shirt_2: 1 - - skeleton_mask_2: 1 - - easter_ring_2: 1 - - bobble_hat_2: 1 - - bobble_scarf_2: 1 - - blue_marionette_2: 1 - - zombie_head_2: 1 - - rubber_chicken_2: 1 - - yo_yo_2: 1 - - bunny_ears_2: 1 - - scythe_2: 1 - - chicken_head_2: 1 - - chicken_feet_2: 1 - - chicken_wings_2: 1 - - chicken_legs_2: 1 - - grim_reaper_hood_2: 1 - - snow_globe_2: 1 - - chocatrice_cape_2: 1 - - witch_top_2: 1 - - witch_skirt_2: 1 - - witch_cloak_2: 1 - - cornucopia_2: 1 - - santa_costume_top_3: 1 - - ice_amulet_2: 1 - - easter_carrot_2: 1 - - more: 1 + length: 58 + defaults: + - bunny_ears: 1 + - scythe: 1 + - yo_yo: 1 + - rubber_chicken: 1 + - zombie_head: 1 + - easter_ring: 1 + - bobble_hat: 1 + - bobble_scarf: 1 + - jester_hat: 1 + - jester_scarf: 1 + - tri_jester_hat: 1 + - tri_jester_scarf: 1 + - woolly_hat: 1 + - woolly_scarf: 1 + - reindeer_hat: 1 + - blue_marionette: 1 + - jack_lantern_mask: 1 + - skeleton_boots: 1 + - skeleton_gloves: 1 + - skeleton_leggings: 1 + - skeleton_shirt: 1 + - skeleton_mask: 1 + - wintumber_tree: 1 + - chicken_feet: 1 + - chicken_legs: 1 + - chicken_wings: 1 + - chicken_head: 1 + - grim_reaper_hood: 1 + - snow_globe: 1 + - chocatrice_cape: 1 + - witch_top: 1 + - witch_skirt: 1 + - witch_cloak: 1 + - santa_costume_top: 1 + - santa_costume_legs: 1 + - santa_costume_gloves: 1 + - santa_costume_boots: 1 + - ice_amulet: 1 + - cornucopia: 1 + - easter_carrot: 1 + - eek: 1 + - web_cloak: 1 + - candy_cane: 1 + - christmas_ghost_hood: 1 + - christmas_ghost_top: 1 + - christmas_ghost_bottoms: 1 + - squirrel_ears: 1 + - bone_brooch: 1 + - flagstaff_of_festivities: 1 + - magnifying_glass: 1 + - investigators_hat: 1 + - investigators_trousers: 1 + - investigators_coat: 1 + - mysterious_book: 1 + - salty_claws_hat: 1 + - heimland_games_souvenir: 1 + - golden_cracker: 1 + - tenth_anniversary_cake: 1 + - hati_head: 1 inventory_454: id: 454 defaults: diff --git a/data/definitions/items.yml b/data/definitions/items.yml index f886594a1..e265fda9c 100644 --- a/data/definitions/items.yml +++ b/data/definitions/items.yml @@ -79510,6 +79510,7 @@ flagstaff_of_festivities: id: 18667 tradeable: false weight: 1.0 + event: flagstaff_runefest slot: "Weapon" destroy: "You can replace this by speaking to Diango in Draynor." examine: "A flagstaff celebrating Runefest '10." diff --git a/data/definitions/npcs.yml b/data/definitions/npcs.yml index 84bcc9f53..888df2e40 100644 --- a/data/definitions/npcs.yml +++ b/data/definitions/npcs.yml @@ -425,17 +425,116 @@ bob: shopkeeper_lumbridge: id: 520 race: human + shop: lumbridge_general_store + wander_radius: 2 examine: "Sells stuff." shop_assistant_lumbridge: id: 521 race: human + shop: lumbridge_general_store + wander_radius: 2 examine: "Helps sell stuff." +shopkeeper_varrock: + id: 522 + race: human + shop: varrock_general_store + wander_radius: 2 + examine: "Likes people spending money." +shop_assistant_varrock: + id: 523 + race: human + shop: varrock_general_store + wander_radius: 2 + examine: "Likes helping sell stuff." +shopkeeper_al_kharid: + id: 524 + race: human + shop: al_kharid_general_store + wander_radius: 2 + examine: "A product of a consumerist society." +shop_assistant_al_kharid: + id: 525 + race: human + shop: al_kharid_general_store + wander_radius: 2 + examine: "Likes you more, the more you spend." +shopkeeper_falador: + id: 526 + race: human + shop: falador_general_store + wander_radius: 2 + examine: "A product of a consumerist society." +shop_assistant_falador: + id: 527 + race: human + shop: falador_general_store + wander_radius: 2 + examine: "Likes you more, the more you spend." +shopkeeper_edgeville: + id: 528 + race: human + shop: edgeville_general_store + wander_radius: 2 + examine: "If he doesn't have it, he can't sell it." +shop_assistant_edgeville: + id: 529 + race: human + shop: edgeville_general_store + wander_radius: 2 + examine: "She's here on work experience." +shopkeeper_rimmington: + id: 530 + race: human + shop: rimmington_general_store + wander_radius: 2 + examine: "Has an interesting assortment of items for sale." +shop_assistant_rimmington: + id: 531 + race: human + shop: rimmington_general_store + wander_radius: 2 + examine: "Works on commission." +shopkeeper_musa_point: + id: 11674 + race: human + shop: karamja_general_store + wander_radius: 2 + examine: "Clearly takes pride in his appearance." +shop_assistant_musa_point: + id: 11678 + race: human + shop: karamja_general_store + wander_radius: 2 + examine: "Needs a haircut." zeke: id: 541 race: human shop: zekes_superior_scimitars wander_radius: 3 examine: "Sells superior scimitars." +louie_legs: + id: 542 + wander_radius: 4 + shop: louies_armoured_legs_bazaar + race: human + examine: "For the finest in armoured legware." +karim: + id: 543 + wander_radius: 4 + race: human + examine: "Kebabs are full of meaty goodness." +ranael: + id: 544 + wander_radius: 4 + shop: ranaels_super_skirt_store + race: human + examine: "She's an expert on armoured skirts!" +dommik: + id: 545 + wander_radius: 4 + shop: dommiks_crafting_store + race: human + examine: "If Crafting's your thing, he's your man." baraek: id: 547 race: human @@ -667,6 +766,12 @@ jeed: race: human wander_radius: 3 examine: "A citizen of Al Kharid." +diango: + id: 970 + wander_radius: 4 + shop: diangos_toy_store + race: human + examine: "A toy-seller who looks after people's toys for them." hamid: id: 1008 race: human @@ -2174,4 +2279,18 @@ explorer_jack: id: 13295 wander_radius: 5 race: human - examine: "He looks like a professional explorer." \ No newline at end of file + examine: "He looks like a professional explorer." +ring_of_stone: + id: 2626 +easter_egg_0: + id: 3689 +easter_egg_1: + id: 3690 +easter_egg_2: + id: 3691 +easter_egg_3: + id: 3692 +easter_egg_4: + id: 3693 +easter_egg_5: + id: 3694 \ No newline at end of file diff --git a/data/definitions/objects.yml b/data/definitions/objects.yml index 5889911a5..6268fe6b1 100644 --- a/data/definitions/objects.yml +++ b/data/definitions/objects.yml @@ -1845,6 +1845,12 @@ fire_orange: examine: "Hot!" city_gate_opened: id: 20091 +anvil_dorics: + id: 2782 + examine: "It says 'Property of Doric the dwarf' on the side." +anvil: + id: 2783 + examine: "Used for fashioning metal items." city_gate_closed: id: 2786 examine: "An entrance to Gu'Tanoth." @@ -2886,6 +2892,9 @@ door_163_opened: door_163_closed: id: 6114 examine: "The door is closed." +anvil_keldagrim: + id: 6150 + examine: "Useful for making weapons." crate_59: id: 6177 examine: "Big mysterious crates. You wonder what could be inside." @@ -5664,23 +5673,26 @@ depleted_rocks_ingneous_3: crate_152: id: 17033 examine: "Big crate. Probably has crossbow bits inside." -large_door_51_opened: - id: 17090 - examine: "A sturdy wooden door." +anvil_blast_Furnace: + id: 17073 + examine: "Used for fashioning metal items." large_door_51_closed: id: 17089 examine: "A sturdy wooden door." -large_door_53_opened: - id: 17092 - examine: "A large double door." +large_door_51_opened: + id: 17090 + examine: "A sturdy wooden door." large_door_53_closed: id: 17091 examine: "A large double door." -large_door_55_opened: - id: 17094 +large_door_53_opened: + id: 17092 examine: "A large double door." large_door_55_closed: id: 17093 + examine: "A large double door." +large_door_55_opened: + id: 17094 examine: "A large double door." crate_153: id: 17100 diff --git a/data/definitions/scripts.yml b/data/definitions/scripts.yml index 7d9ef3771..ae792c016 100644 --- a/data/definitions/scripts.yml +++ b/data/definitions/scripts.yml @@ -15,6 +15,7 @@ update_bank_slots: 1465 quest_journal_refresh: 2165 quest_journal_length: 1207 trade_warning: 143 +close_entry: 101 int_entry: 108 string_entry: 109 dialogue_item_zoom: 3449 @@ -28,3 +29,49 @@ task_main_list_filter_set: 3986 task_summary_accordion: 4000 task_summary_close: 4001 task_list_button_hide: 4101 +set_scroll_height: + id: 1208 + params: + - "scroll bar component" + - "interface container" + - "container height" + - "append" +interface_inv_init: + id: 149 + params: + - "interface container" + - "interface id" + - "width" + - "height" + - "drag mode" + - "drag start interface id" + - "option 1" + - "option 2" + - "option 3" + - "option 4" + - "option 5" +interface_inv_update: + id: 152 + params: + - "interface container" + - "interface id" + - "width" + - "height" + - "drag mode" + - "drag start interface id" + - "option 1" + - "option 2" + - "option 3" + - "option 4" + - "option 5" +scrollbar_resize: + id: 72 + params: + - "scroll bar interface id" + - "container interface id" + - "scroll bar height" +scrollbar_vertical: + id: 30 + params: + - "scroll bar interface id" + - "container interface id" \ No newline at end of file diff --git a/data/definitions/sounds.yml b/data/definitions/sounds.yml index b6e224bf6..97c502909 100644 --- a/data/definitions/sounds.yml +++ b/data/definitions/sounds.yml @@ -72,6 +72,7 @@ activate_smite: 2686 activate_augury: 2670 activate_piety: 3825 deactivate_prayer: 2663 +rubber_chicken_whack: 2257 equip_halloween_pumpkin: 3227 equip_halloween_spray: 3228 equip_salamander: 732 diff --git a/data/definitions/variables-custom.yml b/data/definitions/variables-custom.yml index ce0eb2d3d..77a67f4a8 100644 --- a/data/definitions/variables-custom.yml +++ b/data/definitions/variables-custom.yml @@ -474,3 +474,6 @@ equip_longbow: equip_crossbow: persist: true format: boolean +flagstaff_runefest: + persist: true + format: boolean \ No newline at end of file diff --git a/data/spawns/npc-spawns.yml b/data/spawns/npc-spawns.yml index f0032402a..eae96520e 100644 --- a/data/spawns/npc-spawns.yml +++ b/data/spawns/npc-spawns.yml @@ -1267,6 +1267,9 @@ # 11423 - { id: banker_keldagrim, x: 2836, y: 10205, direction: NORTH, members: true } - { id: banker_keldagrim_2, x: 2838, y: 10205, direction: NORTH, members: true } +# 11569 +- { id: shopkeeper_musa_point, x: 2902, y: 3146 } +- { id: shop_assistant_musa_point, x: 2902, y: 3150 } # 11570 - { id: rat, x: 2923, y: 3251 } - { id: rat, x: 2939, y: 3242 } @@ -1323,6 +1326,8 @@ - { id: a_pile_of_broken_glass, x: 2981, y: 3190 } - { id: thurgo, x: 3001, y: 3144 } # 11826 +- { id: shopkeeper_rimmington, x: 2947, y: 3217 } +- { id: shop_assistant_rimmington, x: 2948, y: 3217 } - { id: butterfly_1, x: 2954, y: 3227 } - { id: butterfly_1, x: 2958, y: 3213 } - { id: goblin_light_grey_bald, x: 2997, y: 3216 } @@ -1334,6 +1339,8 @@ - { id: goblin_light_brown_mohawk, x: 3002, y: 3210 } - { id: goblin_light_topless_spiked, x: 3002, y: 3206 } # 11828 +- { id: shopkeeper_falador, x: 2957, y: 3386 } +- { id: shop_assistant_falador, x: 2955, y: 3389 } - { id: squire_asrol, x: 2975, y: 3343 } - { id: hairdresser, x: 2946, y: 3379 } - { id: banker_falador, x: 2945, y: 3366, direction: NORTH } @@ -1567,6 +1574,7 @@ # 12337 - { id: traiborn, x: 3112, y: 3162, level: 1 } # 12338 +- { id: diango, x: 3081, y: 3247 } - { id: musician_draynor_village, x: 3110, y: 3253, direction: SOUTH } - { id: banker_3, x: 3088, y: 3242 } - { id: banker_3, x: 3090, y: 3245, direction: EAST } @@ -1610,6 +1618,8 @@ - { id: haakon_the_champion, x: 3081, y: 3444 } - { id: kjell, x: 3079, y: 3414, direction: NORTH_EAST } # 12342 +- { id: shopkeeper_edgeville, x: 3080, y: 3511 } +- { id: shop_assistant_edgeville, x: 3081, y: 3511 } - { id: man, x: 3093, y: 3512 } - { id: man, x: 3097, y: 3512 } - { id: man, x: 3100, y: 3509 } @@ -2126,6 +2136,8 @@ - { id: tarquin, x: 3203, y: 3344 } - { id: mage_of_zamorak_varrock, x: 3259, y: 3386, members: true } # 12853 +- { id: shopkeeper_varrock, x: 3218, y: 3415 } +- { id: shop_assistant_varrock, x: 3217, y: 3411 } - { id: ash_cleaner, x: 3250, y: 3429 } - { id: iffie, x: 3204, y: 3419 } - { id: aubury, x: 3253, y: 3402 } @@ -2212,6 +2224,12 @@ # 13104 - { id: musician_shantay_pass, x: 3309, y: 3126, direction: WEST } # 13105 +- { id: karim, x: 3272, y: 3182 } +- { id: dommik, x: 3321, y: 3194 } +- { id: louie_legs, x: 3316, y: 3175 } +- { id: ranael, x: 3316, y: 3164 } +- { id: shopkeeper_al_kharid, x: 3316, y: 3184 } +- { id: shop_assistant_al_kharid, x: 3316, y: 3182 } - { id: zeke, x: 3288, y: 3190 } - { id: banker_al_kharid, x: 3267, y: 3169, direction: EAST } - { id: banker_al_kharid, x: 3267, y: 3167, direction: EAST } 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 c19e69384..1eadb7cda 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/EngineModules.kt @@ -101,6 +101,7 @@ val engineModule = module { single(createdAtStart = true) { PrayerDefinitions().load() } single(createdAtStart = true) { GearDefinitions().load() } single(createdAtStart = true) { ItemOnItemDefinitions().load() } + single(createdAtStart = true) { DiangoCodeDefinitions().load() } single(createdAtStart = true) { AccountDefinitions().load() } single(createdAtStart = true) { HuntModeDefinitions().load() } single(createdAtStart = true) { CategoryDefinitions().load() } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/InterfaceOptions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/InterfaceOptions.kt index a742ed584..08a2f33a4 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/InterfaceOptions.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/client/ui/InterfaceOptions.kt @@ -1,5 +1,6 @@ package world.gregs.voidps.engine.client.ui +import world.gregs.voidps.cache.definition.data.InterfaceDefinition import world.gregs.voidps.engine.client.sendInterfaceSettings import world.gregs.voidps.engine.client.sendScript import world.gregs.voidps.engine.data.definition.InterfaceDefinitions @@ -26,7 +27,7 @@ class InterfaceOptions( val script = if (comp["primary", true]) "primary_options" else "secondary_options" val inventory = inventoryDefinitions.get(comp["inventory", ""]) if (inventory.id != -1) { - val combined = (comp["parent", -1] shl 16) or comp.id + val combined = InterfaceDefinition.pack(comp["parent", -1], comp.id) val all = get(id, component) val options = all.copyOfRange(0, min(9, all.size)) player.sendScript(script, combined, inventory.id, inventory["width", 0], inventory["height", 0], 0, -1, *options) 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 a83871532..30e4956e0 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 @@ -2,6 +2,7 @@ package world.gregs.voidps.engine.client.ui import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import world.gregs.voidps.engine.client.playMusicTrack +import world.gregs.voidps.engine.client.sendScript import world.gregs.voidps.engine.client.ui.chat.Colours import world.gregs.voidps.engine.client.ui.event.CloseInterface import world.gregs.voidps.engine.client.ui.event.InterfaceClosed @@ -287,6 +288,7 @@ fun Player.closeInterfaces(): Boolean { closed = true } queue.clearWeak() + sendScript("close_entry") return closed } diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/DiangoCodeDefinition.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/DiangoCodeDefinition.kt new file mode 100644 index 000000000..b95078190 --- /dev/null +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/config/DiangoCodeDefinition.kt @@ -0,0 +1,25 @@ +package world.gregs.voidps.engine.data.config + +import world.gregs.voidps.engine.entity.item.Item + +/** + * Codes to redeem holiday items from django + * @param variable the variable to unlock this item + * @param add the items added with this code + */ +data class DiangoCodeDefinition( + val variable: String = "", + val add: List = emptyList(), +) { + + companion object { + + @Suppress("UNCHECKED_CAST") + operator fun invoke(map: Map) = DiangoCodeDefinition( + variable = map["variable"] as? String ?: EMPTY.variable, + add = map["add"] as? List ?: EMPTY.add, + ) + + val EMPTY = DiangoCodeDefinition() + } +} \ No newline at end of file diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/DiangoCodeDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/DiangoCodeDefinitions.kt new file mode 100644 index 000000000..f45964df2 --- /dev/null +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/DiangoCodeDefinitions.kt @@ -0,0 +1,58 @@ +package world.gregs.voidps.engine.data.definition + +import com.github.michaelbull.logging.InlineLogger +import world.gregs.voidps.engine.data.config.DiangoCodeDefinition +import world.gregs.voidps.engine.entity.item.Item +import world.gregs.voidps.engine.get +import world.gregs.voidps.engine.getProperty +import world.gregs.voidps.engine.timedLoad +import world.gregs.yaml.Yaml +import world.gregs.yaml.read.YamlReaderConfiguration + +class DiangoCodeDefinitions { + + private lateinit var definitions: Map + + fun get(code: String) = getOrNull(code) ?: DiangoCodeDefinition.EMPTY + + fun getOrNull(code: String) = definitions[code] + + @Suppress("UNCHECKED_CAST") + fun load(yaml: Yaml = get(), path: String = getProperty("diangoCodeDefinitionsPath"), itemDefinitions: ItemDefinitions? = null): DiangoCodeDefinitions { + timedLoad("diango code definition") { + val config = object : YamlReaderConfiguration(2, 2) { + override fun add(list: MutableList, value: Any, parentMap: String?) { + super.add(list, if (value is Map<*, *>) { + val id = value["item"] as String + if (itemDefinitions != null && !itemDefinitions.contains(id)) { + logger.warn { "Invalid diango item id: $id" } + } + Item(id, value["amount"] as? Int ?: 1) + } else { + Item(value as String, amount = 1) + }, parentMap) + } + override fun set(map: MutableMap, key: String, value: Any, indent: Int, parentMap: String?) { + if (key == "<<") { + map.putAll(value as Map) + return + } + if (indent == 0) { + super.set(map, key, DiangoCodeDefinition(value as Map), indent, parentMap) + } else { + super.set(map, key, value, indent, parentMap) + } + } + } + val definitions = yaml.load(path, config) as Map + this.definitions = definitions + definitions.size + } + return this + } + + companion object { + private val logger = InlineLogger() + } + +} \ No newline at end of file diff --git a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/InventoryDefinitions.kt b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/InventoryDefinitions.kt index a218fe9cb..28b026757 100644 --- a/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/InventoryDefinitions.kt +++ b/engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/InventoryDefinitions.kt @@ -29,6 +29,7 @@ class InventoryDefinitions( return } val def = definitions[id] + def.length = map["length"] as? Int ?: def.length def.ids = IntArray(def.length) { itemDefs.get(value.getOrNull(it)?.keys?.first() ?: "").id } def.amounts = IntArray(def.length) { value.getOrNull(it)?.values?.first() ?: 0 } } diff --git a/engine/src/test/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/InteractTest.kt b/engine/src/test/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/InteractTest.kt index 1a0afce30..bc4141a4b 100644 --- a/engine/src/test/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/InteractTest.kt +++ b/engine/src/test/kotlin/world/gregs/voidps/engine/entity/character/mode/interact/InteractTest.kt @@ -1,9 +1,6 @@ package world.gregs.voidps.engine.entity.character.mode.interact -import io.mockk.every -import io.mockk.mockk -import io.mockk.mockkStatic -import io.mockk.spyk +import io.mockk.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DynamicTest.dynamicTest import org.junit.jupiter.api.Test @@ -19,6 +16,7 @@ import org.rsmod.game.pathfinder.StepValidator import org.rsmod.game.pathfinder.collision.CollisionStrategies import world.gregs.voidps.cache.definition.data.NPCDefinition import world.gregs.voidps.engine.GameLoop +import world.gregs.voidps.engine.client.sendScript import world.gregs.voidps.engine.client.ui.close import world.gregs.voidps.engine.client.variable.start import world.gregs.voidps.engine.data.definition.AreaDefinitions @@ -69,11 +67,13 @@ internal class InteractTest : KoinMock() { @BeforeEach fun setup() { mockkStatic("world.gregs.voidps.engine.client.ui.InterfacesKt") + mockkStatic("world.gregs.voidps.engine.client.EncodeExtensionsKt") approached = false operated = false player = spyk(Player(tile = Tile(10, 11))) player.interfaces = mockk(relaxed = true) every { player.close(null) } returns true + every { player.sendScript(any()) } just Runs every { player.interfaces.get(any()) } returns null player.visuals = PlayerVisuals(0, BodyParts()) player.collision = CollisionStrategies.Normal diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/BookPages.kts b/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/BookPages.kts index ef489dfdd..2ce548619 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/BookPages.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/BookPages.kts @@ -14,8 +14,8 @@ inventoryOption("Read") { player.openBook(item.def.getOrNull("book") ?: return@inventoryOption) } -interfaceRefresh("book") { player -> - refreshBook(player) +interfaceRefresh("book", "book_long") { player -> + refreshBook(player, id) } continueDialogue("book", "turn_page_right") { player -> @@ -30,19 +30,31 @@ continueDialogue("book", "turn_page_left") { player -> player.open("book") } -fun refreshBook(player: Player) { +continueDialogue("book_long", "turn_page_right") { player -> + player.inc("book_page") + player.close("book_long") + player.open("book_long") +} + +continueDialogue("book_long", "turn_page_left") { player -> + player.dec("book_page") + player.close("book_long") + player.open("book_long") +} + +fun refreshBook(player: Player, book: String) { val name: String = player["book"] ?: return val pageNumber: Int = player["book_page"] ?: return player.interfaces.apply { - sendText("book", "title", books.title(name)) - sendText("book", "page_number_left", (pageNumber + 1).toString()) - sendText("book", "page_number_right", (pageNumber + 2).toString()) + sendText(book, "title", books.title(name)) + sendText(book, "page_number_left", (pageNumber + 1).toString()) + sendText(book, "page_number_right", (pageNumber + 2).toString()) val pages = books.get(name) - sendVisibility("book", "turn_page_left", pageNumber > 0) - sendVisibility("book", "turn_page_right", pageNumber < pages.lastIndex) + sendVisibility(book, "turn_page_left", pageNumber > 0) + sendVisibility(book, "turn_page_right", pageNumber < pages.lastIndex) val page = pages.getOrNull(pageNumber)?.lines() - for (i in 0 until 30) { - sendText("book", "line${i + 1}", page?.getOrNull(i) ?: "") + for (i in 0 until if (book == "book_long") 30 else 21) { + sendText(book, "line${i + 1}", page?.getOrNull(i) ?: "") } } } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Books.kt b/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Books.kt index 907765e8a..1a0c38ec7 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Books.kt +++ b/game/src/main/kotlin/world/gregs/voidps/world/activity/quest/Books.kt @@ -10,15 +10,18 @@ import world.gregs.yaml.read.YamlReaderConfiguration class Books { + private lateinit var longBooks: Set private lateinit var books: Map> private lateinit var titles: Map - fun get(name: String)= books.getOrDefault(name, emptyList()) + fun isLong(name: String) = longBooks.contains(name) + + fun get(name: String) = books.getOrDefault(name, emptyList()) fun title(name: String) = titles.getOrDefault(name, "") @Suppress("UNCHECKED_CAST") - fun load(yaml: Yaml = get(), path: String = getProperty("bookPath")): Books{ + fun load(yaml: Yaml = get(), path: String = getProperty("bookPath")): Books { timedLoad("book") { val config = object : YamlReaderConfiguration(2, 2) { override fun add(list: MutableList, value: Any, parentMap: String?) { @@ -26,6 +29,7 @@ class Books { } } val data = yaml.load>>(path, config) + this.longBooks = data.mapNotNull { if (it.value["long"] as? Boolean == true) it.value["title"] as String else null }.toSet() this.titles = data.mapValues { it.value["title"] as String } this.books = data.mapValues { it.value["pages"] as List } this.books.size @@ -37,5 +41,5 @@ class Books { fun Player.openBook(name: String) { this["book"] = name this["book_page"] = 0 - open("book") + open(if (get().isLong(name)) "book_long" else "book") } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/GeneralStore.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/GeneralStore.kts new file mode 100644 index 000000000..34512434d --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/npc/shop/GeneralStore.kts @@ -0,0 +1,53 @@ +package world.gregs.voidps.world.interact.entity.npc.shop + +import world.gregs.voidps.engine.entity.character.npc.npcOperate +import world.gregs.voidps.world.interact.dialogue.Happy +import world.gregs.voidps.world.interact.dialogue.Neutral +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("Trade", "shopkeeper*", "shop_assistant*") { + player.openShop(target.def.getOrNull("shop") ?: return@npcOperate) +} + +npcOperate("Talk-to", "shopkeeper*") { + npc("Can I help you at all?") + choice { + option("Yes please. What are you selling?") { + player.openShop(target.def.getOrNull("shop") ?: return@option) + } + option("How should I use your shop?") { + if (target.id.endsWith("lumbridge")) { + npc("I'm glad you ask! The shop has two sections to it: 'Main stock' and 'Free sample items'.") + npc("From 'Main Stock' you can buy as many of the stocked items as you wish. I also offer free samples to help get you started and to keep you coming back.") + npc("Once you take a free sample, I won't give you another for about half an hour. I'm not make of money, you know!") + npc("You can also sell most items to the shop.") + player("Thank you.") + } else { + npc("I'm glad you ask! You can buy as many of the items stocked as you wish. You can also sell most items to the shop.") + player("Thank you.") + } + } + option("No thanks.") + } +} + +npcOperate("Talk-to", "shop_assistant*") { + if (target.id.endsWith("musa_point")) { + npc("It's a beautiful day today, no? Can I do anything for you?") + } else { + npc("Can I help you at all?") + } + choice { + option("Yes please. What are you selling?") { + player.openShop(target.def.getOrNull("shop") ?: return@option) + } + option("How should I use your shop?") { + npc("I'm glad you ask! You can buy as many of the items stocked as you wish. You can also sell most items to the shop.") + player("Thank you.") + } + option("No thanks.") + } +} \ 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 d6d4e679d..8c843298a 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 @@ -1,5 +1,6 @@ package world.gregs.voidps.world.interact.entity.player.display.map +import world.gregs.voidps.engine.client.message 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 @@ -9,6 +10,7 @@ import world.gregs.voidps.engine.entity.character.mode.move.move import world.gregs.voidps.engine.entity.character.player.Player import world.gregs.voidps.engine.inject import world.gregs.voidps.network.login.protocol.encode.updateInterface +import world.gregs.voidps.world.interact.entity.effect.frozen val definitions: InterfaceDefinitions by inject() @@ -56,7 +58,11 @@ interfaceOption("Clear marker", "marker", "world_map") { } interfaceOption(component = "world_map", id = "toplevel*") { - player.open("world_map") + if (player.frozen) { + player.message("You cannot do this at the moment.") // TODO proper message + } else { + player.open("world_map") + } } interfaceOption(component = "close", id = "world_map") { 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 ac4fe2ca6..b215e2a31 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 @@ -67,6 +67,7 @@ interfaceOption(id = "emotes") { id == "yawn" && player.equipped(EquipSlot.Hat).id == "sleeping_cap" -> playEnhancedYawnEmote(player) id == "bow" && player.equipped(EquipSlot.Legs).id == "pantaloons" -> playEnhancedEmote(player, id) id == "dance" && player.equipped(EquipSlot.Legs).id == "flared_trousers" -> playEnhancedEmote(player, id) + id == "flap" && player.equipped(EquipSlot.Feet).id == "chicken_feet" && player.equipped(EquipSlot.Legs).id == "chicken_legs" && player.equipped(EquipSlot.Chest).id == "chicken_wings" && player.equipped(EquipSlot.Hat).id == "chicken_head" -> playEnhancedEmote(player, id) else -> { if (id == "air_guitar") { player.playJingle(id) diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/ItemEmotes.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/ItemEmotes.kts index cc304e081..974f2016b 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/ItemEmotes.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/ItemEmotes.kts @@ -7,6 +7,8 @@ import world.gregs.voidps.engine.client.ui.dialogue.continueDialogue import world.gregs.voidps.engine.client.ui.open import world.gregs.voidps.engine.client.variable.hasClock import world.gregs.voidps.engine.entity.character.clearAnimation +import world.gregs.voidps.engine.entity.character.forceChat +import world.gregs.voidps.engine.entity.character.player.playerOperate import world.gregs.voidps.engine.entity.character.player.skill.Skill import world.gregs.voidps.engine.entity.character.setGraphic import world.gregs.voidps.engine.inv.add @@ -16,11 +18,13 @@ import world.gregs.voidps.engine.suspend.awaitInterfaces import world.gregs.voidps.engine.suspend.playAnimation import world.gregs.voidps.type.random import world.gregs.voidps.world.interact.dialogue.continueDialogue +import world.gregs.voidps.world.interact.entity.combat.weapon import world.gregs.voidps.world.interact.entity.player.equip.inventoryItem import world.gregs.voidps.world.interact.entity.player.equip.inventoryOptions import world.gregs.voidps.world.interact.entity.player.toxin.curePoison import world.gregs.voidps.world.interact.entity.player.toxin.poisoned import world.gregs.voidps.world.interact.entity.sound.playJingle +import world.gregs.voidps.world.interact.entity.sound.playSound inventoryItem("Fly", "toy_kite") { if (player.hasClock("emote_delay")) { @@ -36,6 +40,7 @@ inventoryItem("Emote", "reindeer_hat", "worn_equipment") { return@inventoryItem } player.setGraphic("emote_reindeer") + player.setGraphic("emote_reindeer_2") player.playAnimation("emote_reindeer") } @@ -64,11 +69,22 @@ inventoryItem("Recite-prayer", "prayer_book", "inventory") { player.playAnimation("emote_recite_prayer") } +playerOperate("Whack") { + if (player.weapon.id == "rubber_chicken") { + player.playSound("rubber_chicken_whack") + player.playAnimation("rubber_chicken_whack") + } else { + //todo player.playSound("") + player.playAnimation("easter_carrot_whack") + } +} + inventoryItem("Dance", "rubber_chicken") { if (player.hasClock("emote_delay")) { player.message("Please wait till you've finished performing your current emote.") return@inventoryItem } + player.playJingle("easter_scape_scrambled") player.playAnimation("emote_chicken_dance") } @@ -114,4 +130,108 @@ inventoryOptions("Play", "Loop", "Walk", "Crazy", item = "yo_yo", inventory = "i return@inventoryOptions } player.playAnimation("emote_yoyo_${option.lowercase()}") +} + +inventoryItem("Spin", "candy_cane", "worn_equipment") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.playAnimation("emote_candy_cane_spin") +} + +inventoryItem("Dance", "salty_claws_hat", "worn_equipment") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.playAnimation("emote_salty_claws_hat_dance") +} + +inventoryItem("Celebrate", "tenth_anniversary_cake") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.setGraphic("10th_anniversary_cake") + player.playAnimation("emote_10th_anniversary_cake") +} + +inventoryItem("Brandish (2009)", "golden_hammer", "worn_equipment") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.playAnimation("emote_golden_hammer_brandish") +} + +inventoryItem("Spin (2010)", "golden_hammer", "worn_equipment") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.setGraphic("emote_golden_hammer_spin") + player.playAnimation("emote_golden_hammer_spin") +} + +inventoryOptions("Jump", "Walk", "Bow", "Dance", item = "*_marionette", inventory = "inventory") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryOptions + } + player.setGraphic("emote_${item.id}_${option.lowercase()}") + player.playAnimation("emote_marionette_${option.lowercase()}") +} + +inventoryItem("Sleuth", "magnifying_glass", "worn_equipment") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.playAnimation("emote_magnifying_glass_sleuth") +} + +inventoryItem("Emote", "chocatrice_cape", "worn_equipment") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.setGraphic("emote_chocatrice_cape") + player.playAnimation("emote_chocatrice_cape") +} + +inventoryItem("Juggle", "squirrel_ears", "worn_equipment") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.setGraphic("emote_squirrel_ears") + player.playAnimation("emote_squirrel_ears") +} + +inventoryItem("Play-with", "toy_horsey_*") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryItem + } + player.forceChat = when (random.nextInt(0, 3)) { + 0 -> "Come on Dobbin, we can win the race!" + 1 -> "Hi-ho Silver, and away!" + else -> "Neaahhhyyy! Giddy-up horsey!" + } +// player.forceChat = "Just say neigh to gambling!" + player.playAnimation("emote_${item.id}") +} + +inventoryOptions("Play-with", item = "eek") { + if (player.hasClock("emote_delay")) { + player.message("Please wait till you've finished performing your current emote.") + return@inventoryOptions + } + player.setGraphic("play_with_eek") + player.playAnimation("play_with_eek") +} + +inventoryItem("Summon Minion", "squirrel_ears", "worn_equipment") { + //todo summon npc 9682 and 9681 if dismiss have to wait 30mins before able to summon again } \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Morphing.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Morphing.kts new file mode 100644 index 000000000..375caa14f --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Morphing.kts @@ -0,0 +1,40 @@ +package world.gregs.voidps.world.interact.entity.player.display.tab + +import world.gregs.voidps.engine.client.ui.close +import world.gregs.voidps.engine.client.ui.interfaceOption +import world.gregs.voidps.engine.client.ui.open +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.queue.queue +import world.gregs.voidps.world.interact.entity.effect.clearTransform +import world.gregs.voidps.world.interact.entity.effect.movementDelay +import world.gregs.voidps.world.interact.entity.effect.transform +import world.gregs.voidps.world.interact.entity.player.equip.inventoryOptions +import kotlin.random.Random + +inventoryOptions("Wear", item = "easter_ring") { + morph(player, "easter_egg_${Random.nextInt(0, 6)}") +} + +inventoryOptions("Wear", item = "ring_of_stone") { + morph(player, item.id) +} + +interfaceOption("Ok", "unmorph", "morph") { + unmorph(player) +} + +fun morph(player: Player, npc: String) { + player.transform(npc) + player.movementDelay = Int.MAX_VALUE + player.softTimers.start("movement_delay") + player.open("morph") + player.queue("morph", onCancel = { unmorph(player) }) { + } +} + +fun unmorph(player: Player) { + player.queue.clear() + player.clearTransform() + player.movementDelay = 0 + player.close("morph") +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Whacking.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Whacking.kts new file mode 100644 index 000000000..3df251bd1 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/display/tab/Whacking.kts @@ -0,0 +1,29 @@ +package world.gregs.voidps.world.interact.entity.player.display.tab + +import world.gregs.voidps.engine.entity.playerSpawn +import world.gregs.voidps.engine.inv.itemAdded +import world.gregs.voidps.engine.inv.itemRemoved +import world.gregs.voidps.network.login.protocol.visual.update.player.EquipSlot +import world.gregs.voidps.world.interact.entity.combat.weapon + +itemAdded("rubber_chicken", EquipSlot.Weapon, "worn_equipment") { player -> + player.options.set(5, "Whack") +} + +itemRemoved("rubber_chicken", EquipSlot.Weapon, "worn_equipment") { player -> + player.options.remove("Whack") +} + +itemAdded("easter_carrot", EquipSlot.Weapon, "worn_equipment") { player -> + player.options.set(5, "Whack") +} + +itemRemoved("easter_carrot", EquipSlot.Weapon, "worn_equipment") { player -> + player.options.remove("Whack") +} + +playerSpawn { player -> + if (player.weapon.id == "rubber_chicken" || player.weapon.id == "easter_carrot") { + player.options.set(5, "Whack") + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/equip/Equipping.kts b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/equip/Equipping.kts index d51fb97d0..c282d3f80 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/equip/Equipping.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/interact/entity/player/equip/Equipping.kts @@ -27,7 +27,6 @@ inventoryOptions("Wield", "Wear", "Hold", "Equip", inventory = "inventory") { player.inventoryFull() return@inventoryOptions } - if (replace2hWithShield(player, def) || replaceShieldWith2h(player, def)) { player.inventory.move(slot, player.equipment, item.slot.index) player.equipment.move(getOtherHandSlot(item.slot).index, player.inventory) @@ -44,6 +43,9 @@ inventoryOptions("Wield", "Wear", "Hold", "Equip", inventory = "inventory") { } inventoryOption("Remove", "worn_equipment") { + if (item.id == "rubber_chicken" || item.id == "easter_carrot") { + player.options.remove("Whack") + } player.equipment.move(slot, player.inventory) when (player.equipment.transaction.error) { TransactionError.None -> playEquipSound(player, item.def) @@ -95,16 +97,18 @@ fun playEquipSound(player: Player, item: ItemDefinition) { name.contains("salamander") -> "equip_salamander" name.contains("banner") -> "equip_banner" name.contains("blunt") -> "equip_blunt" - name.contains("ghost buster 500") -> "equip_halloween_spray" + name.contains("ghost buster 500") -> "equip_halloween_spray" name == "sled" -> "equip_sled" name == "dark bow" -> "equip_darkbow" name == "silverlight" -> "equip_silverlight" else -> if (material == "metal") "equip_sword" else "equip_clothes" } + EquipSlot.Hat -> when { name == "jack lantern mask" -> "equip_halloween_pumpkin" else -> if (material == "metal") "equip_helm" else "equip_clothes" } + EquipSlot.Chest -> if (material == "metal") "equip_body" else "equip_clothes" EquipSlot.Shield -> if (material == "metal") "equip_shield" else "equip_clothes" EquipSlot.Legs -> if (material == "metal") "equip_legs" else "equip_clothes" diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/Mill.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/Mill.kts index ba925910d..4badf9954 100644 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/Mill.kts +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/Mill.kts @@ -66,7 +66,7 @@ itemOnObjectOperate("grain", "hopper") { } } -objectOperate("Take-flour", "flour_bin_3") { +objectOperate("Take-flour", "flour_bin") { if (!player.holdsItem("empty_pot")) { player.message("You need an empty pot to hold the flour in.") return@objectOperate diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Dommik.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Dommik.kts new file mode 100644 index 000000000..c7b5e213a --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Dommik.kts @@ -0,0 +1,23 @@ +package world.gregs.voidps.world.map.al_kharid + +import world.gregs.voidps.engine.entity.character.npc.npcOperate +import world.gregs.voidps.world.interact.dialogue.* +import world.gregs.voidps.world.interact.dialogue.type.choice +import world.gregs.voidps.world.interact.dialogue.type.npc +import world.gregs.voidps.world.interact.entity.npc.shop.openShop + +npcOperate("Talk-to", "dommik") { + npc("Would you like to buy some crafting equipment?") + choice { + option("No thanks; I've got all the Crafting equipment I need.") { + npc("Okay. Fare well on your travels.") + } + option("Let's see what you've got, then.") { + player.openShop("dommiks_crafting_store") + } + } +} + +npcOperate("Trade", "dommik") { + player.openShop("dommiks_crafting_store") +} diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Karim.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Karim.kts new file mode 100644 index 000000000..7d2f8baf5 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Karim.kts @@ -0,0 +1,27 @@ +package world.gregs.voidps.world.map.al_kharid + +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.entity.character.npc.npcOperate +import world.gregs.voidps.engine.inv.add +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.engine.inv.remove +import world.gregs.voidps.world.interact.dialogue.* +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", "karim") { + npc("Would you like to buy a nice kebab? Only one gold.") + choice { + option("I think I'll give it a miss.") + option("Yes please.") { + if (player.inventory.remove("coins", 1)) { + player.inventory.add("kebab") + player.message("You buy a kebab.") + } else { + player("Oops, I forgot to bring any money with me.") + npc("Come back when you have some.") + } + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/LouieLegs.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/LouieLegs.kts new file mode 100644 index 000000000..55027aaf8 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/LouieLegs.kts @@ -0,0 +1,18 @@ +package world.gregs.voidps.world.map.al_kharid + +import world.gregs.voidps.engine.entity.character.npc.npcOperate +import world.gregs.voidps.world.interact.dialogue.* +import world.gregs.voidps.world.interact.dialogue.type.choice +import world.gregs.voidps.world.interact.dialogue.type.npc +import world.gregs.voidps.world.interact.entity.npc.shop.openShop + +npcOperate("Talk-to", "louie_legs") { + npc("Hey, wanna buy some armour?") + choice { + option("What have you got?") { + npc("I provide items to help you keep your legs!") + player.openShop("louies_armoured_legs_bazaar") + } + option("No, thank you.") + } +} diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ranael.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ranael.kts new file mode 100644 index 000000000..30d247d92 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/al_kharid/Ranael.kts @@ -0,0 +1,17 @@ +package world.gregs.voidps.world.map.al_kharid + +import world.gregs.voidps.engine.entity.character.npc.npcOperate +import world.gregs.voidps.world.interact.dialogue.* +import world.gregs.voidps.world.interact.dialogue.type.choice +import world.gregs.voidps.world.interact.dialogue.type.npc +import world.gregs.voidps.world.interact.entity.npc.shop.openShop + +npcOperate("Talk-to", "ranael") { + npc("Do you want to buy any armoured skirts? Designed especially for ladies who like to fight.") + choice { + option("Yes please.") { + player.openShop("ranaels_super_skirt_store") + } + option("No thank you, that's not my scene.") + } +} diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/draynor/Diango.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/draynor/Diango.kts new file mode 100644 index 000000000..e3edf3b4f --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/draynor/Diango.kts @@ -0,0 +1,68 @@ +package world.gregs.voidps.world.map.draynor + +import world.gregs.voidps.engine.client.message +import world.gregs.voidps.engine.client.ui.open +import world.gregs.voidps.engine.data.definition.DiangoCodeDefinitions +import world.gregs.voidps.engine.entity.character.npc.npcOperate +import world.gregs.voidps.engine.entity.character.player.chat.inventoryFull +import world.gregs.voidps.engine.inject +import world.gregs.voidps.engine.inv.inventory +import world.gregs.voidps.engine.inv.transact.operation.AddItem.add +import world.gregs.voidps.world.interact.dialogue.Chuckle +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.type.choice +import world.gregs.voidps.world.interact.dialogue.type.npc +import world.gregs.voidps.world.interact.dialogue.type.stringEntry +import world.gregs.voidps.world.interact.entity.npc.shop.openShop + +npcOperate("Talk-to", "diango") { + npc("Howdy there partner! Want to see my spinning plates? Or did ya want a holiday item back?") + choice { + option("Spinning plates?") { + npc("That's right. There's a funny story behind them, their shipment was held up by thieves.") + npc("The crate was marked 'Dragon Plates'. Apparently they thought it was some kind of armour, when really it's just a plate with a dragon on it!") + player.openShop("diangos_toy_store") + } + option("I'd like to check holiday items please!") { + player.open("diangos_item_retrieval") + } + option("What else are you selling?") { + player.openShop("diangos_toy_store") + } + option("I'm fine, thanks.") + } +} + +npcOperate("Holiday-items", "diango") { + player.open("diangos_item_retrieval") +} + +val codeDefinitions: DiangoCodeDefinitions by inject() + +npcOperate("Redeem-code", "diango") { + val code = stringEntry("Please enter your code.").lowercase() + val definition = codeDefinitions.getOrNull(code) + if (definition == null) { + player.message("Your code was not valid. Please check it and try again.") + return@npcOperate + } + for (item in definition.add) { + if (player[definition.variable, false]) { + player.message("You have already claimed this code.") + return@npcOperate + } + } + val success = player.inventory.transaction { + for (item in definition.add) { + add(item.id, item.amount) + } + } + if (success) { + player[definition.variable] = true + player.message("Your code has been successfully processed.") + } else { + player.inventoryFull() + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/draynor/DiangoItemRetrieval.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/draynor/DiangoItemRetrieval.kts new file mode 100644 index 000000000..c77f55c82 --- /dev/null +++ b/game/src/main/kotlin/world/gregs/voidps/world/map/draynor/DiangoItemRetrieval.kts @@ -0,0 +1,100 @@ +package world.gregs.voidps.world.map.draynor + +import world.gregs.voidps.cache.definition.data.InterfaceDefinition +import world.gregs.voidps.engine.client.sendScript +import world.gregs.voidps.engine.client.ui.event.interfaceClose +import world.gregs.voidps.engine.client.ui.event.interfaceOpen +import world.gregs.voidps.engine.client.ui.interfaceOption +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.chat.inventoryFull +import world.gregs.voidps.engine.entity.playerDespawn +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.sendInventory +import world.gregs.voidps.engine.inv.transact.operation.AddItem.add +import world.gregs.voidps.engine.inv.transact.operation.ClearItem.clear +import world.gregs.voidps.world.activity.bank.ownsItem + +val itemLimit = 48 +val container = InterfaceDefinition.pack(468, 2) +val scrollbar = InterfaceDefinition.pack(468, 3) + +interfaceOpen("diangos_item_retrieval") { player -> + refreshItems(player) +} + +interfaceOption("Claim", "items", "diangos_item_retrieval") { + when (item.id) { + "more" -> { + player["retrieve_more"] = true + player.sendScript("scrollbar_resize", scrollbar, container, 0) // Scroll to top + } + + "back" -> player.clear("retrieve_more") + else -> if (!player.inventory.add(item.id)) { + player.inventoryFull() + } + } + refreshItems(player) +} + +val inventoryDefinitions: InventoryDefinitions by inject() +val itemDefinitions: ItemDefinitions by inject() + +fun refreshItems(player: Player) { + val more: Boolean = player["retrieve_more", false] + player.inventories.clear("diangos_item_retrieval") + val inventory = player.inventories.inventory("diangos_item_retrieval") + val defaults = inventoryDefinitions.get("diangos_item_retrieval").getOrNull>>("defaults") ?: return + var displayMore = false + inventory.transaction { + clear() + // Add back "button" when displaying excess + if (more) { + add("back") + } + var skipped = 0 + for (index in 0 until inventory.size) { + val map = defaults.getOrNull(index) ?: continue + val id = map.keys.firstOrNull() ?: continue + val event: String? = itemDefinitions.get(id).getOrNull("event") + if ((event == null || player[event, false]) && !player.ownsItem(id)) { + // Add second screen if itemLimit is reached + if (!more && inventory.count >= itemLimit) { + displayMore = true + break + } + // If displaying second screen skip first X items + if (more && skipped++ < itemLimit) { + continue + } + add(id) + } + } + // Add more "button" when too many to display + if (displayMore) { + add("more") + } + } + player.interfaceOptions.unlockAll("diangos_item_retrieval", "items", 0..inventory.count) + player.sendInventory("diangos_item_retrieval") + if (displayMore) { + player.sendScript("scrollbar_vertical", scrollbar, container) + player.sendScript("set_scroll_height", scrollbar, container, 300, 0) + player.sendScript("interface_inv_init", container, 453, 8, 7, 0, -1, "Claim", "", "", "", "") + } else { + player.sendScript("interface_inv_init", container, 453, 8, 6, 0, -1, "Claim", "", "", "", "") + } +} + +playerDespawn { player -> + // Don't want to store in account save + player.inventories.clear("diangos_item_retrieval") +} + +interfaceClose("diangos_item_retrieval") { player -> + player.inventories.clear(id) +} \ No newline at end of file diff --git a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/GeneralStore.kts b/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/GeneralStore.kts deleted file mode 100644 index 899f32d7e..000000000 --- a/game/src/main/kotlin/world/gregs/voidps/world/map/lumbridge/GeneralStore.kts +++ /dev/null @@ -1,45 +0,0 @@ -package world.gregs.voidps.world.map.lumbridge - -import world.gregs.voidps.engine.entity.character.npc.npcOperate -import world.gregs.voidps.world.interact.dialogue.Happy -import world.gregs.voidps.world.interact.dialogue.Neutral -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 -import world.gregs.voidps.world.interact.entity.npc.shop.openShop - -npcOperate("Trade", "shopkeeper*", "shop_assistant*") { - player.openShop("lumbridge_general_store") -} - -npcOperate("Talk-to", "shopkeeper*") { - npc("Can I help you at all?") - choice { - option("Yes please. What are you selling?") { - player.openShop("lumbridge_general_store") - } - option("How should I use your shop?") { - npc("I'm glad you ask! The shop has two sections to it: 'Main stock' and 'Free sample items'.") - npc("From 'Main Stock' you can buy as many of the stocked items as you wish. I also offer free samples to help get you started and to keep you coming back.") - npc("Once you take a free sample, I won't give you another for about half an hour. I'm not make of money, you know!") - npc("You can also sell most items to the shop.") - player("Thank you.") - } - option("No thanks.") - } -} - -npcOperate("Talk-to", "shop_assistant*") { - npc("Can I help you at all?") - choice { - option("Yes please. What are you selling?") { - player.openShop("lumbridge_general_store") - } - option("How should I use your shop?") { - npc("I'm glad you ask! You can buy as many of the items stocked as you wish. You can also sell most items to the shop.") - player("Thank you.") - } - option("No thanks.") - } -} \ No newline at end of file diff --git a/game/src/main/resources/game.properties b/game/src/main/resources/game.properties index 781c724a0..07ee9f8f6 100644 --- a/game/src/main/resources/game.properties +++ b/game/src/main/resources/game.properties @@ -67,6 +67,7 @@ spellDefinitionsPath=./data/definitions/spells.yml patrolDefinitionsPath=./data/definitions/patrols.yml prayerDefinitionsPath=./data/definitions/prayers.yml itemOnItemDefinitionsPath=./data/definitions/item-on-item.yml +diangoCodeDefinitionsPath=./data/definitions/diango-codes.yml gearDefinitionsPath=./data/definitions/gear-sets.yml enumDefinitionsPath=./data/definitions/enums.yml structDefinitionsPath=./data/definitions/structs.yml diff --git a/game/src/test/resources/test.properties b/game/src/test/resources/test.properties index bdfecc8e0..92b248e86 100644 --- a/game/src/test/resources/test.properties +++ b/game/src/test/resources/test.properties @@ -30,6 +30,7 @@ renderEmoteDefinitionsPath=../data/definitions/render-emotes.yml midiDefinitionsPath=../data/definitions/midis.yml jingleDefinitionsPath=../data/definitions/jingles.yml itemOnItemDefinitionsPath=../data/definitions/item-on-item.yml +diangoCodeDefinitionsPath=../data/definitions/diango-codes.yml spellDefinitionsPath=../data/definitions/spells.yml patrolDefinitionsPath=../data/definitions/patrols.yml prayerDefinitionsPath=../data/definitions/prayers.yml diff --git a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/NPCOption5Decoder.kt b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/NPCOption5Decoder.kt index c748988a4..a1e492526 100644 --- a/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/NPCOption5Decoder.kt +++ b/network/src/main/kotlin/world/gregs/voidps/network/login/protocol/decode/NPCOption5Decoder.kt @@ -4,13 +4,13 @@ import io.ktor.utils.io.core.* import world.gregs.voidps.network.client.Instruction import world.gregs.voidps.network.client.instruction.InteractNPC import world.gregs.voidps.network.login.protocol.Decoder -import world.gregs.voidps.network.login.protocol.readBooleanAdd +import world.gregs.voidps.network.login.protocol.readBooleanInverse class NPCOption5Decoder : Decoder(3) { override suspend fun decode(packet: ByteReadPacket): Instruction { - val run = packet.readBooleanAdd() - val npcIndex = packet.readShortLittleEndian().toInt() + val npcIndex = packet.readShort().toInt() + val run = packet.readBooleanInverse() return InteractNPC(npcIndex, 5) } diff --git a/network/src/test/resources/decoder-packets.csv b/network/src/test/resources/decoder-packets.csv index 9f6b7a171..f10a8ce51 100644 --- a/network/src/test/resources/decoder-packets.csv +++ b/network/src/test/resources/decoder-packets.csv @@ -45,588 +45,7 @@ 29, -71, 48, -127 5, 48, 57, 1 62, 57, 48, -127 -65, -127, 57, 48 -46, 48, 57 -27, 127, 82, 4, -41, 17, 48, 57 -36, 87, 17, 4, 82, 127, -71, 48 -80, 17, 87, -71, 48, -46, 4, -127 -56, -127, 48, -71, 4, 82, -41, 17 -38, -41, 17, -127, 82, 4, 48, -71 -0, -25, 82, 4, -1 -12, 1, 4, -46 -79, 127, -46, 4 -44, 4, -46, -127 -81, 4, 82, 1 -51, 1, 4, 82 -57, 4, 82, -127 -18, 1, 4, 82 -20, 110, 97, 109, 101, 0, 7, -95, -18, -94, -52 -19, 110, 97, 109, 101, 0, 4, -46, 123 -41, 123, 12, 7, -95, -18, -94, -52 -3, 12, 4, -46, 123 -77, 123 -4, -47, 0, 0, 48, 57 -66, 110, 97, 109, 101, 0, 12, 123, 109, 101, 115, 115, 97, 103, 101, 0 -28, 48, 57 -7, 12, 1, 89, 2, -90, 9 -76, 82, 4, -31, 16 -43, 97, 32, 115, 116, 114, 105, 110, 103, 0 -84, 123 -71, 4, -46 -35, -31, 16, -127, 4, 82 -82, -31, 16, -127, 4, 82, -1, -1, 48, 57, 123, 12, 21, 23, 1, 65, 1, -80, 32 -49, 48, 57, 0, 0, -44, 49 -8, 1 -52, 0, 0, 48, 57 -58, 0, 0, 48, 57 -10, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -14, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -13, 48, 57 -40, 57, 48, 21, -72, -113, 25, 0, 0, -91, 110, 29, 102 -31, 123 -50, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -64, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -1, 0, 0, 4, -46, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -74, 5, 102, 114, 105, 101, 110, 100, 32, 110, 97, 109, 101, 0 -53, 1, 2, 105, 116, 101, 109, 32, 97, 98, 121, 115, 115, 97, 108, 95, 119, 104, 105, 112, 32, 49, 0 -6, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -73, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -2, 0, -121, 1, -56, 0, 123 -37, 48, 57 -22, 48, 57, 21, 56, 26, -123, 127 -16, 26, 5, 48, -71, 56, 21, -1 -45, 48, 57, 21, -72, 1, 5, 26 -24, 127, 21, -72, -123, 26, 48, 57 -26, 26, -123, 21, -72, -1, 48, -71 -67, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 0, 115, 101, 97, 114, 99, 104, 0, 123 -32, 0, 0, 48, 57 -70, -34, -46, 4, 48, -71, 12, 0, 16, -31, 1, 91, 32, 1, -56, 0, 123 -72, 2, -114, 1, 65, 123, 0, -56, 1, 0, -116, 48, 57, 0, -107, 91, -96 -61, -116, 0, 0, 123, 1, -56, 57, 48, -127, 91, 32 -54, 91, -96, 82, 4, -56, 1, 123, 0, 16, 97, 127, 12, 0, 57, 48 -48, -116, 0, -46, 4, -96, 91, 123, 0, -56, 1, -1 -23, 0, 123, 1, -56, 91, -96, 0, 12 -59, 0, 123, 1, -56, 91, -96, 0, 12 -9, 0, 123, 1, -56, 91, -96, 0, 12 -15, 0, 123, 1, -56, 91, -96, 0, 12 -17, 0, 123, 1, -56, 91, -96, 0, 12 -39, 0, 123, 1, -56, 91, -96, 0, 12 -33, 0, 123, 1, -56, 91, -96, 0, 12 -60, 0, 123, 1, -56, 91, -96, 0, 12 -11, 0, 123, 1, -56, 91, -96, 0, 12 -42, 0, 123, 1, -56, 91, -96, 0, 12 -78, 0, 123, 1, -56, 21, 0, 1, 65, 2, -114, 91, -96, -116, 0, -71, 48 -69, 1, 0, 123, 2, 1, 65 -75, 123, -56, 21 -30, 0, 1, -30, 64 -55, 48, 57, 91, -96 -68, 48, 57 -63, 1, 57, 48 -29, -71, 48, -127 -5, 48, 57, 1 -62, 57, 48, -127 -65, -127, 57, 48 -46, 48, 57 -27, 127, 82, 4, -41, 17, 48, 57 -36, 87, 17, 4, 82, 127, -71, 48 -80, 17, 87, -71, 48, -46, 4, -127 -56, -127, 48, -71, 4, 82, -41, 17 -38, -41, 17, -127, 82, 4, 48, -71 -0, -25, 82, 4, -1 -12, 1, 4, -46 -79, 127, -46, 4 -44, 4, -46, -127 -81, 4, 82, 1 -51, 1, 4, 82 -57, 4, 82, -127 -18, 1, 4, 82 -20, 110, 97, 109, 101, 0, 7, -95, -18, -94, -52 -19, 110, 97, 109, 101, 0, 4, -46, 123 -41, 123, 12, 7, -95, -18, -94, -52 -3, 12, 4, -46, 123 -77, 123 -4, -47, 0, 0, 48, 57 -66, 110, 97, 109, 101, 0, 12, 123, 109, 101, 115, 115, 97, 103, 101, 0 -28, 48, 57 -7, 12, 1, 89, 2, -90, 9 -76, 82, 4, -31, 16 -43, 97, 32, 115, 116, 114, 105, 110, 103, 0 -84, 123 -71, 4, -46 -35, -31, 16, -127, 4, 82 -82, -31, 16, -127, 4, 82, -1, -1, 48, 57, 123, 12, 21, 23, 1, 65, 1, -80, 32 -49, 48, 57, 0, 0, -44, 49 -8, 1 -52, 0, 0, 48, 57 -58, 0, 0, 48, 57 -10, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -14, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -13, 48, 57 -40, 57, 48, 21, -72, -113, 25, 0, 0, -91, 110, 29, 102 -31, 123 -50, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -64, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -1, 0, 0, 4, -46, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -74, 5, 102, 114, 105, 101, 110, 100, 32, 110, 97, 109, 101, 0 -53, 1, 2, 105, 116, 101, 109, 32, 97, 98, 121, 115, 115, 97, 108, 95, 119, 104, 105, 112, 32, 49, 0 -6, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -73, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -2, 0, -121, 1, -56, 0, 123 -37, 48, 57 -22, 48, 57, 21, 56, 26, -123, 127 -16, 26, 5, 48, -71, 56, 21, -1 -45, 48, 57, 21, -72, 1, 5, 26 -24, 127, 21, -72, -123, 26, 48, 57 -26, 26, -123, 21, -72, -1, 48, -71 -67, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 0, 115, 101, 97, 114, 99, 104, 0, 123 -32, 0, 0, 48, 57 -70, -34, -46, 4, 48, -71, 12, 0, 16, -31, 1, 91, 32, 1, -56, 0, 123 -72, 2, -114, 1, 65, 123, 0, -56, 1, 0, -116, 48, 57, 0, -107, 91, -96 -61, -116, 0, 0, 123, 1, -56, 57, 48, -127, 91, 32 -54, 91, -96, 82, 4, -56, 1, 123, 0, 16, 97, 127, 12, 0, 57, 48 -48, -116, 0, -46, 4, -96, 91, 123, 0, -56, 1, -1 -23, 0, 123, 1, -56, 91, -96, 0, 12 -59, 0, 123, 1, -56, 91, -96, 0, 12 -9, 0, 123, 1, -56, 91, -96, 0, 12 -15, 0, 123, 1, -56, 91, -96, 0, 12 -17, 0, 123, 1, -56, 91, -96, 0, 12 -39, 0, 123, 1, -56, 91, -96, 0, 12 -33, 0, 123, 1, -56, 91, -96, 0, 12 -60, 0, 123, 1, -56, 91, -96, 0, 12 -11, 0, 123, 1, -56, 91, -96, 0, 12 -42, 0, 123, 1, -56, 91, -96, 0, 12 -78, 0, 123, 1, -56, 21, 0, 1, 65, 2, -114, 91, -96, -116, 0, -71, 48 -69, 1, 0, 123, 2, 1, 65 -75, 123, -56, 21 -30, 0, 1, -30, 64 -55, 48, 57, 91, -96 -68, 48, 57 -63, 1, 57, 48 -29, -71, 48, -127 -5, 48, 57, 1 -62, 57, 48, -127 -65, -127, 57, 48 -46, 48, 57 -27, 127, 82, 4, -41, 17, 48, 57 -36, 87, 17, 4, 82, 127, -71, 48 -80, 17, 87, -71, 48, -46, 4, -127 -56, -127, 48, -71, 4, 82, -41, 17 -38, -41, 17, -127, 82, 4, 48, -71 -0, -25, 82, 4, -1 -12, 1, 4, -46 -79, 127, -46, 4 -44, 4, -46, -127 -81, 4, 82, 1 -51, 1, 4, 82 -57, 4, 82, -127 -18, 1, 4, 82 -20, 110, 97, 109, 101, 0, 7, -95, -18, -94, -52 -19, 110, 97, 109, 101, 0, 4, -46, 123 -41, 123, 12, 7, -95, -18, -94, -52 -3, 12, 4, -46, 123 -77, 123 -4, -47, 0, 0, 48, 57 -66, 110, 97, 109, 101, 0, 12, 123, 109, 101, 115, 115, 97, 103, 101, 0 -28, 48, 57 -7, 12, 1, 89, 2, -90, 9 -76, 82, 4, -31, 16 -43, 97, 32, 115, 116, 114, 105, 110, 103, 0 -84, 123 -71, 4, -46 -35, -31, 16, -127, 4, 82 -82, -31, 16, -127, 4, 82, -1, -1, 48, 57, 123, 12, 21, 23, 1, 65, 1, -80, 32 -49, 48, 57, 0, 0, -44, 49 -8, 1 -52, 0, 0, 48, 57 -58, 0, 0, 48, 57 -10, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -14, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -13, 48, 57 -40, 57, 48, 21, -72, -113, 25, 0, 0, -91, 110, 29, 102 -31, 123 -50, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -64, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -1, 0, 0, 4, -46, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -74, 5, 102, 114, 105, 101, 110, 100, 32, 110, 97, 109, 101, 0 -53, 1, 2, 105, 116, 101, 109, 32, 97, 98, 121, 115, 115, 97, 108, 95, 119, 104, 105, 112, 32, 49, 0 -6, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -73, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -2, 0, -121, 1, -56, 0, 123 -37, 48, 57 -22, 48, 57, 21, 56, 26, -123, 127 -16, 26, 5, 48, -71, 56, 21, -1 -45, 48, 57, 21, -72, 1, 5, 26 -24, 127, 21, -72, -123, 26, 48, 57 -26, 26, -123, 21, -72, -1, 48, -71 -67, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 0, 115, 101, 97, 114, 99, 104, 0, 123 -32, 0, 0, 48, 57 -70, -34, -46, 4, 48, -71, 12, 0, 16, -31, 1, 91, 32, 1, -56, 0, 123 -72, 2, -114, 1, 65, 123, 0, -56, 1, 0, -116, 48, 57, 0, -107, 91, -96 -61, -116, 0, 0, 123, 1, -56, 57, 48, -127, 91, 32 -54, 91, -96, 82, 4, -56, 1, 123, 0, 16, 97, 127, 12, 0, 57, 48 -48, -116, 0, -46, 4, -96, 91, 123, 0, -56, 1, -1 -23, 0, 123, 1, -56, 91, -96, 0, 12 -59, 0, 123, 1, -56, 91, -96, 0, 12 -9, 0, 123, 1, -56, 91, -96, 0, 12 -15, 0, 123, 1, -56, 91, -96, 0, 12 -17, 0, 123, 1, -56, 91, -96, 0, 12 -39, 0, 123, 1, -56, 91, -96, 0, 12 -33, 0, 123, 1, -56, 91, -96, 0, 12 -60, 0, 123, 1, -56, 91, -96, 0, 12 -11, 0, 123, 1, -56, 91, -96, 0, 12 -42, 0, 123, 1, -56, 91, -96, 0, 12 -78, 0, 123, 1, -56, 21, 0, 1, 65, 2, -114, 91, -96, -116, 0, -71, 48 -69, 1, 0, 123, 2, 1, 65 -75, 123, -56, 21 -30, 0, 1, -30, 64 -55, 48, 57, 91, -96 -68, 48, 57 -63, 1, 57, 48 -29, -71, 48, -127 -5, 48, 57, 1 -62, 57, 48, -127 -65, -127, 57, 48 -46, 48, 57 -27, 127, 82, 4, -41, 17, 48, 57 -36, 87, 17, 4, 82, 127, -71, 48 -80, 17, 87, -71, 48, -46, 4, -127 -56, -127, 48, -71, 4, 82, -41, 17 -38, -41, 17, -127, 82, 4, 48, -71 -0, -25, 82, 4, -1 -12, 1, 4, -46 -79, 127, -46, 4 -44, 4, -46, -127 -81, 4, 82, 1 -51, 1, 4, 82 -57, 4, 82, -127 -18, 1, 4, 82 -20, 110, 97, 109, 101, 0, 7, -95, -18, -94, -52 -19, 110, 97, 109, 101, 0, 4, -46, 123 -41, 123, 12, 7, -95, -18, -94, -52 -3, 12, 4, -46, 123 -77, 123 -4, -47, 0, 0, 48, 57 -66, 110, 97, 109, 101, 0, 12, 123, 109, 101, 115, 115, 97, 103, 101, 0 -28, 48, 57 -7, 12, 1, 89, 2, -90, 9 -76, 82, 4, -31, 16 -43, 97, 32, 115, 116, 114, 105, 110, 103, 0 -84, 123 -71, 4, -46 -35, -31, 16, -127, 4, 82 -82, -31, 16, -127, 4, 82, -1, -1, 48, 57, 123, 12, 21, 23, 1, 65, 1, -80, 32 -49, 48, 57, 0, 0, -44, 49 -8, 1 -52, 0, 0, 48, 57 -58, 0, 0, 48, 57 -10, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -14, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -13, 48, 57 -40, 57, 48, 21, -72, -113, 25, 0, 0, -91, 110, 29, 102 -31, 123 -50, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -64, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -1, 0, 0, 4, -46, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -74, 5, 102, 114, 105, 101, 110, 100, 32, 110, 97, 109, 101, 0 -53, 1, 2, 105, 116, 101, 109, 32, 97, 98, 121, 115, 115, 97, 108, 95, 119, 104, 105, 112, 32, 49, 0 -6, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -73, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -2, 0, -121, 1, -56, 0, 123 -37, 48, 57 -22, 48, 57, 21, 56, 26, -123, 127 -16, 26, 5, 48, -71, 56, 21, -1 -45, 48, 57, 21, -72, 1, 5, 26 -24, 127, 21, -72, -123, 26, 48, 57 -26, 26, -123, 21, -72, -1, 48, -71 -67, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 0, 115, 101, 97, 114, 99, 104, 0, 123 -32, 0, 0, 48, 57 -70, -34, -46, 4, 48, -71, 12, 0, 16, -31, 1, 91, 32, 1, -56, 0, 123 -72, 2, -114, 1, 65, 123, 0, -56, 1, 0, -116, 48, 57, 0, -107, 91, -96 -61, -116, 0, 0, 123, 1, -56, 57, 48, -127, 91, 32 -54, 91, -96, 82, 4, -56, 1, 123, 0, 16, 97, 127, 12, 0, 57, 48 -48, -116, 0, -46, 4, -96, 91, 123, 0, -56, 1, -1 -23, 0, 123, 1, -56, 91, -96, 0, 12 -59, 0, 123, 1, -56, 91, -96, 0, 12 -9, 0, 123, 1, -56, 91, -96, 0, 12 -15, 0, 123, 1, -56, 91, -96, 0, 12 -17, 0, 123, 1, -56, 91, -96, 0, 12 -39, 0, 123, 1, -56, 91, -96, 0, 12 -33, 0, 123, 1, -56, 91, -96, 0, 12 -60, 0, 123, 1, -56, 91, -96, 0, 12 -11, 0, 123, 1, -56, 91, -96, 0, 12 -42, 0, 123, 1, -56, 91, -96, 0, 12 -78, 0, 123, 1, -56, 21, 0, 1, 65, 2, -114, 91, -96, -116, 0, -71, 48 -69, 1, 0, 123, 2, 1, 65 -75, 123, -56, 21 -30, 0, 1, -30, 64 -55, 48, 57, 91, -96 -68, 48, 57 -63, 1, 57, 48 -29, -71, 48, -127 -5, 48, 57, 1 -62, 57, 48, -127 -65, -127, 57, 48 -46, 48, 57 -27, 127, 82, 4, -41, 17, 48, 57 -36, 87, 17, 4, 82, 127, -71, 48 -80, 17, 87, -71, 48, -46, 4, -127 -56, -127, 48, -71, 4, 82, -41, 17 -38, -41, 17, -127, 82, 4, 48, -71 -0, -25, 82, 4, -1 -12, 1, 4, -46 -79, 127, -46, 4 -44, 4, -46, -127 -81, 4, 82, 1 -51, 1, 4, 82 -57, 4, 82, -127 -18, 1, 4, 82 -20, 110, 97, 109, 101, 0, 7, -95, -18, -94, -52 -19, 110, 97, 109, 101, 0, 4, -46, 123 -41, 123, 12, 7, -95, -18, -94, -52 -3, 12, 4, -46, 123 -77, 123 -4, -47, 0, 0, 48, 57 -66, 110, 97, 109, 101, 0, 12, 123, 109, 101, 115, 115, 97, 103, 101, 0 -28, 48, 57 -7, 12, 1, 89, 2, -90, 9 -76, 82, 4, -31, 16 -43, 97, 32, 115, 116, 114, 105, 110, 103, 0 -84, 123 -71, 4, -46 -35, -31, 16, -127, 4, 82 -82, -31, 16, -127, 4, 82, -1, -1, 48, 57, 123, 12, 21, 23, 1, 65, 1, -80, 32 -49, 48, 57, 0, 0, -44, 49 -8, 1 -52, 0, 0, 48, 57 -58, 0, 0, 48, 57 -10, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -14, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -13, 48, 57 -40, 57, 48, 21, -72, -113, 25, 0, 0, -91, 110, 29, 102 -31, 123 -50, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -64, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -1, 0, 0, 4, -46, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -74, 5, 102, 114, 105, 101, 110, 100, 32, 110, 97, 109, 101, 0 -53, 1, 2, 105, 116, 101, 109, 32, 97, 98, 121, 115, 115, 97, 108, 95, 119, 104, 105, 112, 32, 49, 0 -6, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -73, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -2, 0, -121, 1, -56, 0, 123 -37, 48, 57 -22, 48, 57, 21, 56, 26, -123, 127 -16, 26, 5, 48, -71, 56, 21, -1 -45, 48, 57, 21, -72, 1, 5, 26 -24, 127, 21, -72, -123, 26, 48, 57 -26, 26, -123, 21, -72, -1, 48, -71 -67, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 0, 115, 101, 97, 114, 99, 104, 0, 123 -32, 0, 0, 48, 57 -70, -34, -46, 4, 48, -71, 12, 0, 16, -31, 1, 91, 32, 1, -56, 0, 123 -72, 2, -114, 1, 65, 123, 0, -56, 1, 0, -116, 48, 57, 0, -107, 91, -96 -61, -116, 0, 0, 123, 1, -56, 57, 48, -127, 91, 32 -54, 91, -96, 82, 4, -56, 1, 123, 0, 16, 97, 127, 12, 0, 57, 48 -48, -116, 0, -46, 4, -96, 91, 123, 0, -56, 1, -1 -23, 0, 123, 1, -56, 91, -96, 0, 12 -59, 0, 123, 1, -56, 91, -96, 0, 12 -9, 0, 123, 1, -56, 91, -96, 0, 12 -15, 0, 123, 1, -56, 91, -96, 0, 12 -17, 0, 123, 1, -56, 91, -96, 0, 12 -39, 0, 123, 1, -56, 91, -96, 0, 12 -33, 0, 123, 1, -56, 91, -96, 0, 12 -60, 0, 123, 1, -56, 91, -96, 0, 12 -11, 0, 123, 1, -56, 91, -96, 0, 12 -42, 0, 123, 1, -56, 91, -96, 0, 12 -78, 0, 123, 1, -56, 21, 0, 1, 65, 2, -114, 91, -96, -116, 0, -71, 48 -69, 1, 0, 123, 2, 1, 65 -75, 123, -56, 21 -30, 0, 1, -30, 64 -55, 48, 57, 91, -96 -68, 48, 57 -63, 1, 57, 48 -29, -71, 48, -127 -5, 48, 57, 1 -62, 57, 48, -127 -65, -127, 57, 48 -46, 48, 57 -27, 127, 82, 4, -41, 17, 48, 57 -36, 87, 17, 4, 82, 127, -71, 48 -80, 17, 87, -71, 48, -46, 4, -127 -56, -127, 48, -71, 4, 82, -41, 17 -38, -41, 17, -127, 82, 4, 48, -71 -0, -25, 82, 4, -1 -12, 1, 4, -46 -79, 127, -46, 4 -44, 4, -46, -127 -81, 4, 82, 1 -51, 1, 4, 82 -57, 4, 82, -127 -18, 1, 4, 82 -20, 110, 97, 109, 101, 0, 7, -95, -18, -94, -52 -19, 110, 97, 109, 101, 0, 4, -46, 123 -41, 123, 12, 7, -95, -18, -94, -52 -3, 12, 4, -46, 123 -77, 123 -4, -47, 0, 0, 48, 57 -66, 110, 97, 109, 101, 0, 12, 123, 109, 101, 115, 115, 97, 103, 101, 0 -28, 48, 57 -7, 12, 1, 89, 2, -90, 9 -76, 82, 4, -31, 16 -43, 97, 32, 115, 116, 114, 105, 110, 103, 0 -84, 123 -71, 4, -46 -35, -31, 16, -127, 4, 82 -82, -31, 16, -127, 4, 82, -1, -1, 48, 57, 123, 12, 21, 23, 1, 65, 1, -80, 32 -49, 48, 57, 0, 0, -44, 49 -8, 1 -52, 0, 0, 48, 57 -58, 0, 0, 48, 57 -10, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -14, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -13, 48, 57 -40, 57, 48, 21, -72, -113, 25, 0, 0, -91, 110, 29, 102 -31, 123 -50, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -64, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -1, 0, 0, 4, -46, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -74, 5, 102, 114, 105, 101, 110, 100, 32, 110, 97, 109, 101, 0 -53, 1, 2, 105, 116, 101, 109, 32, 97, 98, 121, 115, 115, 97, 108, 95, 119, 104, 105, 112, 32, 49, 0 -6, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -73, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -2, 0, -121, 1, -56, 0, 123 -37, 48, 57 -22, 48, 57, 21, 56, 26, -123, 127 -16, 26, 5, 48, -71, 56, 21, -1 -45, 48, 57, 21, -72, 1, 5, 26 -24, 127, 21, -72, -123, 26, 48, 57 -26, 26, -123, 21, -72, -1, 48, -71 -67, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 0, 115, 101, 97, 114, 99, 104, 0, 123 -32, 0, 0, 48, 57 -70, -34, -46, 4, 48, -71, 12, 0, 16, -31, 1, 91, 32, 1, -56, 0, 123 -72, 2, -114, 1, 65, 123, 0, -56, 1, 0, -116, 48, 57, 0, -107, 91, -96 -61, -116, 0, 0, 123, 1, -56, 57, 48, -127, 91, 32 -54, 91, -96, 82, 4, -56, 1, 123, 0, 16, 97, 127, 12, 0, 57, 48 -48, -116, 0, -46, 4, -96, 91, 123, 0, -56, 1, -1 -23, 0, 123, 1, -56, 91, -96, 0, 12 -59, 0, 123, 1, -56, 91, -96, 0, 12 -9, 0, 123, 1, -56, 91, -96, 0, 12 -15, 0, 123, 1, -56, 91, -96, 0, 12 -17, 0, 123, 1, -56, 91, -96, 0, 12 -39, 0, 123, 1, -56, 91, -96, 0, 12 -33, 0, 123, 1, -56, 91, -96, 0, 12 -60, 0, 123, 1, -56, 91, -96, 0, 12 -11, 0, 123, 1, -56, 91, -96, 0, 12 -42, 0, 123, 1, -56, 91, -96, 0, 12 -78, 0, 123, 1, -56, 21, 0, 1, 65, 2, -114, 91, -96, -116, 0, -71, 48 -69, 1, 0, 123, 2, 1, 65 -75, 123, -56, 21 -30, 0, 1, -30, 64 -55, 48, 57, 91, -96 -68, 48, 57 -63, 1, 57, 48 -29, -71, 48, -127 -5, 48, 57, 1 -62, 57, 48, -127 -65, -127, 57, 48 -46, 48, 57 -27, 127, 82, 4, -41, 17, 48, 57 -36, 87, 17, 4, 82, 127, -71, 48 -80, 17, 87, -71, 48, -46, 4, -127 -56, -127, 48, -71, 4, 82, -41, 17 -38, -41, 17, -127, 82, 4, 48, -71 -0, -25, 82, 4, -1 -12, 1, 4, -46 -79, 127, -46, 4 -44, 4, -46, -127 -81, 4, 82, 1 -51, 1, 4, 82 -57, 4, 82, -127 -18, 1, 4, 82 -20, 110, 97, 109, 101, 0, 7, -95, -18, -94, -52 -19, 110, 97, 109, 101, 0, 4, -46, 123 -41, 123, 12, 7, -95, -18, -94, -52 -3, 12, 4, -46, 123 -77, 123 -4, -47, 0, 0, 48, 57 -66, 110, 97, 109, 101, 0, 12, 123, 109, 101, 115, 115, 97, 103, 101, 0 -28, 48, 57 -7, 12, 1, 89, 2, -90, 9 -76, 82, 4, -31, 16 -43, 97, 32, 115, 116, 114, 105, 110, 103, 0 -84, 123 -71, 4, -46 -35, -31, 16, -127, 4, 82 -82, -31, 16, -127, 4, 82, -1, -1, 48, 57, 123, 12, 21, 23, 1, 65, 1, -80, 32 -49, 48, 57, 0, 0, -44, 49 -8, 1 -52, 0, 0, 48, 57 -58, 0, 0, 48, 57 -10, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -14, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -13, 48, 57 -40, 57, 48, 21, -72, -113, 25, 0, 0, -91, 110, 29, 102 -31, 123 -50, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -64, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -1, 0, 0, 4, -46, 99, 108, 97, 110, 32, 99, 104, 97, 116, 0 -74, 5, 102, 114, 105, 101, 110, 100, 32, 110, 97, 109, 101, 0 -53, 1, 2, 105, 116, 101, 109, 32, 97, 98, 121, 115, 115, 97, 108, 95, 119, 104, 105, 112, 32, 49, 0 -6, 102, 114, 105, 101, 110, 100, 115, 95, 110, 97, 109, 101, 0 -73, 105, 103, 110, 111, 114, 101, 95, 110, 97, 109, 101, 0 -2, 0, -121, 1, -56, 0, 123 -37, 48, 57 -22, 48, 57, 21, 56, 26, -123, 127 -16, 26, 5, 48, -71, 56, 21, -1 -45, 48, 57, 21, -72, 1, 5, 26 -24, 127, 21, -72, -123, 26, 48, 57 -26, 26, -123, 21, -72, -1, 48, -71 -67, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 0, 115, 101, 97, 114, 99, 104, 0, 123 -32, 0, 0, 48, 57 -70, -34, -46, 4, 48, -71, 12, 0, 16, -31, 1, 91, 32, 1, -56, 0, 123 -72, 2, -114, 1, 65, 123, 0, -56, 1, 0, -116, 48, 57, 0, -107, 91, -96 -61, -116, 0, 0, 123, 1, -56, 57, 48, -127, 91, 32 -54, 91, -96, 82, 4, -56, 1, 123, 0, 16, 97, 127, 12, 0, 57, 48 -48, -116, 0, -46, 4, -96, 91, 123, 0, -56, 1, -1 -23, 0, 123, 1, -56, 91, -96, 0, 12 -59, 0, 123, 1, -56, 91, -96, 0, 12 -9, 0, 123, 1, -56, 91, -96, 0, 12 -15, 0, 123, 1, -56, 91, -96, 0, 12 -17, 0, 123, 1, -56, 91, -96, 0, 12 -39, 0, 123, 1, -56, 91, -96, 0, 12 -33, 0, 123, 1, -56, 91, -96, 0, 12 -60, 0, 123, 1, -56, 91, -96, 0, 12 -11, 0, 123, 1, -56, 91, -96, 0, 12 -42, 0, 123, 1, -56, 91, -96, 0, 12 -78, 0, 123, 1, -56, 21, 0, 1, 65, 2, -114, 91, -96, -116, 0, -71, 48 -69, 1, 0, 123, 2, 1, 65 -75, 123, -56, 21 -30, 0, 1, -30, 64 -55, 48, 57, 91, -96 -68, 48, 57 -63, 1, 57, 48 -29, -71, 48, -127 -5, 48, 57, 1 -62, 57, 48, -127 -65, -127, 57, 48 +65, 48, 57, 0 46, 48, 57 27, 127, 82, 4, -41, 17, 48, 57 36, 87, 17, 4, 82, 127, -71, 48 diff --git a/tools/src/main/kotlin/world/gregs/voidps/tools/NPCDefinitions.kt b/tools/src/main/kotlin/world/gregs/voidps/tools/NPCDefinitions.kt index 4aef44882..186413058 100644 --- a/tools/src/main/kotlin/world/gregs/voidps/tools/NPCDefinitions.kt +++ b/tools/src/main/kotlin/world/gregs/voidps/tools/NPCDefinitions.kt @@ -21,11 +21,8 @@ object NPCDefinitions { val decoder = NPCDefinitions(definitions).load(yaml, property("npcDefinitionsPath")) for (i in decoder.definitions.indices) { val def = decoder.getOrNull(i) ?: continue - if (def.transforms?.contains(171) == true || def.transforms?.contains(4610) == true) { - println("$i ${def.name} ${def.transforms?.toList()}") - } - if (def.name.contains("brimstail", ignoreCase = true)) { - println("$i ${def.name} ${def.extras} ${def.varp} ${def.varbit}") + if (def.name.contains("diango", ignoreCase = true)) { + println("$i ${def.name} ${def.extras} ${def.transforms?.contentToString()} ${def.options.contentDeepToString()}") } } }