gameboy_worlds.emulation.harry_potter.parsers

  1import os
  2import numpy as np
  3from gameboy_worlds.utils import verify_parameters, log_error
  4from gameboy_worlds.emulation.parser import StateParser, NamedScreenRegion
  5
  6
  7class _BaseHarryPotterParser(StateParser):
  8    """
  9    Minimal parser scaffold for Harry Potter variants.
 10
 11    This only configures rom_data_path so the base StateParser can run.
 12    Includes dialogue detection methods used by HarryPotterOCRMetric.
 13    """
 14
 15    VARIANT = ""
 16    REGIONS = []
 17    MULTI_TARGET_REGIONS = []
 18    MULTI_TARGETS = {}
 19
 20    def __init__(self, pyboy, parameters):
 21        verify_parameters(parameters)
 22        variant = self.VARIANT
 23        if f"{variant}_rom_data_path" not in parameters:
 24            log_error(
 25                f"ROM data path not found for variant: {variant}. Add {variant}_rom_data_path to config files.",
 26                parameters,
 27            )
 28        self.rom_data_path = parameters[f"{variant}_rom_data_path"]
 29        captures_dir = os.path.join(self.rom_data_path, "captures")
 30        named_screen_regions = []
 31        for region_name, x, y, w, h in self.REGIONS:
 32            region = NamedScreenRegion(
 33                region_name,
 34                x,
 35                y,
 36                w,
 37                h,
 38                parameters=parameters,
 39                target_path=os.path.join(captures_dir, region_name),
 40            )
 41            named_screen_regions.append(region)
 42        for region_name, x, y, w, h in self.MULTI_TARGET_REGIONS:
 43            target_names = self.MULTI_TARGETS.get(region_name, [])
 44            multi_target_paths = {
 45                t: os.path.join(captures_dir, region_name, t)
 46                for t in target_names
 47            }
 48            region = NamedScreenRegion(
 49                region_name,
 50                x,
 51                y,
 52                w,
 53                h,
 54                parameters=parameters,
 55                multi_target_paths=multi_target_paths if multi_target_paths else None,
 56            )
 57            named_screen_regions.append(region)
 58        super().__init__(pyboy, parameters, named_screen_regions)
 59
 60    def __repr__(self) -> str:
 61        return f"{self.__class__.__name__}(variant={self.VARIANT})"
 62
 63    # -- Dialogue detection methods (used by HarryPotterOCRMetric) --
 64    # These require "dialogue_box_full" (MULTI_TARGET_REGIONS) to be defined
 65    # in the child parser. No separate indicator region needed — detection
 66    # works by analyzing the dialogue area content directly.
 67
 68    def _dialogue_box_content_ratio(self, current_screen: np.ndarray) -> float:
 69        """Returns the fraction of non-white pixels in the dialogue box area."""
 70        box = self.capture_named_region(
 71            current_frame=current_screen, name="dialogue_box_full"
 72        )
 73        return float(np.mean(box < 255))
 74
 75    def dialogue_box_open(self, current_screen: np.ndarray) -> bool:
 76        """
 77        Checks if a dialogue box is currently displayed by analyzing pixel
 78        content in the dialogue_box_full region. If enough non-white pixels
 79        are present, dialogue is considered active.
 80        """
 81        return self._dialogue_box_content_ratio(current_screen) >= 0.08
 82
 83    def dialogue_box_empty(self, current_screen: np.ndarray) -> bool:
 84        """
 85        Checks if the dialogue box area contains no meaningful text.
 86        """
 87        return self._dialogue_box_content_ratio(current_screen) < 0.08
 88
 89    def is_in_dialogue(self, current_screen: np.ndarray) -> bool:
 90        """Checks if the player is actively reading dialogue text."""
 91        return self.dialogue_box_open(current_screen)
 92
 93
 94class HarryPotterChamberOfSecretsParser(_BaseHarryPotterParser):
 95    VARIANT = "harry_potter_chamber_of_secrets"
 96    DIALOGUE_BOX_REGION = (0, 112, 155, 7)
 97    """Shared CoS dialogue box coordinates in (x, y, width, height) form."""
 98
 99    REGIONS = []
