gameboy_worlds.emulation.deja_vu.emulators

 1from gameboy_worlds.emulation.emulator import Emulator, LowLevelActions
 2from gameboy_worlds.emulation.deja_vu.parsers import DejaVuStateParser, AgentState
 3from gameboy_worlds.emulation.deja_vu.trackers import CoreDejaVuTracker
 4from gameboy_worlds.utils import log_error
 5from typing import Tuple
 6import numpy as np
 7
 8
 9class DejaVuEmulator(Emulator):
10    """
11    Deja Vu-specific emulator adapter.
12
13    Handles Deja Vu game-specific logic:
14    - Menu navigation and investigation system
15    - Dialogue and clue collection
16    - Puzzle-solving phases
17    """
18
19    REQUIRED_STATE_PARSER = DejaVuStateParser
20    REQUIRED_STATE_TRACKER = CoreDejaVuTracker
21    _MAXIMUM_DIALOGUE_PRESSES = 2000  # For now set a crazy high value
22    """ Maximum number of times the agent will click B to get through a dialogue. """
23    _SKIP_DIALOGUE = False
24    """ Whether to auto skip dialogue by clicking B repeatedly until we are no longer in dialogue."""
25
26    def step(self, action=None) -> Tuple[np.ndarray, bool]:
27        """
28        Execute one game step with Deja Vu-specific handling.
29
30        Handles dialogue auto-skip to speed up gameplay while preserving investigation mechanics.
31
32        Args:
33            action: The action to execute (can be None for no action)
34
35        Returns:
36            Tuple of (frames, done): frames from the step, and whether episode ended
37        """
38        frames, done = super().step(action)
39        self.state_parser: DejaVuStateParser
40        current_frame = self.get_current_frame()
41
42        all_next_frames = [frames]
43        if self._SKIP_DIALOGUE:
44            # Auto-skip dialogue to accelerate game progression
45            # This allows the agent to move through story elements faster
46            # For Deja Vu, dialogue is critical to story progression and investigations, so we initialize the auto-skip action to false
47            current_state = self.state_parser.get_agent_state(current_frame)
48            n_clicks = 0
49            # Clicks through any dialogue popups
50            while (
51                n_clicks < self._MAXIMUM_DIALOGUE_PRESSES
52                and current_state == AgentState.IN_DIALOGUE
53            ):
54                next_frames = self.run_action_on_emulator(
55                    LowLevelActions.PRESS_BUTTON_A
56                )
57                current_state = self.state_parser.get_agent_state(next_frames[-1])
58                all_next_frames.append(next_frames)
59                n_clicks += 1
60
61        if len(all_next_frames) > 1:
62            frames = np.concatenate(all_next_frames)
63            self._update_listeners_after_actions(
64                self._get_unique_frames(frames[1:])
65            )  # Skip the first frame as that is already counted
66            frames = self._get_unique_frames(frames)
67
68        return frames, done
69
70    def _open_to_first_state(self):
71        self._pyboy.tick(10000, False)  # get to opening menu
72        self.run_action_on_emulator(
73            LowLevelActions.PRESS_BUTTON_A
74        )  # press A to get past opening menu
75        self._pyboy.tick(1000, False)  # wait for load
76        self.run_action_on_emulator(
77            LowLevelActions.PRESS_BUTTON_A
78        )  # press A to load game
79        self._pyboy.tick(1000, False)  # wait for file select
80        self.run_action_on_emulator(
81            LowLevelActions.PRESS_BUTTON_A
82        )  # press A to confirm load
83        self._pyboy.tick(5000, False)  # wait for game to load
class DejaVuEmulator(gameboy_worlds.emulation.emulator.Emulator):
10class DejaVuEmulator(Emulator):
11    """
12    Deja Vu-specific emulator adapter.
13
14    Handles Deja Vu game-specific logic:
15    - Menu navigation and investigation system
16    - Dialogue and clue collection
17    - Puzzle-solving phases
18    """
19
20    REQUIRED_STATE_PARSER = DejaVuStateParser
21    REQUIRED_STATE_TRACKER = CoreDejaVuTracker
22    _MAXIMUM_DIALOGUE_PRESSES = 2000  # For now set a crazy high value
23    """ Maximum number of times the agent will click B to get through a dialogue. """
24    _SKIP_DIALOGUE = False
25    """ Whether to auto skip dialogue by clicking B repeatedly until we are no longer in dialogue."""
26
27    def step(self, action=None) -> Tuple[np.ndarray, bool]:
28        """
29        Execute one game step with Deja Vu-specific handling.
30
31        Handles dialogue auto-skip to speed up gameplay while preserving investigation mechanics.
32
33        Args:
34            action: The action to execute (can be None for no action)
35
36        Returns:
37            Tuple of (frames, done): frames from the step, and whether episode ended
38        """
39        frames, done = super().step(action)
40        self.state_parser: DejaVuStateParser
41        current_frame = self.get_current_frame()
42
43        all_next_frames = [frames]
44        if self._SKIP_DIALOGUE:
45            # Auto-skip dialogue to accelerate game progression
46            # This allows the agent to move through story elements faster
47            # For Deja Vu, dialogue is critical to story progression and investigations, so we initialize the auto-skip action to false
48            current_state = self.state_parser.get_agent_state(current_frame)
49            n_clicks = 0
50            # Clicks through any dialogue popups
51            while (
52                n_clicks < self._MAXIMUM_DIALOGUE_PRESSES
53                and current_state == AgentState.IN_DIALOGUE
54            ):
55                next_frames = self.run_action_on_emulator(
56                    LowLevelActions.PRESS_BUTTON_A
57                )
58                current_state = self.state_parser.get_agent_state(next_frames[-1])
59                all_next_frames.append(next_frames)
60                n_clicks += 1
61
62        if len(all_next_frames) > 1:
63            frames = np.concatenate(all_next_frames)
64            self._update_listeners_after_actions(
65                self._get_unique_frames(frames[1:])
66            )  # Skip the first frame as that is already counted
67            frames = self._get_unique_frames(frames)
68
69        return frames, done
70
71    def _open_to_first_state(self):
72        self._pyboy.tick(10000, False)  # get to opening menu
73        self.run_action_on_emulator(
74            LowLevelActions.PRESS_BUTTON_A
75        )  # press A to get past opening menu
76        self._pyboy.tick(1000, False)  # wait for load
77        self.run_action_on_emulator(
78            LowLevelActions.PRESS_BUTTON_A
79        )  # press A to load game
80        self._pyboy.tick(1000, False)  # wait for file select
81        self.run_action_on_emulator(
82            LowLevelActions.PRESS_BUTTON_A
83        )  # press A to confirm load
84        self._pyboy.tick(5000, False)  # wait for game to load

