class PlacePreview(TwoScreenRenderer): 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_) def update(self, dt: float): for sprite in self.sprites: sprite.animate(dt) for obj in self.objects: obj.animate(dt) for exit_ in self.exits: exit_.animate(dt) self.bgm.update_(dt) if not self.move_mode: self.move_button.animate(dt) if self.move_button.pressed(self.btm_camera, dt): self.move_mode = True else: for exit_ in self.exits: if exit_.pressed(self.btm_camera, dt): break if exit_._pressed: break else: if self.inp.get_mouse_down(1): self.move_mode = False def draw(self): self.top_bg.draw(self.top_camera) self.map_icon.draw(self.top_camera) self.btm_bg.draw(self.btm_camera) for sprite in self.sprites: sprite.draw(self.btm_camera) for obj in self.objects: obj.draw(self.btm_camera) if not self.move_mode: self.move_button.draw(self.btm_camera) else: for exit_ in self.exits: exit_.draw(self.btm_camera)
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)
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