100
101    MULTI_TARGET_REGIONS = [
102        ("dialogue_box_full", *DIALOGUE_BOX_REGION),
103        ("dobby_bed_area", 96, 71, 40, 48),
104        ("dobby_dialogue_area", *DIALOGUE_BOX_REGION),
105        ("choose_deck_cos_area", 41, 95, 78, 9),
106        ("talk_to_ron_cos_area", *DIALOGUE_BOX_REGION),
107        ("flying_car_cutscene_area", 0, 0, 158, 56),
108        ("burrow_arrival_dialogue_area", *DIALOGUE_BOX_REGION),
109        ("mrs_weasley_dialogue_area", *DIALOGUE_BOX_REGION),
110        ("battle_menu_cos_area", 102, 120, 57, 23),
111        # -- Burrow room navigation tasks --
112        ("percy_room_area", 16, 0, 52, 80),         # termination: inside_percy_room
113        ("ginny_room_area", 74, 0, 36, 57),         # termination: inside_ginny_room
114        ("parents_room_area", 97, 0, 60, 65),       # termination: inside_parents_room
115        ("fred_george_room_area", 16, 32, 16, 84),  # termination: inside_fred_george_room
116        ("rons_room_area", 137, 0, 22, 71),         # termination: inside_rons_room
117        # -- Burrow kitchen / garden quest tasks --
118        ("garden_door_area", 80, 24, 10, 8),        # subgoal: outside_garden_door
119        ("car_area", 80, 65, 55, 70),
120    ]
121
122    MULTI_TARGETS = {
123        "dobby_bed_area": [
124            "find_dobby",
125        ],
126        "dialogue_box_full": [
127            "talk_to_ron_burrow",
128            "talk_to_mom_kitchen",
129            "talk_to_ron_garden",
130        ],
131        "dobby_dialogue_area": [
132            "dobby_dialogue_started",
133        ],
134        "choose_deck_cos_area": [
135            "deck_selected_cos",
136        ],
137        "talk_to_ron_cos_area": [
138            "talk_to_ron",
139        ],
140        "flying_car_cutscene_area": [
141            "flying_car_departure",
142        ],
143        "burrow_arrival_dialogue_area": [
144            "outside_burrow_after_cutscene",
145        ],
146        "mrs_weasley_dialogue_area": [
147            "mrs_weasley_table_dialogue",
148        ],
149        "battle_menu_cos_area": [
150            "in_battle_cos",
151        ],
152        # -- Burrow room navigation tasks --
153        "percy_room_area": [
154            "inside_percy_room",
155        ],
156        "ginny_room_area": [
157            "inside_ginny_room",
158        ],
159        "parents_room_area": [
160            "inside_parents_room",
161        ],
162        "fred_george_room_area": [
163            "inside_fred_george_room",
164        ],
165        "rons_room_area": [
166            "inside_rons_room",
167        ],
168        "garden_door_area": [
169            "outside_garden_door",
170        ],
171        "car_area": ["next_to_car"],
172    }
173
174
175class HarryPotterPhilosophersStoneParser(_BaseHarryPotterParser):
176    VARIANT = "harry_potter_philosophers_stone"
177    DIALOGUE_BOX_REGION = (0, 112, 158, 8)
178    """Shared PS dialogue box coordinates in (x, y, width, height) form."""
179
180    REGIONS = [
181        ("potions_shop_shelf", 7, 26, 105, 21),
182    ]
183
184    MULTI_TARGET_REGIONS = [
185        ("dialogue_box_full", *DIALOGUE_BOX_REGION),
186        ("ollivanders_area", 80, 16, 63, 40),
187        ("ollivanders_entrance", 70, 21, 23, 21),
188        ("wand_dialogue_area", 19, 43, 31, 46),
189        ("wand_received_text", 7, 80, 144, 8),
190        ("folio_boy_area", 0, 63, 105, 54),
191        ("choose_deck_text", 42, 86, 77, 10),
192        ("deck_reward_icon", 68, 129, 16, 14),
193        ("gringotts_entrance", 65, 3, 30, 11),
194        ("gringotts_interior_area", 62, 112, 31, 15),
195        ("hagrid_gringotts_area", 49, 33, 31, 21),
196        ("vault_interior", 0, 49, 117, 69),
197        ("level_up_text", 33, 47, 94, 9),
198        ("boss_rat_area", 44, 40, 12, 15),
199        ("spell_level_text", 34, 48, 92, 16),
200        ("battle_reward_bar", 39, 25, 77, 6),
201        # -- Task 14: find_hagrid_vault_test --
202        # The subgoal uses the Hagrid dialogue box screen state rather than
203        # Hagrid's sprite, since dialogue is more stable than character art.
204        ("post_boss_hagrid_area", 31, 111, 129, 10),   # subgoal: navigate_to_hagrid (capture the Hagrid dialogue box state)
205        ("vault_entry_cutscene_area", 55, 32, 75, 39), # termination: vault_entry_cutscene
206        # -- Madam Malkin split-task assets --
207        ("outside_malkins_area", 19, 4, 21, 17),       # subgoal: outside_malkins
208        ("inside_malkins_area", 121, 29, 16, 16),      # termination: inside_malkins
209        ("robes_menu_area", 0, 0, 143, 29),            # termination: malkins_buy_menu_open
210        ("robes_purchase_area", 31, 25, 80, 6),        # confirmation prompt: confirm_robes_purchase
211        # -- Flourish & Blotts split-task assets --
212        ("outside_flourish_blotts_area", 93, 21, 21, 19),  # subgoal: outside_flourish_blotts
213        ("inside_flourish_blotts_area", 54, 16, 91, 49),   # termination: inside_flourish_blotts
214        ("books_received_area", 45, 110, 68, 32),          # termination: books_received
215        # -- Apothecary split-task assets --
216        ("outside_apothecary_area", 95, 31, 20, 18),    # subgoal: outside_apothecary
217        ("inside_apothecary_area", 94, 14, 49, 20),     # termination: inside_apothecary
218        ("apothecary_menu_area", 0, 0, 157, 30),    # terminations: apothecary_buy_menu_open, selected_apothecary_item
219        ("apothecary_purchase_area", 16, 0, 131, 86),   # termination: confirm_apothecary_purchase
220        # -- Cauldron shop assets --
221        ("outside_cauldron_shop_area", 57, 20, 22, 20),     # subgoal: outside_cauldron_shop
222        ("inside_cauldron_shop_area", 17, 2, 54, 20),      # termination: inside_cauldron_shop
223        ("cauldron_menu_area", 0, 0, 115, 32),          # subgoal: cauldron_buy_menu_open
224        ("cauldron_purchase_area", 31, 24, 78, 7),      # termination: confirm_cauldron_purchase
225        # -- Sugarplums Sweets filler tasks --
226        ("outside_sugarplums_area", 55, 22, 22, 20),    # subgoal: outside_sugarplums
227        ("inside_sugarplums_area", 25, 30, 75, 35),     # termination: inside_sugarplums
228        ("sugarplums_menu_area", 0, 0, 130, 30),        # termination: sugarplums_buy_menu_open
229        ("find_location", 0, 100, 160, 44),
230        ("menu", 0, 0, 90, 120),
231        ("last_item", 0, 105, 160, 30),
232        ("item_consumption", 0, 30, 160, 110),
233        ("equip_screen", 0, 25, 160, 119),
234        ("rat_king_sprite_area", 0, 0, 60, 100),
235        ("full_screen_area", 0, 0, 160, 144),
236        ("mp_points_area", 60, 120, 60, 10),
237        ("large_dialogue_box", 0, 112, 160, 32),
238        ("chocolate_frogs_5_inventory_area", 0, 60, 160, 20),
239        ("leftmost_train_car", 0, 0, 90, 90),
240        ("rightmost_train_car", 75, 0, 85, 90),
241        ("boat_battle", 100, 60, 60, 20),
242        ("top_left_battle", 0, 0, 40, 40),
243        ("middle_fight_area", 35, 35, 25, 30),
244    ]
245
246    MULTI_TARGETS = {
247        "large_dialogue_box": [
248            "large_text_content",
249            "weakened_health_bar",
250            "restored_full_health",
251        ],
252        "top_left_battle": [
253            "yellow_rat",
254            "big_yellow_monster",
255        ],
256        "middle_fight_area": [
257            "bat",
258            "big_yellow_monster",
259        ],
260        "chocolate_frogs_5_inventory_area": [
261            "chocolate_frogs_5_inventory",
262            "chocolate_frogs_4_inventory",
263        ],
264        "mp_points_area": [
265            "fully_restore_your_mp",
266        ],
267        "find_location": [
268            "diagon_alley",
269        ],
270        "full_screen_area": [
271            "respawn_death_rat_screen",
272            "reenter_gringotts",
273            "exit_gringotts",
274            "on_train",
275            "sell_chocolate_frog",
276            "start_of_duel",
277            "win_duel",
278            "lose_duel",
279        ],
280        "leftmost_train_car": ["leftmost_train_car_capture"],
281        "rightmost_train_car": ["rightmost_train_car_capture"],
282        "menu": [
283            "start_menu",
284        ],
285        "rat_king_sprite_area": [
286            "rat_king_sprite",
287        ],
288        "last_item": [
289            "pumpkin_pasties",
290        ],
291        "item_consumption": [
292            "ate_pumpkin_pasties",
293        ],
294        "equip_screen": [
295            "nothing_equipped",
296            "equipped_pointed_hat",
297            "equipped_pointed_hat_plain_work_robe",
298            "remove_hat",
299            "remove_robe",
300            "empty_equip_cursor_robe",
301        ],
302        "dialogue_box_full": [
303            "talk_to_flourish_clerk",
304            "hagrid_diagon_dialogue",
305            "unable_to_escape",
306            "talk_to_weasleys",
307            "talk_to_ron_weasley",
308            "talk_with_hagrid_before_boat",
309        ],
310        "ollivanders_area": [
311            "ollivanders_interior",
312        ],
313        "ollivanders_entrance": [
314            "outside_ollivanders_door",
315        ],
316        "wand_dialogue_area": [
317            "talk_to_ollivander",
318        ],
319        "wand_received_text": [
320            "wand_received",
321        ],
322        "folio_boy_area": [
323            "boy_approaches",
324        ],
325        "choose_deck_text": [
326            "choose_deck_shown",
327        ],
328        "deck_reward_icon": [
329            "deck_selected",
330        ],
331        "gringotts_entrance": [
332            "outside_gringotts_door",
333        ],
334        "gringotts_interior_area": [
335            "gringotts_interior",
336        ],
337        "hagrid_gringotts_area": [
338            "find_hagrid_gringotts",
339        ],
340        "vault_interior": [
341            "hagrid_vault_dialogue",
342        ],
343        "level_up_text": [
344            "gained_new_level",
345        ],
346        "boss_rat_area": [
347            "boss_rat_found",
348        ],
349        "spell_level_text": [
350            "gained_new_spell",
351        ],
352        "battle_reward_bar": [
353            "battle_won",
354        ],
355        # -- Task 14 --
356        "post_boss_hagrid_area": [
357            "navigate_to_hagrid",
358        ],
359        "vault_entry_cutscene_area": [
360            "vault_entry_cutscene",
361        ],
362        # -- Madam Malkin split-task assets --
363        "outside_malkins_area": [
364            "outside_malkins",
365        ],
366        "inside_malkins_area": [
367            "inside_malkins",
368        ],
369        "robes_menu_area": [
370            "malkins_buy_menu_open",
371            "selected_robes",
372        ],
373        "robes_purchase_area": [
374            "confirm_robes_purchase",
375        ],
376        # -- Flourish & Blotts split-task assets --
377        "outside_flourish_blotts_area": [
378            "outside_flourish_blotts",
379        ],
380        "inside_flourish_blotts_area": [
381            "inside_flourish_blotts",
382        ],
383        "books_received_area": [
384            "books_received",
385        ],
386        # -- Apothecary split-task assets --
387        "outside_apothecary_area": [
388            "outside_apothecary",
389        ],
390        "inside_apothecary_area": [
391            "inside_apothecary",
392        ],
393        "apothecary_menu_area": [
394            "apothecary_buy_menu_open",
395        ],
396        "apothecary_purchase_area": [
397            "confirm_apothecary_purchase",
398        ],
399        # -- Cauldron shop assets --
400        "outside_cauldron_shop_area": [
401            "outside_cauldron_shop",
402        ],
403        "inside_cauldron_shop_area": [
404            "inside_cauldron_shop",
405        ],
406        "cauldron_menu_area": [
407            "cauldron_buy_menu_open",
408        ],
409        "cauldron_purchase_area": [
410            "confirm_cauldron_purchase",
411        ],
412        # -- Sugarplums Sweets filler tasks --
413        "outside_sugarplums_area": [
414            "outside_sugarplums",
415        ],
416        "inside_sugarplums_area": [
417            "inside_sugarplums",
418        ],
419        "sugarplums_menu_area": [
420            "sugarplums_buy_menu_open",
421        ],
422        "boat_battle": [
423            "boat_battle_target",
424        ],
425    }
class HarryPotterChamberOfSecretsParser(_BaseHarryPotterParser):
 95class HarryPotterChamberOfSecretsParser(_BaseHarryPotterParser):
 96    VARIANT = "harry_potter_chamber_of_secrets"
 97    DIALOGUE_BOX_REGION = (0, 112, 155, 7)
 98    """Shared CoS dialogue box coordinates in (x, y, width, height) form."""
 99
