gameboy_worlds.emulation.bomberman.parsers

  1import os
  2from abc import ABC
  3
  4import numpy as np
  5
  6from gameboy_worlds.emulation.parser import NamedScreenRegion, StateParser
  7from gameboy_worlds.utils import log_error, verify_parameters
  8
  9
 10class BombermanParser(StateParser, ABC):
 11    VARIANT = ""
 12    MULTI_TARGET_REGIONS = []
 13    MULTI_TARGETS = {}
 14
 15    def __init__(self, pyboy, parameters):
 16        verify_parameters(parameters)
 17        if f"{self.VARIANT}_rom_data_path" not in parameters:
 18            log_error(
 19                f"ROM data path not found for variant: {self.VARIANT}. Add {self.VARIANT}_rom_data_path to config files.",
 20                parameters,
 21            )
 22        self.rom_data_path = parameters[f"{self.VARIANT}_rom_data_path"]
 23        captures_dir = os.path.join(self.rom_data_path, "captures")
 24        regions = []
 25        for region_name, x, y, w, h in self.MULTI_TARGET_REGIONS:
 26            subdir = os.path.join(captures_dir, region_name)
 27            region_target_paths = {
 28                target_name: os.path.join(subdir, target_name)
 29                for target_name in self.MULTI_TARGETS.get(region_name, [])
 30            }
 31            regions.append(
 32                NamedScreenRegion(
 33                    name=region_name,
 34                    start_x=x,
 35                    start_y=y,
 36                    width=w,
 37                    height=h,
 38                    parameters=parameters,
 39                    multi_target_paths=region_target_paths,
 40                )
 41            )
 42        super().__init__(pyboy, parameters, named_screen_regions=regions)
 43
 44    def _matches(self, current_screen: np.ndarray, region_name: str, target_name: str) -> bool:
 45        return self.named_region_matches_multi_target(
 46            current_screen, region_name, target_name
 47        )
 48
 49    def __repr__(self) -> str:
 50        return f"{self.__class__.__name__}(variant={self.VARIANT})"
 51
 52
 53class BombermanMaxParser(BombermanParser):
 54    VARIANT = "bomberman_max"
 55
 56    MULTI_TARGET_REGIONS = [
 57        ("screen_top", 0, 0, 160, 16),
 58        ("stage_briefing_strip", 0, 87, 43, 41),
 59        ("stage_briefing_box", 0, 72, 160, 56),
 60        ("hud_enemy_count", 110, 136, 17, 8),
 61        ("hud_bomb_count", 127, 136, 15, 8),
 62        ("hud_fire", 142, 136, 18, 8),
 63        ("zone_background", 0, 0, 160, 32),
 64    ]
 65
 66    MULTI_TARGETS = {
 67        "screen_top": [
 68            "pause_menu_open",
 69            "stage_select",
 70            "game_over",
 71            "charabom_select_open",
 72            "pitch_area",
 73        ],
 74        "stage_briefing_strip": ["stage_briefing_active"],
 75        "hud_enemy_count": [],
 76        "hud_bomb_count": [],
 77        "hud_fire": [],
 78        "zone_background": [],
 79    }
 80
 81    def is_in_menu(self, current_screen: np.ndarray) -> bool:
 82        return self._matches(current_screen, "screen_top", "pause_menu_open")
 83
 84    def is_on_stage_select(self, current_screen: np.ndarray) -> bool:
 85        return self._matches(current_screen, "screen_top", "stage_select")
 86
 87    def is_game_over(self, current_screen: np.ndarray) -> bool:
 88        return self._matches(current_screen, "screen_top", "game_over")
 89
 90    def is_in_charabom_select(self, current_screen: np.ndarray) -> bool:
 91        return self._matches(current_screen, "screen_top", "charabom_select_open")
 92
 93    def is_stage_briefing_active(self, current_screen: np.ndarray) -> bool:
 94        return self._matches(
 95            current_screen, "stage_briefing_strip", "stage_briefing_active"
 96        )
 97
 98    def is_in_zone_1(self, current_screen: np.ndarray) -> bool:
 99        return self._matches(current_screen, "zone_background", "in_zone_1")