Deja Vu-specific emulator adapter.

Handles Deja Vu game-specific logic:

  • Menu navigation and investigation system
  • Dialogue and clue collection
  • Puzzle-solving phases

The minimal functionality StateParser needed for this emulator to run

The minimal functionality StateTracker needed for this emulator to run

def step(self, action=None) -> Tuple[numpy.ndarray, bool]:
27    def step(self, action=None) -> Tuple[np.ndarray, bool]:
28        """
29        Execute one game step with Deja Vu-specific handling.
30
31        Handles dialogue auto-skip to speed up gameplay while preserving investigation mechanics.
32
33        Args:
34            action: The action to execute (can be None for no action)
35
36        Returns:
37            Tuple of (frames, done): frames from the step, and whether episode ended
38        """
39        frames, done = super().step(action)
40        self.state_parser: DejaVuStateParser
41        current_frame = self.get_current_frame()
42
43        all_next_frames = [frames]
44        if self._SKIP_DIALOGUE:
45            # Auto-skip dialogue to accelerate game progression
46            # This allows the agent to move through story elements faster
47            # For Deja Vu, dialogue is critical to story progression and investigations, so we initialize the auto-skip action to false
48            current_state = self.state_parser.get_agent_state(current_frame)
49            n_clicks = 0
50            # Clicks through any dialogue popups
51            while (
52                n_clicks < self._MAXIMUM_DIALOGUE_PRESSES
53                and current_state == AgentState.IN_DIALOGUE
54            ):
55                next_frames = self.run_action_on_emulator(
56                    LowLevelActions.PRESS_BUTTON_A
57                )
58                current_state = self.state_parser.get_agent_state(next_frames[-1])
59                all_next_frames.append(next_frames)
60                n_clicks += 1
61
62        if len(all_next_frames) > 1:
63            frames = np.concatenate(all_next_frames)
64            self._update_listeners_after_actions(
65                self._get_unique_frames(frames[1:])
66            )  # Skip the first frame as that is already counted
67            frames = self._get_unique_frames(frames)
68
69        return frames, done

Execute one game step with Deja Vu-specific handling.

Handles dialogue auto-skip to speed up gameplay while preserving investigation mechanics.

Arguments:
  • action: The action to execute (can be None for no action)
Returns:

Tuple of (frames, done): frames from the step, and whether episode ended