100    REGIONS = []
101
102    MULTI_TARGET_REGIONS = [
103        ("dialogue_box_full", *DIALOGUE_BOX_REGION),
104        ("dobby_bed_area", 96, 71, 40, 48),
105        ("dobby_dialogue_area", *DIALOGUE_BOX_REGION),
106        ("choose_deck_cos_area", 41, 95, 78, 9),
107        ("talk_to_ron_cos_area", *DIALOGUE_BOX_REGION),
108        ("flying_car_cutscene_area", 0, 0, 158, 56),
109        ("burrow_arrival_dialogue_area", *DIALOGUE_BOX_REGION),
110        ("mrs_weasley_dialogue_area", *DIALOGUE_BOX_REGION),
111        ("battle_menu_cos_area", 102, 120, 57, 23),
112        # -- Burrow room navigation tasks --
113        ("percy_room_area", 16, 0, 52, 80),         # termination: inside_percy_room
114        ("ginny_room_area", 74, 0, 36, 57),         # termination: inside_ginny_room
115        ("parents_room_area", 97, 0, 60, 65),       # termination: inside_parents_room
116        ("fred_george_room_area", 16, 32, 16, 84),  # termination: inside_fred_george_room
117        ("rons_room_area", 137, 0, 22, 71),         # termination: inside_rons_room
118        # -- Burrow kitchen / garden quest tasks --
119        ("garden_door_area", 80, 24, 10, 8),        # subgoal: outside_garden_door
120        ("car_area", 80, 65, 55, 70),
121    ]
122
123    MULTI_TARGETS = {
124        "dobby_bed_area": [
125            "find_dobby",
126        ],
127        "dialogue_box_full": [
128            "talk_to_ron_burrow",
129            "talk_to_mom_kitchen",
130            "talk_to_ron_garden",
131        ],
132        "dobby_dialogue_area": [
133            "dobby_dialogue_started",
134        ],
135        "choose_deck_cos_area": [
136            "deck_selected_cos",
137        ],
138        "talk_to_ron_cos_area": [
139            "talk_to_ron",
140        ],
141        "flying_car_cutscene_area": [
142            "flying_car_departure",
143        ],
144        "burrow_arrival_dialogue_area": [
145            "outside_burrow_after_cutscene",
146        ],
147        "mrs_weasley_dialogue_area": [
148            "mrs_weasley_table_dialogue",
149        ],
150        "battle_menu_cos_area": [
151            "in_battle_cos",
152        ],
153        # -- Burrow room navigation tasks --
154        "percy_room_area": [
155            "inside_percy_room",
156        ],
157        "ginny_room_area": [
158            "inside_ginny_room",
159        ],
160        "parents_room_area": [
161            "inside_parents_room",
162        ],
163        "fred_george_room_area": [
164            "inside_fred_george_room",
165        ],
166        "rons_room_area": [
167            "inside_rons_room",
168        ],
169        "garden_door_area": [
170            "outside_garden_door",
171        ],
172        "car_area": ["next_to_car"],
173    }