100
101    def is_in_battle(self, current_screen: np.ndarray) -> bool:
102        return False
103
104
105class BombermanPocketParser(BombermanParser):
106    VARIANT = "bomberman_pocket"
107
108    MULTI_TARGET_REGIONS = [
109        ("area_intro_strip", 0, 0, 160, 20),
110        ("area_intro_block", 0, 0, 53, 20),
111        ("pause_indicator", 96, 128, 64, 16),
112        ("hud_heart", 54, 136, 10, 7),
113        ("hud_enemy_count", 86, 136, 21, 7),
114        ("hud_bomb_count", 110, 136, 20, 7),
115        ("hud_bottom_right", 130, 136, 30, 7),
116        ("zone_background", 0, 0, 160, 32),
117    ]
118
119    MULTI_TARGETS = {
120        "area_intro_strip": [
121            "world_clear",
122            "game_over",
123            "jump_level_select",
124            "jump_results",
125            "jump_ranking",
126        ],
127        "area_intro_block": ["area_intro_active"],
128        "pause_indicator": ["pause_active"],
129        "hud_heart": [],
130        "hud_enemy_count": [],
131        "hud_bomb_count": [],
132        "hud_bottom_right": [],
133        "zone_background": [
134            "in_forest_world",
135            "in_ocean_world",
136            "in_wind_world",
137            "in_cloud_world",
138            "in_evil_world",
139        ],
140    }
141
142    def is_paused(self, current_screen: np.ndarray) -> bool:
143        return self._matches(current_screen, "pause_indicator", "pause_active")
144
145    def is_in_menu(self, current_screen: np.ndarray) -> bool:
146        return self.is_paused(current_screen)
147
148    def is_world_clear(self, current_screen: np.ndarray) -> bool:
149        return self._matches(current_screen, "area_intro_strip", "world_clear")
150
151    def is_area_intro_active(self, current_screen: np.ndarray) -> bool:
152        return self._matches(current_screen, "area_intro_block", "area_intro_active")
153
154    def is_in_any_area_intro(self, current_screen: np.ndarray) -> bool:
155        return self.is_area_intro_active(current_screen)
156
157    def is_in_forest_world(self, current_screen: np.ndarray) -> bool:
158        return self._matches(current_screen, "zone_background", "in_forest_world")
159
160    def is_in_ocean_world(self, current_screen: np.ndarray) -> bool:
161        return self._matches(current_screen, "zone_background", "in_ocean_world")
162
163    def is_in_wind_world(self, current_screen: np.ndarray) -> bool:
164        return self._matches(current_screen, "zone_background", "in_wind_world")
165
166    def is_in_cloud_world(self, current_screen: np.ndarray) -> bool:
167        return self._matches(current_screen, "zone_background", "in_cloud_world")
168
169    def is_in_evil_world(self, current_screen: np.ndarray) -> bool:
170        return self._matches(current_screen, "zone_background", "in_evil_world")
171
172
173
174class BombermanQuestParser(BombermanParser):
175    VARIANT = "bomberman_quest"
176
177    MULTI_TARGET_REGIONS = [
178        ("screen_top", 0, 0, 160, 16),
179        ("dialogue_strip", 0, 12, 160, 10),
180        ("dialogue_box", 0, 12, 160, 60),
181        ("dialogue_icon", 124, 30, 31, 27),
182        ("hud_bottom", 47, 136, 33, 8),
183        ("item_select_panel", 95, 5, 65, 85),
184        ("zone_background", 0, 0, 160, 32),
185        ("book_bottom", 0, 120, 160, 20),
186        ("bottom_strip", 0, 120, 160, 24),
187        ("button_region", 80, 80, 16, 16),
188        ("switch_detector", 64, 64, 16, 16),
189        ("box_detector", 80, 64, 16, 16),
190        ("cliff_box_detector", 32, 32, 16, 16),
191        ("hard_switch_detector", 16, 16, 16, 16),
192    ]
193
194    MULTI_TARGETS = {
195        "screen_top": ["pause_menu_open", "bomb_select_open", "game_over"],
196        "dialogue_strip": ["dialogue_active"],
197        "dialogue_icon": ["sign_dialogue_active"],
198        "hud_bottom": ["battle_active"],
199        "item_select_panel": [
200            "shield_select_active",
201            "bomb_component_select_active",
202        ],
203        "zone_background": [
204            "in_camp",
205            "in_house",
206            "in_cave",
207            "in_room",
208            "in_ruins",
209            "save_npc_active",
210        ],
211        "book_bottom": ["book_read_active"],
212        "bottom_strip": [],
213        "button_region": [],
214        "switch_detector": ["switch_activated"],
215        "box_detector": [],
216        "cliff_box_detector": [],
217        "hard_switch_detector": [],
218    }
219
220    def is_in_menu(self, current_screen: np.ndarray) -> bool:
221        return self._matches(current_screen, "screen_top", "pause_menu_open")
222
223    def is_game_over(self, current_screen: np.ndarray) -> bool:
224        return self._matches(current_screen, "screen_top", "game_over")
225
226    def is_in_battle(self, current_screen: np.ndarray) -> bool:
227        return self._matches(current_screen, "hud_bottom", "battle_active")
228
229    def is_in_dialogue(self, current_screen: np.ndarray) -> bool:
230        return self._matches(current_screen, "dialogue_strip", "dialogue_active")
231
232    def is_in_npc_dialogue(self, current_screen: np.ndarray) -> bool:
233        return self.is_in_dialogue(current_screen) and not self.is_reading_sign(
234            current_screen
235        )
236
237    def is_reading_sign(self, current_screen: np.ndarray) -> bool:
238        return self._matches(current_screen, "dialogue_icon", "sign_dialogue_active")
239
240    def is_reading_book(self, current_screen: np.ndarray) -> bool:
241        return self._matches(current_screen, "book_bottom", "book_read_active")
242
243    def is_shield_select_active(self, current_screen: np.ndarray) -> bool:
244        return self._matches(current_screen, "item_select_panel", "shield_select_active")
245
246    def is_bomb_component_select_active(self, current_screen: np.ndarray) -> bool:
247        return self._matches(
248            current_screen, "item_select_panel", "bomb_component_select_active"
249        )
250
251    def is_in_camp(self, current_screen: np.ndarray) -> bool:
252        return self._matches(current_screen, "zone_background", "in_camp")
253
254    def is_in_house(self, current_screen: np.ndarray) -> bool:
255        return self._matches(current_screen, "zone_background", "in_house")
256
257    def is_in_cave(self, current_screen: np.ndarray) -> bool:
258        return self._matches(current_screen, "zone_background", "in_cave")
class BombermanParser(gameboy_worlds.emulation.parser.StateParser, abc.ABC):
11class BombermanParser(StateParser, ABC):
12    VARIANT = ""
13    MULTI_TARGET_REGIONS = []
14    MULTI_TARGETS = {}
15
16    def __init__(self, pyboy, parameters):
17        verify_parameters(parameters)
18        if f"{self.VARIANT}_rom_data_path" not in parameters:
19            log_error(
20                f"ROM data path not found for variant: {self.VARIANT}. Add {self.VARIANT}_rom_data_path to config files.",
21                parameters,
22            )
23        self.rom_data_path = parameters[f"{self.VARIANT}_rom_data_path"]
24        captures_dir = os.path.join(self.rom_data_path, "captures")
25        regions = []
26        for region_name, x, y, w, h in self.MULTI_TARGET_REGIONS:
27            subdir = os.path.join(captures_dir, region_name)
28            region_target_paths = {
29                target_name: os.path.join(subdir, target_name)
30                for target_name in self.MULTI_TARGETS.get(region_name, [])
31            }
32            regions.append(
33                NamedScreenRegion(
34                    name=region_name,
35                    start_x=x,
36                    start_y=y,
37                    width=w,
38                    height=h,
39                    parameters=parameters,
40                    multi_target_paths=region_target_paths,
41                )
42            )
43        super().__init__(pyboy, parameters, named_screen_regions=regions)
44
45    def _matches(self, current_screen: np.ndarray, region_name: str, target_name: str) -> bool:
46        return self.named_region_matches_multi_target(
47            current_screen, region_name, target_name
48        )
49
50    def __repr__(self) -> str:
51        return f"{self.__class__.__name__}(variant={self.VARIANT})"

