Пример #1
0
    def __init__(self, player: StreamPlayerAbstract, snd_obj: Any, name: str):
        super(SoundPreview, self).__init__()

        self.sprite_loader = RomSingleton().get_sprite_loader()
        self.sprite_loader_os = pge.SpriteLoaderOS(
            base_path_os="data_permanent/sprites")
        self.font_loader = RomSingleton().get_font_loader()

        self.now_playing_text = pge.Text(
            position=[0, -10],
            center=[pge.Alignment.CENTER, pge.Alignment.BOTTOM],
            scale=[0.7, 0.7])
        self.font_loader.load("font_event", 12, self.now_playing_text)
        self.now_playing_text.text = "Now playing:"

        self.track_name = pge.Text(
            position=[0, 10], center=[pge.Alignment.CENTER, pge.Alignment.TOP])
        self.font_loader.load("font_event", 12, self.track_name)
        self.track_name.text = name.replace("\\", "/").split("/")[-1]

        self.explanation_text = pge.Text(position=[0, -50])
        self.font_loader.load("font_event", 12, self.explanation_text)
        self.explanation_text.text = "Touch the headphones to play"

        self.play_btn = pge.Button(pressed_counter=0.09)
        self.sprite_loader_os.load("headphones_play.png",
                                   self.play_btn,
                                   sprite_sheet=True,
                                   convert_alpha=False)
        self.play_btn.color_key = pg.Color(0, 255, 0)

        self.volume_slider = pge.Slider(min_value=0,
                                        max_value=1,
                                        start_value=0.5)
        self.sprite_loader_os.load("slider_main.png",
                                   self.volume_slider,
                                   sprite_sheet=False)
        self.sprite_loader_os.load("slider_ball.png",
                                   self.volume_slider.child,
                                   sprite_sheet=False)
        self.volume_slider.center = [
            pge.Alignment.CENTER, pge.Alignment.BOTTOM
        ]
        self.volume_slider.position[1] = 192 // 2 - 20

        self.player: StreamPlayerAbstract = player
        self.player.set_volume(0.5)
        self.snd_obj: Any = snd_obj
        self.playing = False
        if self.check_playable():
            self.explanation_text.text = "Touch the headphones to play"
            self.play_btn.set_tag("OFF")
        else:
            self.explanation_text.text = "Missing dependencies"
            self.play_btn.set_tag("CAN'T BE PLAYED")
