def scroll_commands(page_size=4): import df_utils return { "scroll up [<positive_num>]": df_utils.async_action(scroll_up, 'positive_num'), "scroll down [<positive_num>]": df_utils.async_action(scroll_down, 'positive_num'), "page up [<positive_num>]": df_utils.AsyncFunction( scroll_up, format_args=lambda **kw: [kw['positive_num'] * page_size]), "page down [<positive_num>]": df_utils.AsyncFunction( scroll_down, format_args=lambda **kw: [kw['positive_num'] * page_size]), }
def simple_click(*fields): import df_utils async def to_call(menu, field_list): for field in field_list: cmp = menu.get(field) if cmp: await click_component(cmp) return return df_utils.async_action(to_call, fields)
def inventory_commands(): import df_utils inventory_wrapper = InventoryMenuWrapper() async def inventory_focus(menu, new_row, new_col): inventory = menu['inventory'] await inventory_wrapper.focus_box(inventory, new_row, new_col) async def click_button(menu, name): await click_component(menu[name]) commands = { "item <positive_index>": df_utils.async_action(inventory_focus, None, 'positive_index'), "row <positive_index>": df_utils.async_action(inventory_focus, 'positive_index', None), "ok": df_utils.async_action(click_button, "okButton"), "trash can": df_utils.async_action(click_button, "trashCan"), } return commands
async def buy_item_index(menu, idx: int): buttons = menu["forSaleButtons"] await menu_utils.focus_component(buttons[idx]) async def buy_item(menu, n: int): await server.mouse_click(count=n) async def click_range(menu, start, end): await inventory_wrapper.click_range(menu["inventory"], start, end) mapping = { "sell <positive_index> [through <positive_index2>]": df_utils.async_action(click_range, "positive_index", "positive_index2"), "item <positive_index>": df_utils.async_action(focus_item, "positive_index", "item"), "row <positive_index>": df_utils.async_action(focus_item, "positive_index", "row"), "(shop | for sale)": df_utils.async_action(focus_menu_section, "forSale"), "backpack | (player items)": df_utils.async_action(focus_menu_section, "inventory"), "buy [<positive_num>]": df_utils.async_action(buy_item, "positive_num"), **menu_utils.scroll_commands(), } def load_grammar():
if menu["currentTab"] == "HOST_TAB": button_index = game_idx + 1 # skip "host new farm" slot try: btn = menu["slotButtons"][button_index] except IndexError: return await menu_utils.click_component(btn) mapping = { "host": menu_utils.simple_click("hostTab"), "join": menu_utils.simple_click("joinTab"), "host new farm": df_utils.async_action(host_new_farm), "join lan game": df_utils.async_action(join_lan_game), "refresh": menu_utils.simple_click("refreshButton"), "[host | load] (farm | game) <positive_index>": df_utils.async_action(load_game, "positive_index"), "[go] back": menu_utils.simple_click("backButton"), } def load_grammar(): extras = [rules.num, df_utils.positive_index, df_utils.positive_num] defaults = {"positive_num": 1} grammar = menu_utils.build_menu_grammar(mapping,
async def buy_animal(menu, animal_index: str): await menu_utils.click_component(menu["animalsToPurchase"][0]) mapping = { "ok": menu_utils.simple_click("doneNamingButton"), "cancel": menu_utils.simple_click( "okButton"), # strange but using existing field names "random": menu_utils.simple_click("randomButton"), "(buy | purchase) <animals>": df_utils.async_action(buy_animal, "animals"), "pan <direction_keys>": objective.objective_action(objective.HoldKeyObjective, "direction_keys"), } def load_grammar(): extras = [ df.Choice("direction_keys", game.direction_keys), rules.num, df_utils.positive_index, df_utils.positive_num, df.Choice("animals", animals), ] defaults = {"positive_num": 1} grammar = menu_utils.build_menu_grammar(mapping,
async def click_equipment_icon(page, item): cmp = menu_utils.find_component_by_field(page['equipmentIcons'], 'name', item["name"]) await menu_utils.focus_component(cmp) with server.player_items_stream() as stream: player_items = await stream.next() if player_items['cursorSlotItem'] and not player_items['equippedItems'][ item['field']]: await menu_utils.click_component(cmp) else: await menu_utils.focus_component(cmp) mapping = { "item <positive_index>": df_utils.async_action(focus_item, None, 'positive_index'), "row <positive_index>": df_utils.async_action(focus_item, 'positive_index', None), "trash can": menu_utils.simple_click("trashCan"), "<equipment_icons>": df_utils.async_action(click_equipment_icon, 'equipment_icons'), } equipment_icons = { "boots": { "name": "Boots", "field": "boots" }, "hat": { "name": "Hat",
async def click_button(name): menu = await get_carpenter_menu() await menu_utils.click_component(menu[name]) async def move_cursor_tile(direction, amount): await game.move_mouse_in_direction(direction, amount * 64) mapping = { "pan <direction_keys>": objective.objective_action(objective.HoldKeyObjective, "direction_keys"), "previous": df_utils.async_action(click_button, "backButton"), "cancel": df_utils.async_action(click_button, "cancelButton"), "demolish [buildings]": df_utils.async_action(click_button, "demolishButton"), "next": df_utils.async_action(click_button, "forwardButton"), "move [buildings]": df_utils.async_action(click_button, "moveButton"), "build": df_utils.async_action(click_button, "okButton"), "paint": df_utils.async_action(click_button, "paintButton"), "upgrade": df_utils.async_action(click_button, "upgradeIcon"), }
import title_menu, menu_utils, server, df_utils, game, container_menu, objective, server, constants BILLBOARD = 'billboard' async def get_billboard_menu(): return await menu_utils.get_active_menu(BILLBOARD) async def click_button(name): menu = await get_billboard_menu() await menu_utils.click_component(menu[name]) mapping = { "accept quest": df_utils.async_action(click_button, "acceptQuestButton"), } @menu_utils.valid_menu_test def is_active(): game.get_context_menu(BILLBOARD) def load_grammar(): grammar = df.Grammar("billboard_menu") main_rule = df.MappingRule( name="billboard_menu_rule", mapping=mapping, extras=[ df.Choice("direction_keys", game.direction_keys),
async def get_shipping_menu(): menu = await menu_utils.get_active_menu(menu_type='itemsToGrabMenu') if not menu['shippingBin']: raise menu_utils.InvalidMenuOption() return menu async def focus_item(new_row, new_col): menu = await get_shipping_menu() submenu = menu['inventoryMenu'] await wrapper.focus_box(submenu, new_row, new_col) mapping = { "item <positive_index>": df_utils.async_action(focus_item, None, 'positive_index'), "row <positive_index>": df_utils.async_action(focus_item, 'positive_index', None), "ok": df_utils.async_action(menu_utils.click_menu_button, 'okButton', get_shipping_menu), "undo": df_utils.async_action(menu_utils.click_menu_button, 'lastShippedHolder', get_shipping_menu), } @menu_utils.valid_menu_test def is_active(): menu = game.get_context_menu('itemsToGrabMenu') return menu['shippingBin']
import dragonfly as df import functools from srabuilder import rules import characters, locations, fishing_menu, title_menu, menu_utils, server, df_utils, game, container_menu, objective, constants, items async def click_skip_btn(): evt = game.get_context_value('GAME_EVENT') if 'skipBounds' in evt: await menu_utils.click_component(evt['skipBounds']) mapping = { "skip [cutscene | event]": df_utils.async_action(click_skip_btn), } def is_active(): evt = game.get_context_value('GAME_EVENT') return evt is not None and evt['skippable'] def load_grammar(): grammar = df.Grammar("cutscene") main_rule = df.MappingRule( name="cutscene_rule", mapping=mapping, context=df.FuncContext(is_active), ) grammar.add_rule(main_rule) grammar.load()
await menu_utils.focus_component(current_position) def sort_fn(current_cmp, direction_index, multiplier, cmp): center = cmp["center"] current_center = current_cmp["center"] val, target_val = current_center[direction_index], center[direction_index] direction_diff = (target_val - val) * multiplier side_index = 0 if direction_index == 1 else 1 side_diff = abs(current_center[side_index] - center[side_index]) right_direction = 0 if direction_diff > 0 else 1 return (right_direction, 0.1 * direction_diff + 0.9 * side_diff) mapping = { "<direction_nums> [<positive_num>]": df_utils.async_action( move_cursor_to_next_component, "direction_nums", "positive_num" ), } def load_grammar(): extras = [ rules.num, df_utils.positive_index, df_utils.positive_num, df.Choice("direction_nums", game.direction_nums), ] grammar = menu_utils.build_menu_grammar(mapping, validate_any_menu, extras=extras) grammar.load()
mouse_directions = { "up": constants.NORTH, "right": constants.EAST, "down": constants.SOUTH, "left": constants.WEST, } async def move_mouse_by_tile(direction, n): await game.move_mouse_in_direction(direction, n * 64) non_repeat_mapping = { "click [<positive_num>]": df_utils.async_action(server.mouse_click, "left", "positive_num"), "right click [<positive_num>]": df_utils.async_action(server.mouse_click, "right", "positive_num"), "mouse <mouse_directions> [<positive_num>]": df_utils.async_action(move_mouse_by_tile, "mouse_directions", "positive_num"), "small mouse <mouse_directions> [<positive_num>]": df_utils.async_action(game.move_mouse_in_direction, "mouse_directions", "positive_num"), "write game state": df_utils.async_action(game.write_game_state), "(action | check)": df_utils.async_action(game.press_key, constants.ACTION_BUTTON), "(escape | [open | close] menu)": df_utils.async_action(game.press_key, constants.MENU_BUTTON), "hold mouse":
async def click_main_button(menu, btn_name: str): button = menu_utils.find_component_by_field(menu['buttons'], 'name', btn_name) await menu_utils.click_component(button) def get_submenu(tm, menu_type): menu_utils.validate_menu_type(TITLE_MENU, tm) submenu = tm.get('subMenu') menu_utils.validate_menu_type(menu_type, submenu) return submenu mapping = { "<main_buttons> [game]": df_utils.async_action(click_main_button, 'main_buttons'), "[change | select] (language | languages)": menu_utils.simple_click('languageButton'), "about": menu_utils.simple_click('aboutButton'), } def load_grammar(): grammar = menu_utils.build_menu_grammar( mapping, get_title_menu, extras=[main_button_choice], defaults={'positive_num': 1}, ) grammar.load()
cmp = menu_utils.find_component_by_field(menu["tabs"], 'name', tab_name) await menu_utils.click_component(cmp) tabs = { "inventory": "inventory", "skills": "skills", "social": "social", "map": "map", "crafting": "crafting", "collections": "collections", "options": "options", "exit [game]": "exit", } mapping = { "<tabs>": df_utils.async_action(click_tab, 'tabs'), } @menu_utils.valid_menu_test def is_active(): game.get_context_menu('gameMenu') def load_grammar(): grammar = df.Grammar("game_menu") main_rule = df.MappingRule( name="game_menu_rule", mapping=mapping, extras=[ df.Choice("tabs", tabs), df_utils.positive_num, ],
def get_collections_page(menu): from game_menu import game_menu menu_utils.validate_menu_type("gameMenu", menu) page = game_menu.get_page_by_name(menu, "collectionsPage") return page async def click_side_tab(menu, idx: int): cmp = menu["tabs"][idx] await menu_utils.click_component(cmp) mapping = { "<tabs>": df_utils.async_action(click_side_tab, "tabs"), "previous": menu_utils.simple_click("backButton"), "next": menu_utils.simple_click("forwardButton"), } def get_grammar(): extras = [ df_utils.positive_num, df_utils.positive_index, tabs, ] grammar = menu_utils.build_menu_grammar(mapping, get_collections_page, extras=extras) return grammar
"(wood | twigs)": constants.TWIG, "weeds": constants.WEEDS, "debris": "debris", } mapping = { "<direction_keys>": objective.objective_action(objective.HoldKeyObjective, "direction_keys"), "<direction_nums> <n>": objective.objective_action(objective.MoveNTilesObjective, "direction_nums", "n"), "start swinging [tool]": objective.objective_action(objective.HoldKeyObjective, constants.USE_TOOL_BUTTON), "[equip] item <positive_index>": df_utils.async_action(game.equip_item_by_index, "positive_index"), "equip [melee] weapon": df_utils.async_action(game.equip_melee_weapon), "equip <items>": df_utils.async_action(game.equip_item_by_name, "items"), "nearest <items> [<positive_index>]": objective.function_objective(go_to_object, "items", "positive_index"), "jump <direction_nums> [<positive_num>]": df_utils.async_action(move_and_face_previous_direction, "direction_nums", "positive_num"), "go to bed": objective.function_objective(go_to_bed), "go to shipping bin": objective.function_objective(go_to_shipping_bin), "start shopping": objective.function_objective(objective.start_shopping),
'containsMouse'] else 'inventoryMenu' submenu = menu[submenu_name] submenu_wrapper = item_grab[submenu_name] await submenu_wrapper.focus_box(submenu, new_row, new_col) async def click_range(start, end): menu = await get_container_menu() submenu = menu['inventoryMenu'] submenu_wrapper = item_grab['inventoryMenu'] await submenu_wrapper.click_range(submenu, start, end) mapping = { "deposit <positive_index>": df_utils.async_action(click_range, "positive_index", None), "deposit <positive_index> through <positive_index2>": df_utils.async_action(click_range, "positive_index", 'positive_index2'), "item <positive_index>": df_utils.async_action(focus_item, None, 'positive_index'), "row <positive_index>": df_utils.async_action(focus_item, 'positive_index', None), "backpack": df_utils.async_action(set_item_grab_submenu, 'inventoryMenu'), "container": df_utils.async_action(set_item_grab_submenu, 'itemsToGrabMenu'), "ok": df_utils.async_action(click_button, 'okButton'), "(trash | garbage) can": df_utils.async_action(click_button, 'trashCan'), "[add to] existing stacks":
from game_menu import game_menu menu_utils.validate_menu_type("gameMenu", menu) page = game_menu.get_page_by_name(menu, "socialPage") return page async def click_npc(menu, name: str): index = menu["names"].index(name) - menu["slotPosition"] if 0 <= index < PAGE_SIZE: await menu_utils.click_component(menu["characterSlots"][index]) mapping = { **menu_utils.scroll_commands(page_size=PAGE_SIZE), "<npcs>": df_utils.async_action(click_npc, "npcs") } def get_grammar(): extras = [ df_utils.positive_num, df.Choice("npcs", characters.npcs), df_utils.positive_index, df_utils.dictation_rule(), ] grammar = menu_utils.build_menu_grammar(mapping, get_social_page, extras=extras) return grammar
button_index = game_idx try: btn = menu["deleteButtons"][button_index] except IndexError: return await menu_utils.click_component(btn) mapping = { "[go] back": menu_utils.simple_click("backButton"), "(yes | ok)": menu_utils.simple_click("okDeleteButton"), "(no | cancel)": menu_utils.simple_click("cancelDeleteButton"), "(load [game] | [load] game) <positive_index>": df_utils.async_action(load_game, "positive_index"), "delete [game] <positive_index>": df_utils.async_action(delete_game, "positive_index"), **menu_utils.scroll_commands(), } def load_grammar(): grammar = menu_utils.build_menu_grammar( mapping, validate_load_game_menu, extras=[df_utils.positive_index, df_utils.positive_num], ) grammar.load()
page = game_menu.get_page_by_name(menu, "skillsPage") return page async def focus_item_dictation(page, text): cmp = approximate_matching.match_component(text, page["specialItems"], "hoverText") await menu_utils.focus_component(cmp) async def focus_skill(page, index): cmp = page["skillAreas"][index] await menu_utils.focus_component(cmp) mapping = { "<skills>": df_utils.async_action(focus_skill, "skills"), "<dictation>": df_utils.async_action(focus_item_dictation, "dictation"), } def load_grammar(): extras = [df_utils.dictation_rule(), df.Choice("skills", skills)] grammar = menu_utils.build_menu_grammar(mapping, get_inventory_page, extras=extras) grammar.load() # { # "xPositionOnScreen": 413, # "yPositionOnScreen": 140, # "upperRightCloseButton": null, # "containsMouse": true,
if top_index is not None: await menu_utils.click_component(menu['responseCC'][top_index]) async def get_dialogue_menu(): return await menu_utils.get_active_menu(DIALOGUE_BOX) async def focus_item(idx): menu = await get_dialogue_menu() await menu_utils.click_component(menu['responseCC'][idx]) mapping = { "(item | response) <positive_index>": df_utils.async_action(focus_item, 'positive_index'), "<dictation>": df_utils.async_action(do_dictation, 'dictation') } @menu_utils.valid_menu_test def is_active(): game.get_context_menu(DIALOGUE_BOX) def load_grammar(): grammar = df.Grammar("dialogue_menu") main_rule = df.MappingRule( name="dialogue_menu_rule", mapping=mapping,
"direction": "Direction", "hair": "Hair", "pants": "Pants Style", "(pet | animal) [preference]": "Pet", "shirt": "Shirt", "skin": "Skin", "(wallets | money style)": "Wallets", "(difficulty | profit margin)": "Difficulty", "[starting] cabins": "Cabins", } mapping = { "name": menu_utils.simple_click("nameBoxCC"), "((nearby | close) cabin layout | cabin layout (nearby | close))": df_utils.async_action(click_cabin_layout, 0), "(separate cabin layout | cabin layout separate)": df_utils.async_action(click_cabin_layout, 1), "farm name": menu_utils.simple_click("farmnameBoxCC"), "favorite thing": menu_utils.simple_click("favThingBoxCC"), "(random | [roll] dice)": menu_utils.simple_click("randomButton"), "(ok [button] | start game)": menu_utils.simple_click("okButton"), "skip (intro | introduction)": menu_utils.simple_click("skipIntroButton"), "help": menu_utils.simple_click("coopHelpButton"), "next":
import dragonfly as df from srabuilder import rules import menu_utils, server, df_utils, game, objective, server, constants LEVEL_UP_MENU = 'shippingMenu' categories_list = ('farming', 'foraging', 'fishing', 'mining', 'other') categories = {category: i for i, category in enumerate(categories_list)} async def click_category(menu, idx: int): cmp = menu['categories'][idx] if cmp['visible']: await menu_utils.click_component(cmp) mapping = { "ok": menu_utils.simple_click("okButton"), '<category>': df_utils.async_action(click_category, 'category'), "(back | previous)": menu_utils.simple_click("backButton"), "(forward | next)": menu_utils.simple_click("forwardButton"), } def load_grammar(): grammar = menu_utils.build_menu_grammar(mapping, LEVEL_UP_MENU, extras=[df.Choice('category', categories)]) grammar.load()
"(seventy | seven) five": 75, "(eighty | eight zero)": 80, "(eighty | eight) five": 85, "(ninety | nine zero)": 90, "(ninety | nine) five": 95, "one (hundred | zero zero)": 100, "one (hundred [and] | (oh | zero)) five": 105, "one [hundred [and]] (ten | one zero)": 110, "one [hundred [and]] (fifteen | one five)": 115, "one [hundred [and]] (twenty | too zero)": 120, } async def select_floor(menu, floor: int): floor_index = floor // 5 await menu_utils.click_component(menu['elevators'][floor_index]) mapping = { "[floor | level] <mine_elevator_floors>": df_utils.async_action(select_floor, 'mine_elevator_floors'), } def load_grammar(): extras = [df.Choice("mine_elevator_floors", floors_map)] grammar = menu_utils.build_menu_grammar(mapping, MINE_ELEVATOR_MENU, extras=extras) grammar.load()
async def start_fishing(): async with server.player_status_stream() as stream: await game.equip_item_by_name(constants.FISHING_ROD) async with server.tool_status_stream() as tss: await cast_fishing_rod(tss) await wait_for_nibble(tss) async def cast_fishing_rod(tss): async with game.press_and_release(constants.USE_TOOL_BUTTON): await tss.wait( lambda t: t['isTimingCast'] and t['castingPower'] > 0.95, timeout=10) async def wait_for_nibble(tss): tool_status = await tss.wait(lambda t: t['isNibbling'] or not t['inUse']) if tool_status['inUse']: await game.press_key(constants.USE_TOOL_BUTTON) await tss.wait(lambda t: t['isReeling']) mapping = {"catch fish": df_utils.async_action(catch_fish)} def load_grammar(): grammar = menu_utils.build_menu_grammar(mapping, FISHING_MENU) grammar.load()
async def focus_quest(menu, n): quest = menu["questLogButtons"][n] await menu_utils.click_component(quest) mapping = { "previous": menu_utils.simple_click("backButton"), "next": menu_utils.simple_click("forwardButton"), "cancel [quest]": menu_utils.simple_click("cancelQuestButton"), "scroll up": menu_utils.simple_click("upArrow"), "scroll down": menu_utils.simple_click("downArrow"), "[collect] (reward | rewards)": menu_utils.simple_click("rewardBox"), "(item | quest) <positive_index>": df_utils.async_action(focus_quest, "positive_index"), } def load_grammar(): extras = [df_utils.positive_index] grammar = menu_utils.build_menu_grammar(mapping, QUEST_LOG_MENU, extras=extras) grammar.load()
await menu_utils.focus_component(cmp) return True return False async def focus_item_dictation(page, text): items_on_page = [x[1]["name"] for x in page["currentRecipePage"]] best_idx = approximate_matching.do_match(str(text), items_on_page) if best_idx is not None: cmp = page["currentRecipePage"][best_idx][0] await menu_utils.focus_component(cmp) mapping = { "<craftable_items>": df_utils.async_action(focus_item, "craftable_items"), "scroll up [<positive_num>]": df_utils.async_action(menu_utils.scroll_up, "positive_num"), "scroll down [<positive_num>]": df_utils.async_action(menu_utils.scroll_down, "positive_num"), **menu_utils.inventory_commands(), "<dictation>": df_utils.async_action(focus_item_dictation, "dictation"), } def load_grammar(): grammar = df.Grammar("crafting_page") extras = [ df_utils.positive_num, df_utils.positive_index,