Abstract base class for parsing game state variables from the GameBoy emulator.

BombermanParser(pyboy, parameters)
16    def __init__(self, pyboy, parameters):
17        verify_parameters(parameters)
18        if f"{self.VARIANT}_rom_data_path" not in parameters:
19            log_error(
20                f"ROM data path not found for variant: {self.VARIANT}. Add {self.VARIANT}_rom_data_path to config files.",
21                parameters,
22            )
23        self.rom_data_path = parameters[f"{self.VARIANT}_rom_data_path"]
24        captures_dir = os.path.join(self.rom_data_path, "captures")
25        regions = []
26        for region_name, x, y, w, h in self.MULTI_TARGET_REGIONS:
27            subdir = os.path.join(captures_dir, region_name)
28            region_target_paths = {
29                target_name: os.path.join(subdir, target_name)
30                for target_name in self.MULTI_TARGETS.get(region_name, [])
31            }
32            regions.append(
33                NamedScreenRegion(
34                    name=region_name,
35                    start_x=x,
36                    start_y=y,
37                    width=w,
38                    height=h,
39                    parameters=parameters,
40                    multi_target_paths=region_target_paths,
41                )
42            )
43        super().__init__(pyboy, parameters, named_screen_regions=regions)

Initializes the StateParser. Child implementations should call super().__init__() after running their code. All children must create a self.rom_data_path variable