Minimal parser scaffold for Harry Potter variants.

This only configures rom_data_path so the base StateParser can run. Includes dialogue detection methods used by HarryPotterOCRMetric.

VARIANT = 'harry_potter_chamber_of_secrets'
DIALOGUE_BOX_REGION = (0, 112, 155, 7)

Shared CoS dialogue box coordinates in (x, y, width, height) form.

REGIONS = []
MULTI_TARGET_REGIONS = [('dialogue_box_full', 0, 112, 155, 7), ('dobby_bed_area', 96, 71, 40, 48), ('dobby_dialogue_area', 0, 112, 155, 7), ('choose_deck_cos_area', 41, 95, 78, 9), ('talk_to_ron_cos_area', 0, 112, 155, 7), ('flying_car_cutscene_area', 0, 0, 158, 56), ('burrow_arrival_dialogue_area', 0, 112, 155, 7), ('mrs_weasley_dialogue_area', 0, 112, 155, 7), ('battle_menu_cos_area', 102, 120, 57, 23), ('percy_room_area', 16, 0, 52, 80), ('ginny_room_area', 74, 0, 36, 57), ('parents_room_area', 97, 0, 60, 65), ('fred_george_room_area', 16, 32, 16, 84), ('rons_room_area', 137, 0, 22, 71), ('garden_door_area', 80, 24, 10, 8), ('car_area', 80, 65, 55, 70)]
MULTI_TARGETS = {'dobby_bed_area': ['find_dobby'], 'dialogue_box_full': ['talk_to_ron_burrow', 'talk_to_mom_kitchen', 'talk_to_ron_garden'], 'dobby_dialogue_area': ['dobby_dialogue_started'], 'choose_deck_cos_area': ['deck_selected_cos'], 'talk_to_ron_cos_area': ['talk_to_ron'], 'flying_car_cutscene_area': ['flying_car_departure'], 'burrow_arrival_dialogue_area': ['outside_burrow_after_cutscene'], 'mrs_weasley_dialogue_area': ['mrs_weasley_table_dialogue'], 'battle_menu_cos_area': ['in_battle_cos'], 'percy_room_area': ['inside_percy_room'], 'ginny_room_area': ['inside_ginny_room'], 'parents_room_area': ['inside_parents_room'], 'fred_george_room_area': ['inside_fred_george_room'], 'rons_room_area': ['inside_rons_room'], 'garden_door_area': ['outside_garden_door'], 'car_area': ['next_to_car']}
class HarryPotterPhilosophersStoneParser(_BaseHarryPotterParser):
176class HarryPotterPhilosophersStoneParser(_BaseHarryPotterParser):
177    VARIANT = "harry_potter_philosophers_stone"
178    DIALOGUE_BOX_REGION = (0, 112, 158, 8)
179    """Shared PS dialogue box coordinates in (x, y, width, height) form."""
180
181    REGIONS = [
182        ("potions_shop_shelf", 7, 26, 105, 21),
183    ]
184
185    MULTI_TARGET_REGIONS = [
186        ("dialogue_box_full", *DIALOGUE_BOX_REGION),
187        ("ollivanders_area", 80, 16, 63, 40),
188        ("ollivanders_entrance", 70, 21, 23, 21),
189        ("wand_dialogue_area", 19, 43, 31, 46),
190        ("wand_received_text", 7, 80, 144, 8),
191        ("folio_boy_area", 0, 63, 105, 54),
192        ("choose_deck_text", 42, 86, 77, 10),
193        ("deck_reward_icon", 68, 129, 16, 14),
194        ("gringotts_entrance", 65, 3, 30, 11),
195        ("gringotts_interior_area", 62, 112, 31, 15),
196        ("hagrid_gringotts_area", 49, 33, 31, 21),
197        ("vault_interior", 0, 49, 117, 69),
198        ("level_up_text", 33, 47, 94, 9),
199        ("boss_rat_area", 44, 40, 12, 15),
200        ("spell_level_text", 34, 48, 92, 16),
201        ("battle_reward_bar", 39, 25, 77, 6),
202        # -- Task 14: find_hagrid_vault_test --
203        # The subgoal uses the Hagrid dialogue box screen state rather than
204        # Hagrid's sprite, since dialogue is more stable than character art.
205        ("post_boss_hagrid_area", 31, 111, 129, 10),   # subgoal: navigate_to_hagrid (capture the Hagrid dialogue box state)
206        ("vault_entry_cutscene_area", 55, 32, 75, 39), # termination: vault_entry_cutscene
207        # -- Madam Malkin split-task assets --
208        ("outside_malkins_area", 19, 4, 21, 17),       # subgoal: outside_malkins
209        ("inside_malkins_area", 121, 29, 16, 16),      # termination: inside_malkins
210        ("robes_menu_area", 0, 0, 143, 29),            # termination: malkins_buy_menu_open
211        ("robes_purchase_area", 31, 25, 80, 6),        # confirmation prompt: confirm_robes_purchase
212        # -- Flourish & Blotts split-task assets --
213        ("outside_flourish_blotts_area", 93, 21, 21, 19),  # subgoal: outside_flourish_blotts
214        ("inside_flourish_blotts_area", 54, 16, 91, 49),   # termination: inside_flourish_blotts
215        ("books_received_area", 45, 110, 68, 32),          # termination: books_received
216        # -- Apothecary split-task assets --
217        ("outside_apothecary_area", 95, 31, 20, 18),    # subgoal: outside_apothecary
218        ("inside_apothecary_area", 94, 14, 49, 20),     # termination: inside_apothecary
219        ("apothecary_menu_area", 0, 0, 157, 30),    # terminations: apothecary_buy_menu_open, selected_apothecary_item
220        ("apothecary_purchase_area", 16, 0, 131, 86),   # termination: confirm_apothecary_purchase
221        # -- Cauldron shop assets --
222        ("outside_cauldron_shop_area", 57, 20, 22, 20),     # subgoal: outside_cauldron_shop
223        ("inside_cauldron_shop_area", 17, 2, 54, 20),      # termination: inside_cauldron_shop
224        ("cauldron_menu_area", 0, 0, 115, 32),          # subgoal: cauldron_buy_menu_open
225        ("cauldron_purchase_area", 31, 24, 78, 7),      # termination: confirm_cauldron_purchase
226        # -- Sugarplums Sweets filler tasks --
227        ("outside_sugarplums_area", 55, 22, 22, 20),    # subgoal: outside_sugarplums
228        ("inside_sugarplums_area", 25, 30, 75, 35),     # termination: inside_sugarplums
229        ("sugarplums_menu_area", 0, 0, 130, 30),        # termination: sugarplums_buy_menu_open
230        ("find_location", 0, 100, 160, 44),
231        ("menu", 0, 0, 90, 120),
232        ("last_item", 0, 105, 160, 30),
233        ("item_consumption", 0, 30, 160, 110),
234        ("equip_screen", 0, 25, 160, 119),
235        ("rat_king_sprite_area", 0, 0, 60, 100),
236        ("full_screen_area", 0, 0, 160, 144),
237        ("mp_points_area", 60, 120, 60, 10),
238        ("large_dialogue_box", 0, 112, 160, 32),
239        ("chocolate_frogs_5_inventory_area", 0, 60, 160, 20),
240        ("leftmost_train_car", 0, 0, 90, 90),
241        ("rightmost_train_car", 75, 0, 85, 90),
242        ("boat_battle", 100, 60, 60, 20),
243        ("top_left_battle", 0, 0, 40, 40),
244        ("middle_fight_area", 35, 35, 25, 30),
245    ]
246
247    MULTI_TARGETS = {
248        "large_dialogue_box": [
249            "large_text_content",
250            "weakened_health_bar",
251            "restored_full_health",
252        ],
253        "top_left_battle": [
254            "yellow_rat",
255            "big_yellow_monster",
256        ],
257        "middle_fight_area": [
258            "bat",
259            "big_yellow_monster",
260        ],
261        "chocolate_frogs_5_inventory_area": [
262            "chocolate_frogs_5_inventory",
263            "chocolate_frogs_4_inventory",
264        ],
265        "mp_points_area": [
266            "fully_restore_your_mp",
267        ],
268        "find_location": [
269            "diagon_alley",
270        ],
271        "full_screen_area": [
272            "respawn_death_rat_screen",
273            "reenter_gringotts",
274            "exit_gringotts",
275            "on_train",
276            "sell_chocolate_frog",
277            "start_of_duel",
278            "win_duel",
279            "lose_duel",
280        ],
281        "leftmost_train_car": ["leftmost_train_car_capture"],
282        "rightmost_train_car": ["rightmost_train_car_capture"],
283        "menu": [
284            "start_menu",
285        ],
286        "rat_king_sprite_area": [
287            "rat_king_sprite",
288        ],
289        "last_item": [
290            "pumpkin_pasties",
291        ],
292        "item_consumption": [
293            "ate_pumpkin_pasties",
294        ],
295        "equip_screen": [
296            "nothing_equipped",
297            "equipped_pointed_hat",
298            "equipped_pointed_hat_plain_work_robe",
299            "remove_hat",
300            "remove_robe",
301            "empty_equip_cursor_robe",
302        ],
303        "dialogue_box_full": [
304            "talk_to_flourish_clerk",
305            "hagrid_diagon_dialogue",
306            "unable_to_escape",
307            "talk_to_weasleys",
308            "talk_to_ron_weasley",
309            "talk_with_hagrid_before_boat",
310        ],
311        "ollivanders_area": [
312            "ollivanders_interior",
313        ],
314        "ollivanders_entrance": [
315            "outside_ollivanders_door",
316        ],
317        "wand_dialogue_area": [
318            "talk_to_ollivander",
319        ],
320        "wand_received_text": [
321            "wand_received",
322        ],
323        "folio_boy_area": [
324            "boy_approaches",
325        ],
326        "choose_deck_text": [
327            "choose_deck_shown",
328        ],
329        "deck_reward_icon": [
330            "deck_selected",
331        ],
332        "gringotts_entrance": [
333            "outside_gringotts_door",
334        ],
335        "gringotts_interior_area": [
336            "gringotts_interior",
337        ],
338        "hagrid_gringotts_area": [
339            "find_hagrid_gringotts",
340        ],
341        "vault_interior": [
342            "hagrid_vault_dialogue",
343        ],
344        "level_up_text": [
345            "gained_new_level",
346        ],
347        "boss_rat_area": [
348            "boss_rat_found",
349        ],
350        "spell_level_text": [
351            "gained_new_spell",
352        ],
353        "battle_reward_bar": [
354            "battle_won",
355        ],
356        # -- Task 14 --
357        "post_boss_hagrid_area": [
358            "navigate_to_hagrid",
359        ],
360        "vault_entry_cutscene_area": [
361            "vault_entry_cutscene",
362        ],
363        # -- Madam Malkin split-task assets --
364        "outside_malkins_area": [
365            "outside_malkins",
366        ],
367        "inside_malkins_area": [
368            "inside_malkins",
369        ],
370        "robes_menu_area": [
371            "malkins_buy_menu_open",
372            "selected_robes",
373        ],
374        "robes_purchase_area": [
375            "confirm_robes_purchase",
376        ],
377        # -- Flourish & Blotts split-task assets --
378        "outside_flourish_blotts_area": [
379            "outside_flourish_blotts",
380        ],
381        "inside_flourish_blotts_area": [
382            "inside_flourish_blotts",
383        ],
384        "books_received_area": [
385            "books_received",
386        ],
387        # -- Apothecary split-task assets --
388        "outside_apothecary_area": [
389            "outside_apothecary",
390        ],
391        "inside_apothecary_area": [
392            "inside_apothecary",
393        ],
394        "apothecary_menu_area": [
395            "apothecary_buy_menu_open",
396        ],
397        "apothecary_purchase_area": [
398            "confirm_apothecary_purchase",
399        ],
400        # -- Cauldron shop assets --
401        "outside_cauldron_shop_area": [
402            "outside_cauldron_shop",
403        ],
404        "inside_cauldron_shop_area": [
405            "inside_cauldron_shop",
406        ],
407        "cauldron_menu_area": [
408            "cauldron_buy_menu_open",
409        ],
410        "cauldron_purchase_area": [
411            "confirm_cauldron_purchase",
412        ],
413        # -- Sugarplums Sweets filler tasks --
414        "outside_sugarplums_area": [
415            "outside_sugarplums",
416        ],
417        "inside_sugarplums_area": [
418            "inside_sugarplums",
419        ],
420        "sugarplums_menu_area": [
421            "sugarplums_buy_menu_open",
422        ],
423        "boat_battle": [
424            "boat_battle_target",
425        ],
426    }