Пример #2
0
    def __init__(self, event: Event):
        super(EventPlayer, self).__init__()
        self.event = event
        self.current_command = 0
        self.next_voice = -1
        self.next_dialogue_sfx = -1

        self.sprite_loader = RomSingleton().get_sprite_loader()
        self.font_loader = RomSingleton().get_font_loader()

        self.top_bg = EventBG("top")
        self.sprite_loader.load(
            f"data_lt2/bg/event/sub{self.event.map_top_id}.arc",
            self.top_bg.bg,
            sprite_sheet=False)
        self.top_bg.fade(2, None, True)
        self.top_bg.set_opacity(0)
        self.btm_bg = EventBG("btm")
        self.sprite_loader.load(
            f"data_lt2/bg/map/main{self.event.map_bottom_id}.arc",
            self.btm_bg.bg,
            sprite_sheet=False)
        self.btm_bg.set_opacity(120)
        self.btm_bg.fade(2, None, True)

        self.waiter = EventWaiter()
        self.event_sound = EventSound()

        self.characters: List[Optional[EventCharacter]] = [None] * 8

        for i in range(8):
            if self.event.characters[i] == 0:
                continue
            char_id = self.event.characters[i]
            slot = self.event.characters_pos[i]
            anim = self.event.characters_anim_index[i]
            visibility = self.event.characters_shown[i]
            char = EventCharacter(char_id, slot, anim, visibility,
                                  self.sprite_loader)
            self.characters[i] = char

        self.dialogue = EventDialogue(
            self,
            position=[0, 192 // 2 + 3],
            center=[pge.Alignment.CENTER, pge.Alignment.BOTTOM])
        self.sprite_loader.load("data_lt2/ani/event/twindow.ani",
                                self.dialogue)
        self.dialogue.init_text(self.font_loader)

        self.inp = pge.Input()
        self.wait_tap = False

        self.run_events_until_busy()
Пример #3
0
    def open_rom(self, rom: Union[NintendoDSRom, BinaryIO, bytes, str,
                                  ndspy.rom.NintendoDSRom]):
        rom_last_filename = self.rom_last_filename
        if isinstance(rom, str):  # Filename
            rom_last_filename = rom
            rom = NintendoDSRom.fromFile(rom)
        elif isinstance(rom, BinaryIO):  # File
            rom = NintendoDSRom(rom.read())
        elif isinstance(rom, bytes):  # Raw bytes
            rom = NintendoDSRom(rom)
        elif isinstance(rom, ndspy.rom.NintendoDSRom):
            rom = NintendoDSRom(rom.save())
        elif isinstance(rom, NintendoDSRom):
            rom = rom

        # Load language from arm9
        if rom.name == b"LAYTON2":
            arm9 = rom.loadArm9()
            lang_address = 0x02000d3c - arm9.ramAddress
            lang_id = rom.arm9[lang_address]
            lang_table = ["jp", "en", "sp", "fr", "it", "ge", "du", "ko", "ch"]
            try:
                conf.LANG = lang_table[lang_id]
            except IndexError:  # US version?
                # TODO: Figure out how to read it properly
                conf.LANG = "en"
            print(f"Game language: {conf.LANG}")
            if conf.LANG == "jp":
                error_dialog = wx.MessageDialog(
                    self,
                    "Japanese is not currently supported",
                    style=wx.ICON_ERROR | wx.OK)
                error_dialog.ShowModal()
                return
        else:
            warning_game_dialog = wx.MessageDialog(
                self, "Warning: LaytonEditor is specifically made to edit "
                "Layton 2, and support with other games is not guaranteed.",
                style=wx.ICON_WARNING | wx.OK)
            warning_game_dialog.ShowModal()
            conf.LANG = "en"

        # After checking language
        self.rom = rom
        self.rom_last_filename = rom_last_filename

        RomSingleton(rom=self.rom)

        # Only open the main filesystem page.
        self.le_editor_pages.DeleteAllPages()
        menus_to_remove = []
        for menu in self.le_menu.Menus:
            if menu[1] != "File":
                menus_to_remove.append(menu[1])
        for menu_to_remove in menus_to_remove:
            self.remove_menu(menu_to_remove)
        self.open_filesystem_page("Rom FS")
Пример #4
0
class SoundPreview(TwoScreenRenderer):
    def __init__(self, player: StreamPlayerAbstract, snd_obj: Any, name: str):
        super(SoundPreview, self).__init__()

        self.sprite_loader = RomSingleton().get_sprite_loader()
        self.sprite_loader_os = pge.SpriteLoaderOS(
            base_path_os="data_permanent/sprites")
        self.font_loader = RomSingleton().get_font_loader()

        self.now_playing_text = pge.Text(
            position=[0, -10],
            center=[pge.Alignment.CENTER, pge.Alignment.BOTTOM],
            scale=[0.7, 0.7])
        self.font_loader.load("font_event", 12, self.now_playing_text)
        self.now_playing_text.text = "Now playing:"

        self.track_name = pge.Text(
            position=[0, 10], center=[pge.Alignment.CENTER, pge.Alignment.TOP])
        self.font_loader.load("font_event", 12, self.track_name)
        self.track_name.text = name.replace("\\", "/").split("/")[-1]

        self.explanation_text = pge.Text(position=[0, -50])
        self.font_loader.load("font_event", 12, self.explanation_text)
        self.explanation_text.text = "Touch the headphones to play"

        self.play_btn = pge.Button(pressed_counter=0.09)
        self.sprite_loader_os.load("headphones_play.png",
                                   self.play_btn,
                                   sprite_sheet=True,
                                   convert_alpha=False)
        self.play_btn.color_key = pg.Color(0, 255, 0)

        self.volume_slider = pge.Slider(min_value=0,
                                        max_value=1,
                                        start_value=0.5)
        self.sprite_loader_os.load("slider_main.png",
                                   self.volume_slider,
                                   sprite_sheet=False)
        self.sprite_loader_os.load("slider_ball.png",
                                   self.volume_slider.child,
                                   sprite_sheet=False)
        self.volume_slider.center = [
            pge.Alignment.CENTER, pge.Alignment.BOTTOM
        ]
        self.volume_slider.position[1] = 192 // 2 - 20

        self.player: StreamPlayerAbstract = player
        self.player.set_volume(0.5)
        self.snd_obj: Any = snd_obj
        self.playing = False
        if self.check_playable():
            self.explanation_text.text = "Touch the headphones to play"
            self.play_btn.set_tag("OFF")
        else:
            self.explanation_text.text = "Missing dependencies"
            self.play_btn.set_tag("CAN'T BE PLAYED")

    def unload(self):
        super(SoundPreview, self).unload()
        self.now_playing_text.unload()
        self.track_name.unload()
        self.explanation_text.unload()
        self.play_btn.unload()
        self.player.stop()

    def check_playable(self):
        return self.player.get_playable()

    def toggle_sound(self):
        if not self.check_playable():
            return
        if self.playing:
            self.stop_sound()
        else:
            self.start_sound()

    def start_sound(self):
        self.play_btn.set_tag("ON")
        if self.snd_obj and not self.playing:
            self.playing = True
            self.player.start_sound(self.snd_obj)

    def stop_sound(self):
        self.play_btn.set_tag("OFF")
        self.playing = False
        self.player.stop()

    def update(self, dt: float):
        if self.play_btn.pressed(self.btm_camera, dt):
            self.toggle_sound()
        self.play_btn.animate(dt)
        self.player.update_(dt)

    def draw(self):
        self.top_camera.surf.fill((40, 40, 40))
        self.now_playing_text.draw(self.top_camera)
        self.track_name.draw(self.top_camera)
        self.play_btn.draw(self.btm_camera)
        self.explanation_text.draw(self.btm_camera)
        slider_value, changed = self.volume_slider.get_value(self.btm_camera)
        if changed:
            self.player.set_volume(slider_value)
        self.volume_slider.draw(self.btm_camera)
Пример #5
0
    def __init__(self, place: Place):
        super(PlacePreview, self).__init__()
        self.place = place

        self.sprite_loader = RomSingleton().get_sprite_loader()
        self.font_loader = RomSingleton().get_font_loader()
        self.inp = pge.Input()

        self.top_bg = pge.Sprite()
        self.sprite_loader.load(
            f"data_lt2/bg/map/map{self.place.map_image_index}",
            self.top_bg,
            sprite_sheet=False,
            convert_alpha=False)
        self.btm_bg = pge.Sprite()
        self.sprite_loader.load(
            f"data_lt2/bg/map/main{self.place.background_image_index}",
            self.btm_bg,
            sprite_sheet=False,
            convert_alpha=False)
        self.map_icon = pge.Sprite(
            position=[
                self.place.map_x - 256 // 2, self.place.map_y - 192 // 2
            ],
            center=[pge.Alignment.LEFT, pge.Alignment.TOP])
        self.sprite_loader.load(f"data_lt2/ani/map/mapicon.arj",
                                self.map_icon,
                                sprite_sheet=True,
                                convert_alpha=False)

        self.move_mode = False
        self.move_button = pge.Button(
            position=[256 // 2 - 3, 192 // 2 - 3],
            center=[pge.Alignment.RIGHT, pge.Alignment.BOTTOM],
            pressed_tag="on",
            not_pressed_tag="off")
        self.sprite_loader.load(f"data_lt2/ani/map/movemode.arc",
                                self.move_button,
                                sprite_sheet=True,
                                convert_alpha=False)

        self.bgm = SMDLStreamPlayer()

        self.sprites = []
        self.objects = []
        self.exits = []

        for sprite_obj in self.place.sprites:
            if sprite_obj.filename == "":
                continue
            sprite = pge.Sprite(
                position=[sprite_obj.x - 256 // 2, sprite_obj.y - 192 // 2],
                center=[pge.Alignment.LEFT, pge.Alignment.TOP],
                color_key=pg.Color(0, 255, 0))
            self.sprite_loader.load(
                f"data_lt2/ani/bgani/{sprite_obj.filename}",
                sprite,
                sprite_sheet=True,
                convert_alpha=False)
            sprite.set_tag("gfx")
            self.sprites.append(sprite)

        for object_obj in self.place.objects:
            if object_obj.width <= 0:
                continue
            obj = pge.Sprite(
                position=[object_obj.x - 256 // 2, object_obj.y - 192 // 2],
                center=[pge.Alignment.LEFT, pge.Alignment.TOP],
                color_key=pg.Color(0, 255, 0))
            if object_obj.character_index != 0:
                self.sprite_loader.load(
                    f"data_lt2/ani/eventobj/obj_{object_obj.character_index}.arc",
                    obj,
                    sprite_sheet=True,
                    convert_alpha=False)
                obj.set_tag("gfx")
            self.objects.append(obj)

        for exit_obj in self.place.exits:
            if exit_obj.width <= 0:
                continue
            exit_ = FadeInOutBtn(
                position=[exit_obj.x - 256 // 2, exit_obj.y - 192 // 2],
                center=[pge.Alignment.LEFT, pge.Alignment.TOP],
                color_key=pg.Color(0, 255, 0),
                pressed_tag="gfx2",
                not_pressed_tag="gfx")
            self.sprite_loader.load(
                f"data_lt2/ani/map/exit_{exit_obj.image_index}.arc",
                exit_,
                sprite_sheet=True,
                convert_alpha=False)
            self.exits.append(exit_)
Пример #6
0
    def __init__(self, puzzle_data: pzd.Puzzle):
        super(PuzzlePlayer, self).__init__()

        self.hints_used = 0
        self.selected_hint = 0
        self.text_pos = 0
        self.between_letters = 0.017
        self.current_between_letters = 0.0
        self.on_hints = False
        self.puzzle_data = puzzle_data

        self.inp = pge.Input()

        self.sprite_loader: pge.SpriteLoader = RomSingleton(
        ).get_sprite_loader()
        self.font_loader: pge.FontLoader = RomSingleton().get_font_loader()

        self.top_bg = pge.Sprite()
        self.sprite_loader.load(
            f"data_lt2/bg/nazo/system/nazo_text{puzzle_data.bg_top_id}.arc",
            self.top_bg,
            sprite_sheet=False)

        self.btm_bg = pge.Sprite()
        if not puzzle_data.bg_lang:
            self.sprite_loader.load(
                f"data_lt2/bg/nazo/q{puzzle_data.internal_id}.arc",
                self.btm_bg,
                sprite_sheet=False)
        else:
            self.sprite_loader.load(
                f"data_lt2/bg/nazo/?/q{puzzle_data.internal_id}.arc",
                self.btm_bg,
                sprite_sheet=False)

        self.top_text = pge.Text(
            position=[-256 // 2 + 8, -192 // 2 + 23],
            center=[pge.Alignment.LEFT, pge.Alignment.TOP],
            color=pg.Color(0, 0, 0),
            line_spacing=2)
        self.font_loader.load("fontq", 10, self.top_text)

        self.header_top_left = []
        for i in range(4):
            header_item = pge.Sprite(
                center=[pge.Alignment.TOP, pge.Alignment.LEFT])
            self.sprite_loader.load(
                f"data_lt2/ani/nazo/system/?/nazo_text.arc",
                header_item,
                sprite_sheet=True)
            if i == 0:
                header_item.set_tag("nazo")
                header_item.position = [-256 // 2 + 5, -192 // 2 + 4]
            else:
                i -= 1
                p_num = puzzle_data.number
                for a in range(2 - i):
                    p_num //= 10
                header_item.set_tag(str(p_num % 10))
                header_item.position = [-256 // 2 + 23 + i * 7, -192 // 2 + 5]
            self.header_top_left.append(header_item)

        self.hint_bg = pge.Sprite()

        btn_off = "off"
        btn_on = "on"

        current_y = -192 // 2
        self.hints_btn = pge.Button(
            center=[pge.Alignment.RIGHT, pge.Alignment.TOP],
            position=[256 // 2, current_y],
            not_pressed_tag="0_off",
            pressed_tag="0_on")
        self.sprite_loader.load("data_lt2/ani/system/btn/?/hint.arc",
                                self.hints_btn,
                                sprite_sheet=True)

        current_y += self.hints_btn.get_world_rect().h
        self.quit_btn = pge.Button(
            center=[pge.Alignment.RIGHT, pge.Alignment.TOP],
            position=[256 // 2, current_y],
            not_pressed_tag=btn_off,
            pressed_tag=btn_on)
        self.sprite_loader.load("data_lt2/ani/system/btn/?/atode.arc",
                                self.quit_btn,
                                sprite_sheet=True)

        current_y += self.quit_btn.get_world_rect().h
        self.memo_btn = pge.Button(
            center=[pge.Alignment.RIGHT, pge.Alignment.TOP],
            position=[256 // 2, current_y],
            not_pressed_tag=btn_off,
            pressed_tag=btn_on)
        self.sprite_loader.load("data_lt2/ani/system/btn/?/memo.arc",
                                self.memo_btn,
                                sprite_sheet=True)

        self.submit_btn = pge.Button(
            center=[pge.Alignment.RIGHT, pge.Alignment.BOTTOM],
            position=[256 // 2, 192 // 2],
            not_pressed_tag=btn_off,
            pressed_tag=btn_on)
        self.sprite_loader.load("data_lt2/ani/system/btn/?/hantei.arc",
                                self.submit_btn,
                                sprite_sheet=True)

        self.hint_back = pge.Button(
            position=[256 // 2, -192 // 2],
            center=[pge.Alignment.RIGHT, pge.Alignment.TOP],
            not_pressed_tag=btn_off,
            pressed_tag=btn_on)
        self.sprite_loader.load("data_lt2/ani/system/btn/?/modoru_memo.arc",
                                self.hint_back,
                                sprite_sheet=True)

        self.hint_unlock = pge.Button(
            position=[-80, 40],
            center=[pge.Alignment.LEFT, pge.Alignment.TOP],
            not_pressed_tag=btn_off,
            pressed_tag=btn_on)
        self.sprite_loader.load("data_lt2/ani/system/btn/?/yes.arc",
                                self.hint_unlock,
                                sprite_sheet=True)

        self.hint_no_unlock = pge.Button(
            position=[80, 40],
            center=[pge.Alignment.RIGHT, pge.Alignment.TOP],
            not_pressed_tag=btn_off,
            pressed_tag=btn_on)
        self.sprite_loader.load("data_lt2/ani/system/btn/?/no.arc",
                                self.hint_no_unlock,
                                sprite_sheet=True)

        self.hint_text = pge.Text(
            position=[-256 // 2 + 20, -192 // 2 + 42],
            center=[pge.Alignment.LEFT, pge.Alignment.TOP],
            color=pg.Color(0, 0, 0))
        self.font_loader.load("fontq", 10, self.hint_text)

        self.hint_selected: List[pge.Button] = []

        current_x = -256 // 2 + 8
        for i in range(3):
            hint_select = pge.Button(
                position=[current_x, -192 // 2 + 4],
                center=[pge.Alignment.LEFT, pge.Alignment.TOP],
                not_pressed_tag="OFF",
                pressed_tag="ON")
            hint_select.visible = False
            self.sprite_loader.load(
                f"data_lt2/ani/nazo/system/?/hint{i + 1}.arc",
                hint_select,
                sprite_sheet=True)
            current_x += hint_select.get_world_rect().w + 1
            self.hint_selected.append(hint_select)

        self.view_hint(self.progress_hints(set_hint=0))

        smd, presets = load_smd("data_lt2/sound/BG_035.SMD")
        self.puzzle_bg_music = SMDLStreamPlayer()
        self.puzzle_bg_music.set_preset_dict(presets)
        self.puzzle_bg_music.start_sound(smd, loops=-1)
Пример #7
0
class EventPlayer(TwoScreenRenderer):
    def __init__(self, event: Event):
        super(EventPlayer, self).__init__()
        self.event = event
        self.current_command = 0
        self.next_voice = -1
        self.next_dialogue_sfx = -1

        self.sprite_loader = RomSingleton().get_sprite_loader()
        self.font_loader = RomSingleton().get_font_loader()

        self.top_bg = EventBG("top")
        self.sprite_loader.load(
            f"data_lt2/bg/event/sub{self.event.map_top_id}.arc",
            self.top_bg.bg,
            sprite_sheet=False)
        self.top_bg.fade(2, None, True)
        self.top_bg.set_opacity(0)
        self.btm_bg = EventBG("btm")
        self.sprite_loader.load(
            f"data_lt2/bg/map/main{self.event.map_bottom_id}.arc",
            self.btm_bg.bg,
            sprite_sheet=False)
        self.btm_bg.set_opacity(120)
        self.btm_bg.fade(2, None, True)

        self.waiter = EventWaiter()
        self.event_sound = EventSound()

        self.characters: List[Optional[EventCharacter]] = [None] * 8

        for i in range(8):
            if self.event.characters[i] == 0:
                continue
            char_id = self.event.characters[i]
            slot = self.event.characters_pos[i]
            anim = self.event.characters_anim_index[i]
            visibility = self.event.characters_shown[i]
            char = EventCharacter(char_id, slot, anim, visibility,
                                  self.sprite_loader)
            self.characters[i] = char

        self.dialogue = EventDialogue(
            self,
            position=[0, 192 // 2 + 3],
            center=[pge.Alignment.CENTER, pge.Alignment.BOTTOM])
        self.sprite_loader.load("data_lt2/ani/event/twindow.ani",
                                self.dialogue)
        self.dialogue.init_text(self.font_loader)

        self.inp = pge.Input()
        self.wait_tap = False

        self.run_events_until_busy()

    def run_events_until_busy(self):
        while True:
            if self.current_command >= len(self.event.gds.commands):
                return
            command = self.event.gds.commands[self.current_command]
            self.current_command += 1

            self.execute_gds_command(command)

            if self.is_busy():
                return

    def execute_gds_command(self, command: gds.GDSCommand):
        fade_out = 1
        fade_in = 2
        if command.command == 0x2:
            self.top_bg.fade(fade_in, None, False)
            self.btm_bg.fade(fade_in, None, False)
        elif command.command == 0x3:
            self.top_bg.fade(fade_out, None, False)
            self.btm_bg.fade(fade_out, None, False)
        elif command.command == 0x4:
            if len(command.params) == 0:
                return
            dialogue_gds = self.event.get_text(command.params[0])
            if len(dialogue_gds.params) != 5:
                return
            character = None
            for char in self.characters:
                if char is None:
                    continue
                if char.get_char_id() == dialogue_gds.params[0]:
                    character = char
                    break
            self.dialogue.start_dialogue(character, dialogue_gds.params[1],
                                         dialogue_gds.params[4],
                                         self.next_voice,
                                         self.next_dialogue_sfx,
                                         self.sprite_loader)
            self.next_voice = -1
            self.next_dialogue_sfx = -1
        elif command.command == 0x21:
            bg_path = command.params[0]
            self.sprite_loader.load(f"data_lt2/bg/{bg_path}",
                                    self.btm_bg.bg,
                                    sprite_sheet=False)
            self.btm_bg.set_opacity(0)
        elif command.command == 0x22:
            bg_path = command.params[0]
            self.sprite_loader.load(f"data_lt2/bg/{bg_path}",
                                    self.top_bg.bg,
                                    sprite_sheet=False)
            self.top_bg.set_opacity(0)
        elif command.command == 0x2a:
            self.characters[command.params[0]].show()
        elif command.command == 0x2b:
            self.characters[command.params[0]].hide()
        elif command.command == 0x2c:
            # Still not clue about why it works like this
            if command.params[0] < 8:
                self.characters[command.params[0]].set_visibility(
                    command.params[1] > 0)
        elif command.command == 0x30:
            self.characters[command.params[0]].set_slot(command.params[1])
        elif command.command == 0x31:
            self.waiter.wait(command.params[0])
        elif command.command == 0x32:
            self.btm_bg.fade(fade_in, None, False)
        elif command.command == 0x33:
            self.btm_bg.fade(fade_out, None, False)
        elif command.command == 0x37:
            self.btm_bg.set_opacity(command.params[3])
        elif command.command == 0x3f:
            character = None
            for char in self.characters:
                if char is None:
                    continue
                if char.get_char_id() == command.params[0]:
                    character = char
                    break
            if character:
                character.set_anim(command.params[1])
        elif command.command == 0x5c:
            self.next_voice = command.params[0]
        elif command.command == 0x5d:
            self.event_sound.play_sadl(
                f"data_lt2/stream/ST_{str(command.params[0]).zfill(3)}.SAD")
        elif command.command == 0x62:
            self.event_sound.play_smdl(
                f"data_lt2/sound/BG_{str(command.params[0]).zfill(3)}.SMD")
        elif command.command == 0x69:
            self.wait_tap = True
        elif command.command == 0x6a:
            self.btm_bg.shake()
        elif command.command == 0x71:
            # Something about mysteries -> hides all character
            for char in self.characters:
                if char:
                    char.hide()
        elif command.command == 0x72:
            self.top_bg.fade(fade_out, command.params[0], False)
            self.btm_bg.fade(fade_out, command.params[0], False)
        elif command.command == 0x80:
            self.top_bg.fade(fade_in, command.params[0], False)
            self.btm_bg.fade(fade_in, command.params[0], False)
        elif command.command == 0x87:
            self.top_bg.fade(fade_out, command.params[0], False)
        elif command.command == 0x88:
            self.top_bg.fade(fade_in, command.params[0], False)
        elif command.command == 0x8a:
            self.event_sound.fade(False, command.params[1])
        elif command.command == 0x8b:
            self.event_sound.fade(True, command.params[0])
        elif command.command == 0x99:
            self.next_dialogue_sfx = command.params[0]
        else:
            print(
                f"[EventPlayer]    Command {hex(command.command)} not recognised (skipped). "
            )

    def execute_str_command(self, command):
        print(command)
        command_split = command.split(" ")
        if command_split[0] == "setani":
            try:
                int(command_split[1])
            except ValueError:
                return
            character = None
            for char in self.characters:
                char: EventCharacter
                if char.get_char_id() == int(command_split[1]):
                    character = char
                    break
            if character:
                character.set_anim(command_split[2].replace("_", " "))

    def update(self, dt: float):
        for character in self.characters:
            if character is not None:
                character.update_fade(dt)
        self.waiter.update_(dt)
        self.event_sound.update_(dt)
        self.top_bg.update_(dt)
        self.btm_bg.update_(dt)
        self.dialogue.interact(self.btm_camera, dt)
        for character in self.characters:
            if character:
                character.animate(dt)
        if self.wait_tap:
            if self.inp.get_mouse_down(1):
                self.wait_tap = False
        if not self.is_busy():
            self.run_events_until_busy()

    def draw(self):
        self.top_bg.draw_back(self.top_camera)
        self.top_bg.draw_front(self.top_camera)

        self.btm_bg.draw_back(self.btm_camera)
        for character in self.characters:
            if character:
                character.draw(self.btm_camera)
        self.dialogue.draw(self.btm_camera)
        self.btm_bg.draw_front(self.btm_camera)

    def unload(self):
        self.top_bg.unload()
        self.btm_bg.unload()
        for character in self.characters:
            if character:
                character.unload()
        self.dialogue.unload()
        self.event_sound.stop_smdl()
        self.event_sound.stop_sadl()

    def is_busy(self):
        for character in self.characters:
            if character is not None:
                if character.busy():
                    return True
        return self.top_bg.busy() or self.btm_bg.busy() or self.waiter.busy(
        ) or self.dialogue.busy() or self.wait_tap