Arguments:
  • pyboy: An instance of the PyBoy emulator.
  • parameters: A dictionary of parameters for configuration.
  • named_screen_regions (Optional[list[NamedScreenRegion]]): A list of NamedScreenRegion objects for easy access to specific screen regions.
VARIANT = ''
MULTI_TARGET_REGIONS = []
MULTI_TARGETS = {}
rom_data_path

Path to the rom data directory for the game variant.

class BombermanMaxParser(BombermanParser):
 54class BombermanMaxParser(BombermanParser):
 55    VARIANT = "bomberman_max"
 56
 57    MULTI_TARGET_REGIONS = [
 58        ("screen_top", 0, 0, 160, 16),
 59        ("stage_briefing_strip", 0, 87, 43, 41),
 60        ("stage_briefing_box", 0, 72, 160, 56),
 61        ("hud_enemy_count", 110, 136, 17, 8),
 62        ("hud_bomb_count", 127, 136, 15, 8),
 63        ("hud_fire", 142, 136, 18, 8),
 64        ("zone_background", 0, 0, 160, 32),
 65    ]
 66
 67    MULTI_TARGETS = {
 68        "screen_top": [
 69            "pause_menu_open",
 70            "stage_select",
 71            "game_over",
 72            "charabom_select_open",
 73            "pitch_area",
 74        ],
 75        "stage_briefing_strip": ["stage_briefing_active"],
 76        "hud_enemy_count": [],
 77        "hud_bomb_count": [],
 78        "hud_fire": [],
 79        "zone_background": [],
 80    }
 81
 82    def is_in_menu(self, current_screen: np.ndarray) -> bool:
 83        return self._matches(current_screen, "screen_top", "pause_menu_open")
 84
 85    def is_on_stage_select(self, current_screen: np.ndarray) -> bool:
 86        return self._matches(current_screen, "screen_top", "stage_select")
 87
 88    def is_game_over(self, current_screen: np.ndarray) -> bool:
 89        return self._matches(current_screen, "screen_top", "game_over")
 90
 91    def is_in_charabom_select(self, current_screen: np.ndarray) -> bool:
 92        return self._matches(current_screen, "screen_top", "charabom_select_open")
 93
 94    def is_stage_briefing_active(self, current_screen: np.ndarray) -> bool:
 95        return self._matches(
 96            current_screen, "stage_briefing_strip", "stage_briefing_active"
 97        )
 98
 99    def is_in_zone_1(self, current_screen: np.ndarray) -> bool:
100        return self._matches(current_screen, "zone_background", "in_zone_1")
101
102    def is_in_battle(self, current_screen: np.ndarray) -> bool:
103        return False

Abstract base class for parsing game state variables from the GameBoy emulator.