Minimal parser scaffold for Harry Potter variants.

This only configures rom_data_path so the base StateParser can run. Includes dialogue detection methods used by HarryPotterOCRMetric.

VARIANT = 'harry_potter_philosophers_stone'
DIALOGUE_BOX_REGION = (0, 112, 158, 8)

Shared PS dialogue box coordinates in (x, y, width, height) form.

REGIONS = [('potions_shop_shelf', 7, 26, 105, 21)]
MULTI_TARGET_REGIONS = [('dialogue_box_full', 0, 112, 158, 8), ('ollivanders_area', 80, 16, 63, 40), ('ollivanders_entrance', 70, 21, 23, 21), ('wand_dialogue_area', 19, 43, 31, 46), ('wand_received_text', 7, 80, 144, 8), ('folio_boy_area', 0, 63, 105, 54), ('choose_deck_text', 42, 86, 77, 10), ('deck_reward_icon', 68, 129, 16, 14), ('gringotts_entrance', 65, 3, 30, 11), ('gringotts_interior_area', 62, 112, 31, 15), ('hagrid_gringotts_area', 49, 33, 31, 21), ('vault_interior', 0, 49, 117, 69), ('level_up_text', 33, 47, 94, 9), ('boss_rat_area', 44, 40, 12, 15), ('spell_level_text', 34, 48, 92, 16), ('battle_reward_bar', 39, 25, 77, 6), ('post_boss_hagrid_area', 31, 111, 129, 10), ('vault_entry_cutscene_area', 55, 32, 75, 39), ('outside_malkins_area', 19, 4, 21, 17), ('inside_malkins_area', 121, 29, 16, 16), ('robes_menu_area', 0, 0, 143, 29), ('robes_purchase_area', 31, 25, 80, 6), ('outside_flourish_blotts_area', 93, 21, 21, 19), ('inside_flourish_blotts_area', 54, 16, 91, 49), ('books_received_area', 45, 110, 68, 32), ('outside_apothecary_area', 95, 31, 20, 18), ('inside_apothecary_area', 94, 14, 49, 20), ('apothecary_menu_area', 0, 0, 157, 30), ('apothecary_purchase_area', 16, 0, 131, 86), ('outside_cauldron_shop_area', 57, 20, 22, 20), ('inside_cauldron_shop_area', 17, 2, 54, 20), ('cauldron_menu_area', 0, 0, 115, 32), ('cauldron_purchase_area', 31, 24, 78, 7), ('outside_sugarplums_area', 55, 22, 22, 20), ('inside_sugarplums_area', 25, 30, 75, 35), ('sugarplums_menu_area', 0, 0, 130, 30), ('find_location', 0, 100, 160, 44), ('menu', 0, 0, 90, 120), ('last_item', 0, 105, 160, 30), ('item_consumption', 0, 30, 160, 110), ('equip_screen', 0, 25, 160, 119), ('rat_king_sprite_area', 0, 0, 60, 100), ('full_screen_area', 0, 0, 160, 144), ('mp_points_area', 60, 120, 60, 10), ('large_dialogue_box', 0, 112, 160, 32), ('chocolate_frogs_5_inventory_area', 0, 60, 160, 20), ('leftmost_train_car', 0, 0, 90, 90), ('rightmost_train_car', 75, 0, 85, 90), ('boat_battle', 100, 60, 60, 20), ('top_left_battle', 0, 0, 40, 40), ('middle_fight_area', 35, 35, 25, 30)]
MULTI_TARGETS = {'large_dialogue_box': ['large_text_content', 'weakened_health_bar', 'restored_full_health'], 'top_left_battle': ['yellow_rat', 'big_yellow_monster'], 'middle_fight_area': ['bat', 'big_yellow_monster'], 'chocolate_frogs_5_inventory_area': ['chocolate_frogs_5_inventory', 'chocolate_frogs_4_inventory'], 'mp_points_area': ['fully_restore_your_mp'], 'find_location': ['diagon_alley'], 'full_screen_area': ['respawn_death_rat_screen', 'reenter_gringotts', 'exit_gringotts', 'on_train', 'sell_chocolate_frog', 'start_of_duel', 'win_duel', 'lose_duel'], 'leftmost_train_car': ['leftmost_train_car_capture'], 'rightmost_train_car': ['rightmost_train_car_capture'], 'menu': ['start_menu'], 'rat_king_sprite_area': ['rat_king_sprite'], 'last_item': ['pumpkin_pasties'], 'item_consumption': ['ate_pumpkin_pasties'], 'equip_screen': ['nothing_equipped', 'equipped_pointed_hat', 'equipped_pointed_hat_plain_work_robe', 'remove_hat', 'remove_robe', 'empty_equip_cursor_robe'], 'dialogue_box_full': ['talk_to_flourish_clerk', 'hagrid_diagon_dialogue', 'unable_to_escape', 'talk_to_weasleys', 'talk_to_ron_weasley', 'talk_with_hagrid_before_boat'], 'ollivanders_area': ['ollivanders_interior'], 'ollivanders_entrance': ['outside_ollivanders_door'], 'wand_dialogue_area': ['talk_to_ollivander'], 'wand_received_text': ['wand_received'], 'folio_boy_area': ['boy_approaches'], 'choose_deck_text': ['choose_deck_shown'], 'deck_reward_icon': ['deck_selected'], 'gringotts_entrance': ['outside_gringotts_door'], 'gringotts_interior_area': ['gringotts_interior'], 'hagrid_gringotts_area': ['find_hagrid_gringotts'], 'vault_interior': ['hagrid_vault_dialogue'], 'level_up_text': ['gained_new_level'], 'boss_rat_area': ['boss_rat_found'], 'spell_level_text': ['gained_new_spell'], 'battle_reward_bar': ['battle_won'], 'post_boss_hagrid_area': ['navigate_to_hagrid'], 'vault_entry_cutscene_area': ['vault_entry_cutscene'], 'outside_malkins_area': ['outside_malkins'], 'inside_malkins_area': ['inside_malkins'], 'robes_menu_area': ['malkins_buy_menu_open', 'selected_robes'], 'robes_purchase_area': ['confirm_robes_purchase'], 'outside_flourish_blotts_area': ['outside_flourish_blotts'], 'inside_flourish_blotts_area': ['inside_flourish_blotts'], 'books_received_area': ['books_received'], 'outside_apothecary_area': ['outside_apothecary'], 'inside_apothecary_area': ['inside_apothecary'], 'apothecary_menu_area': ['apothecary_buy_menu_open'], 'apothecary_purchase_area': ['confirm_apothecary_purchase'], 'outside_cauldron_shop_area': ['outside_cauldron_shop'], 'inside_cauldron_shop_area': ['inside_cauldron_shop'], 'cauldron_menu_area': ['cauldron_buy_menu_open'], 'cauldron_purchase_area': ['confirm_cauldron_purchase'], 'outside_sugarplums_area': ['outside_sugarplums'], 'inside_sugarplums_area': ['inside_sugarplums'], 'sugarplums_menu_area': ['sugarplums_buy_menu_open'], 'boat_battle': ['boat_battle_target']}