VARIANT = 'bomberman_max'
MULTI_TARGET_REGIONS = [('screen_top', 0, 0, 160, 16), ('stage_briefing_strip', 0, 87, 43, 41), ('stage_briefing_box', 0, 72, 160, 56), ('hud_enemy_count', 110, 136, 17, 8), ('hud_bomb_count', 127, 136, 15, 8), ('hud_fire', 142, 136, 18, 8), ('zone_background', 0, 0, 160, 32)]
MULTI_TARGETS = {'screen_top': ['pause_menu_open', 'stage_select', 'game_over', 'charabom_select_open', 'pitch_area'], 'stage_briefing_strip': ['stage_briefing_active'], 'hud_enemy_count': [], 'hud_bomb_count': [], 'hud_fire': [], 'zone_background': []}
def is_in_menu(self, current_screen: numpy.ndarray) -> bool:
82    def is_in_menu(self, current_screen: np.ndarray) -> bool:
83        return self._matches(current_screen, "screen_top", "pause_menu_open")
def is_on_stage_select(self, current_screen: numpy.ndarray) -> bool:
85    def is_on_stage_select(self, current_screen: np.ndarray) -> bool:
86        return self._matches(current_screen, "screen_top", "stage_select")
def is_game_over(self, current_screen: numpy.ndarray) -> bool:
88    def is_game_over(self, current_screen: np.ndarray) -> bool:
89        return self._matches(current_screen, "screen_top", "game_over")
def is_in_charabom_select(self, current_screen: numpy.ndarray) -> bool:
91    def is_in_charabom_select(self, current_screen: np.ndarray) -> bool:
92        return self._matches(current_screen, "screen_top", "charabom_select_open")
def is_stage_briefing_active(self, current_screen: numpy.ndarray) -> bool:
94    def is_stage_briefing_active(self, current_screen: np.ndarray) -> bool:
95        return self._matches(
96            current_screen, "stage_briefing_strip", "stage_briefing_active"
97        )
def is_in_zone_1(self, current_screen: numpy.ndarray) -> bool:
 99    def is_in_zone_1(self, current_screen: np.ndarray) -> bool:
100        return self._matches(current_screen, "zone_background", "in_zone_1")
def is_in_battle(self, current_screen: numpy.ndarray) -> bool:
102    def is_in_battle(self, current_screen: np.ndarray) -> bool:
103        return False
class BombermanPocketParser(BombermanParser):
106class BombermanPocketParser(BombermanParser):
107    VARIANT = "bomberman_pocket"
108
109    MULTI_TARGET_REGIONS = [
110        ("area_intro_strip", 0, 0, 160, 20),
111        ("area_intro_block", 0, 0, 53, 20),
112        ("pause_indicator", 96, 128, 64, 16),
113        ("hud_heart", 54, 136, 10, 7),
114        ("hud_enemy_count", 86, 136, 21, 7),
115        ("hud_bomb_count", 110, 136, 20, 7),
116        ("hud_bottom_right", 130, 136, 30, 7),
117        ("zone_background", 0, 0, 160, 32),
118    ]
119
120    MULTI_TARGETS = {
121        "area_intro_strip": [
122            "world_clear",
123            "game_over",
124            "jump_level_select",
125            "jump_results",
126            "jump_ranking",
127        ],
128        "area_intro_block": ["area_intro_active"],
129        "pause_indicator": ["pause_active"],
130        "hud_heart": [],
131        "hud_enemy_count": [],
132        "hud_bomb_count": [],
133        "hud_bottom_right": [],
134        "zone_background": [
135            "in_forest_world",
136            "in_ocean_world",
137            "in_wind_world",
138            "in_cloud_world",
139            "in_evil_world",
140        ],
141    }
142
143    def is_paused(self, current_screen: np.ndarray) -> bool:
144        return self._matches(current_screen, "pause_indicator", "pause_active")
145
146    def is_in_menu(self, current_screen: np.ndarray) -> bool:
147        return self.is_paused(current_screen)
148
149    def is_world_clear(self, current_screen: np.ndarray) -> bool:
150        return self._matches(current_screen, "area_intro_strip", "world_clear")
151
152    def is_area_intro_active(self, current_screen: np.ndarray) -> bool:
153        return self._matches(current_screen, "area_intro_block", "area_intro_active")
154
155    def is_in_any_area_intro(self, current_screen: np.ndarray) -> bool:
156        return self.is_area_intro_active(current_screen)
157
158    def is_in_forest_world(self, current_screen: np.ndarray) -> bool:
159        return self._matches(current_screen, "zone_background", "in_forest_world")
160
161    def is_in_ocean_world(self, current_screen: np.ndarray) -> bool:
162        return self._matches(current_screen, "zone_background", "in_ocean_world")
163
164    def is_in_wind_world(self, current_screen: np.ndarray) -> bool:
165        return self._matches(current_screen, "zone_background", "in_wind_world")
166
167    def is_in_cloud_world(self, current_screen: np.ndarray) -> bool:
168        return self._matches(current_screen, "zone_background", "in_cloud_world")
169
170    def is_in_evil_world(self, current_screen: np.ndarray) -> bool:
171        return self._matches(current_screen, "zone_background", "in_evil_world")

Abstract base class for parsing game state variables from the GameBoy emulator.

VARIANT = 'bomberman_pocket'
MULTI_TARGET_REGIONS = [('area_intro_strip', 0, 0, 160, 20), ('area_intro_block', 0, 0, 53, 20), ('pause_indicator', 96, 128, 64, 16), ('hud_heart', 54, 136, 10, 7), ('hud_enemy_count', 86, 136, 21, 7), ('hud_bomb_count', 110, 136, 20, 7), ('hud_bottom_right', 130, 136, 30, 7), ('zone_background', 0, 0, 160, 32)]
MULTI_TARGETS = {'area_intro_strip': ['world_clear', 'game_over', 'jump_level_select', 'jump_results', 'jump_ranking'], 'area_intro_block': ['area_intro_active'], 'pause_indicator': ['pause_active'], 'hud_heart': [], 'hud_enemy_count': [], 'hud_bomb_count': [], 'hud_bottom_right': [], 'zone_background': ['in_forest_world', 'in_ocean_world', 'in_wind_world', 'in_cloud_world', 'in_evil_world']}
def is_paused(self, current_screen: numpy.ndarray) -> bool:
143    def is_paused(self, current_screen: np.ndarray) -> bool:
144        return self._matches(current_screen, "pause_indicator", "pause_active")
def is_in_menu(self, current_screen: numpy.ndarray) -> bool:
146    def is_in_menu(self, current_screen: np.ndarray) -> bool:
147        return self.is_paused(current_screen)
def is_world_clear(self, current_screen: numpy.ndarray) -> bool:
149    def is_world_clear(self, current_screen: np.ndarray) -> bool:
150        return self._matches(current_screen, "area_intro_strip", "world_clear")
def is_area_intro_active(self, current_screen: numpy.ndarray) -> bool:
152    def is_area_intro_active(self, current_screen: np.ndarray) -> bool:
153        return self._matches(current_screen, "area_intro_block", "area_intro_active")
def is_in_any_area_intro(self, current_screen: numpy.ndarray) -> bool:
155    def is_in_any_area_intro(self, current_screen: np.ndarray) -> bool:
156        return self.is_area_intro_active(current_screen)
def is_in_forest_world(self, current_screen: numpy.ndarray) -> bool:
158    def is_in_forest_world(self, current_screen: np.ndarray) -> bool:
159        return self._matches(current_screen, "zone_background", "in_forest_world")
def is_in_ocean_world(self, current_screen: numpy.ndarray) -> bool:
161    def is_in_ocean_world(self, current_screen: np.ndarray) -> bool:
162        return self._matches(current_screen, "zone_background", "in_ocean_world")
def is_in_wind_world(self, current_screen: numpy.ndarray) -> bool:
164    def is_in_wind_world(self, current_screen: np.ndarray) -> bool:
165        return self._matches(current_screen, "zone_background", "in_wind_world")
def is_in_cloud_world(self, current_screen: numpy.ndarray) -> bool:
167    def is_in_cloud_world(self, current_screen: np.ndarray) -> bool:
168        return self._matches(current_screen, "zone_background", "in_cloud_world")
def is_in_evil_world(self, current_screen: numpy.ndarray) -> bool:
170    def is_in_evil_world(self, current_screen: np.ndarray) -> bool:
171        return self._matches(current_screen, "zone_background", "in_evil_world")
class BombermanQuestParser(BombermanParser):
175class BombermanQuestParser(BombermanParser):
176    VARIANT = "bomberman_quest"
177
178    MULTI_TARGET_REGIONS = [
179        ("screen_top", 0, 0, 160, 16),
180        ("dialogue_strip", 0, 12, 160, 10),
181        ("dialogue_box", 0, 12, 160, 60),
182        ("dialogue_icon", 124, 30, 31, 27),
183        ("hud_bottom", 47, 136, 33, 8),
184        ("item_select_panel", 95, 5, 65, 85),
185        ("zone_background", 0, 0, 160, 32),
186        ("book_bottom", 0, 120, 160, 20),
187        ("bottom_strip", 0, 120, 160, 24),
188        ("button_region", 80, 80, 16, 16),
189        ("switch_detector", 64, 64, 16, 16),
190        ("box_detector", 80, 64, 16, 16),
191        ("cliff_box_detector", 32, 32, 16, 16),
192        ("hard_switch_detector", 16, 16, 16, 16),
193    ]
194
195    MULTI_TARGETS = {
196        "screen_top": ["pause_menu_open", "bomb_select_open", "game_over"],
197        "dialogue_strip": ["dialogue_active"],
198        "dialogue_icon": ["sign_dialogue_active"],
199        "hud_bottom": ["battle_active"],
200        "item_select_panel": [
201            "shield_select_active",
202            "bomb_component_select_active",
203        ],
204        "zone_background": [
205            "in_camp",
206            "in_house",
207            "in_cave",
208            "in_room",
209            "in_ruins",
210            "save_npc_active",
211        ],
212        "book_bottom": ["book_read_active"],
213        "bottom_strip": [],
214        "button_region": [],
215        "switch_detector": ["switch_activated"],
216        "box_detector": [],
217        "cliff_box_detector": [],
218        "hard_switch_detector": [],
219    }
220
221    def is_in_menu(self, current_screen: np.ndarray) -> bool:
222        return self._matches(current_screen, "screen_top", "pause_menu_open")
223
224    def is_game_over(self, current_screen: np.ndarray) -> bool:
225        return self._matches(current_screen, "screen_top", "game_over")
226
227    def is_in_battle(self, current_screen: np.ndarray) -> bool:
228        return self._matches(current_screen, "hud_bottom", "battle_active")
229
230    def is_in_dialogue(self, current_screen: np.ndarray) -> bool:
231        return self._matches(current_screen, "dialogue_strip", "dialogue_active")
232
233    def is_in_npc_dialogue(self, current_screen: np.ndarray) -> bool:
234        return self.is_in_dialogue(current_screen) and not self.is_reading_sign(
235            current_screen
236        )
237
238    def is_reading_sign(self, current_screen: np.ndarray) -> bool:
239        return self._matches(current_screen, "dialogue_icon", "sign_dialogue_active")
240
241    def is_reading_book(self, current_screen: np.ndarray) -> bool:
242        return self._matches(current_screen, "book_bottom", "book_read_active")
243
244    def is_shield_select_active(self, current_screen: np.ndarray) -> bool:
245        return self._matches(current_screen, "item_select_panel", "shield_select_active")
246
247    def is_bomb_component_select_active(self, current_screen: np.ndarray) -> bool:
248        return self._matches(
249            current_screen, "item_select_panel", "bomb_component_select_active"
250        )
251
252    def is_in_camp(self, current_screen: np.ndarray) -> bool:
253        return self._matches(current_screen, "zone_background", "in_camp")
254
255    def is_in_house(self, current_screen: np.ndarray) -> bool:
256        return self._matches(current_screen, "zone_background", "in_house")
257
258    def is_in_cave(self, current_screen: np.ndarray) -> bool:
259        return self._matches(current_screen, "zone_background", "in_cave")

Abstract base class for parsing game state variables from the GameBoy emulator.

VARIANT = 'bomberman_quest'
MULTI_TARGET_REGIONS = [('screen_top', 0, 0, 160, 16), ('dialogue_strip', 0, 12, 160, 10), ('dialogue_box', 0, 12, 160, 60), ('dialogue_icon', 124, 30, 31, 27), ('hud_bottom', 47, 136, 33, 8), ('item_select_panel', 95, 5, 65, 85), ('zone_background', 0, 0, 160, 32), ('book_bottom', 0, 120, 160, 20), ('bottom_strip', 0, 120, 160, 24), ('button_region', 80, 80, 16, 16), ('switch_detector', 64, 64, 16, 16), ('box_detector', 80, 64, 16, 16), ('cliff_box_detector', 32, 32, 16, 16), ('hard_switch_detector', 16, 16, 16, 16)]
MULTI_TARGETS = {'screen_top': ['pause_menu_open', 'bomb_select_open', 'game_over'], 'dialogue_strip': ['dialogue_active'], 'dialogue_icon': ['sign_dialogue_active'], 'hud_bottom': ['battle_active'], 'item_select_panel': ['shield_select_active', 'bomb_component_select_active'], 'zone_background': ['in_camp', 'in_house', 'in_cave', 'in_room', 'in_ruins', 'save_npc_active'], 'book_bottom': ['book_read_active'], 'bottom_strip': [], 'button_region': [], 'switch_detector': ['switch_activated'], 'box_detector': [], 'cliff_box_detector': [], 'hard_switch_detector': []}
def is_in_menu(self, current_screen: numpy.ndarray) -> bool:
221    def is_in_menu(self, current_screen: np.ndarray) -> bool:
222        return self._matches(current_screen, "screen_top", "pause_menu_open")
def is_game_over(self, current_screen: numpy.ndarray) -> bool:
224    def is_game_over(self, current_screen: np.ndarray) -> bool:
225        return self._matches(current_screen, "screen_top", "game_over")
def is_in_battle(self, current_screen: numpy.ndarray) -> bool:
227    def is_in_battle(self, current_screen: np.ndarray) -> bool:
228        return self._matches(current_screen, "hud_bottom", "battle_active")
def is_in_dialogue(self, current_screen: numpy.ndarray) -> bool:
230    def is_in_dialogue(self, current_screen: np.ndarray) -> bool:
231        return self._matches(current_screen, "dialogue_strip", "dialogue_active")
def is_in_npc_dialogue(self, current_screen: numpy.ndarray) -> bool:
233    def is_in_npc_dialogue(self, current_screen: np.ndarray) -> bool:
234        return self.is_in_dialogue(current_screen) and not self.is_reading_sign(
235            current_screen
236        )
def is_reading_sign(self, current_screen: numpy.ndarray) -> bool:
238    def is_reading_sign(self, current_screen: np.ndarray) -> bool:
239        return self._matches(current_screen, "dialogue_icon", "sign_dialogue_active")
def is_reading_book(self, current_screen: numpy.ndarray) -> bool:
241    def is_reading_book(self, current_screen: np.ndarray) -> bool:
242        return self._matches(current_screen, "book_bottom", "book_read_active")
def is_shield_select_active(self, current_screen: numpy.ndarray) -> bool:
244    def is_shield_select_active(self, current_screen: np.ndarray) -> bool:
245        return self._matches(current_screen, "item_select_panel", "shield_select_active")
def is_bomb_component_select_active(self, current_screen: numpy.ndarray) -> bool:
247    def is_bomb_component_select_active(self, current_screen: np.ndarray) -> bool:
248        return self._matches(
249            current_screen, "item_select_panel", "bomb_component_select_active"
250        )
def is_in_camp(self, current_screen: numpy.ndarray) -> bool:
252    def is_in_camp(self, current_screen: np.ndarray) -> bool:
253        return self._matches(current_screen, "zone_background", "in_camp")
def is_in_house(self, current_screen: numpy.ndarray) -> bool:
255    def is_in_house(self, current_screen: np.ndarray) -> bool:
256        return self._matches(current_screen, "zone_background", "in_house")
def is_in_cave(self, current_screen: numpy.ndarray) -> bool:
258    def is_in_cave(self, current_screen: np.ndarray) -> bool:
259        return self._matches(current_screen, "zone_background", "in_cave")