diff --git a/Metro/Metro_RP2350_Chips_Challenge/audio.py b/Metro/Metro_RP2350_Chips_Challenge/audio.py index 0fd1321ab..a3e263d6e 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/audio.py +++ b/Metro/Metro_RP2350_Chips_Challenge/audio.py @@ -2,16 +2,16 @@ # # SPDX-License-Identifier: MIT import audiocore -import audiobusio from definitions import PLAY_SOUNDS class Audio: - def __init__(self, *, bit_clock, word_select, data): - self._audio = audiobusio.I2SOut(bit_clock, word_select, data) + def __init__(self, audio_bus, sounds): + self._audio = audio_bus self._wav_files = {} - - def add_sound(self, sound_name, file): - self._wav_files[sound_name] = file + for sound_name, file in sounds.items(): + self._add_sound(sound_name, file) + # Play the first sound in the list to initialize the audio system + self.play(tuple(self._wav_files.keys())[0], wait=True) def play(self, sound_name, wait=False): if not PLAY_SOUNDS: @@ -23,3 +23,6 @@ def play(self, sound_name, wait=False): if wait: while self._audio.playing: pass + + def _add_sound(self, sound_name, file): + self._wav_files[sound_name] = file diff --git a/Metro/Metro_RP2350_Chips_Challenge/code.py b/Metro/Metro_RP2350_Chips_Challenge/code.py index db22b2b3d..9c39e5a4d 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/code.py +++ b/Metro/Metro_RP2350_Chips_Challenge/code.py @@ -7,6 +7,9 @@ import picodvi import framebufferio import displayio +import adafruit_tlv320 +import audiobusio +from audio import Audio from game import Game from definitions import SECOND_LENGTH, TICKS_PER_SECOND @@ -17,13 +20,33 @@ # Change this to use a different data file DATA_FILE = "CHIPS.DAT" +SOUND_EFFECTS = { + "BUTTON_PUSHED": "/sounds/pop2.wav", + "DOOR_OPENED": "/sounds/door.wav", + "ITEM_COLLECTED": "/sounds/blip2.wav", + "BOOTS_STOLEN": "/sounds/strike.wav", + "WATER_SPLASH": "/sounds/water2.wav", + "TELEPORT": "/sounds/teleport.wav", + "CANT_MOVE": "/sounds/oof3.wav", + "CHIP_LOSES": "/sounds/bummer.wav", + "LEVEL_COMPLETE": "/sounds/ditty1.wav", + "IC_COLLECTED": "/sounds/click3.wav", + "BOMB_EXPLOSION": "/sounds/hit3.wav", + "SOCKET_SOUND": "/sounds/chimes.wav", + "TIME_LOW_TICK": "/sounds/click1.wav", + "TIME_UP": "/sounds/bell.wav" +} + displayio.release_displays() -audio_settings = { - 'bit_clock': board.D9, - 'word_select': board.D10, - 'data': board.D11 -} +i2c = board.I2C() +dac = adafruit_tlv320.TLV320DAC3100(i2c) +dac.configure_clocks(sample_rate=44100, bit_depth=16) +dac.headphone_output = True +dac.headphone_volume = -15 # dB + +audio_bus = audiobusio.I2SOut(board.D9, board.D10, board.D11) +audio = Audio(audio_bus, SOUND_EFFECTS) fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN, red_dp=board.D0P, red_dn=board.D0N, @@ -32,7 +55,7 @@ color_depth=8) display = framebufferio.FramebufferDisplay(fb) -game = Game(display, DATA_FILE, **audio_settings) +game = Game(display, DATA_FILE, audio) tick_length = SECOND_LENGTH / 1000 / TICKS_PER_SECOND while True: start = time.monotonic() diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index 19e0acaed..df53dc158 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -4,7 +4,7 @@ from micropython import const # Settings -PLAY_SOUNDS = False +PLAY_SOUNDS = True # Timing Constants TICKS_PER_SECOND = const(20) diff --git a/Metro/Metro_RP2350_Chips_Challenge/dialog.py b/Metro/Metro_RP2350_Chips_Challenge/dialog.py index 78125e2ae..0d3fe008d 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/dialog.py +++ b/Metro/Metro_RP2350_Chips_Challenge/dialog.py @@ -384,6 +384,9 @@ def draw_field(self, field, first_draw=False): # The box should be on the right of the coordinates # The width and height should be the size of the box # The font should be the font to use for the label and the text box + if isinstance(field["padding"], int): + field["padding"] = convert_padding(field["padding"]) + if first_draw: # draw the label label = TextBox( diff --git a/Metro/Metro_RP2350_Chips_Challenge/game.py b/Metro/Metro_RP2350_Chips_Challenge/game.py index 47fbfa302..cfb23a349 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/game.py +++ b/Metro/Metro_RP2350_Chips_Challenge/game.py @@ -70,7 +70,7 @@ def get_victory_message(deaths): return None class Game: - def __init__(self, display, data_file, **kwargs): + def __init__(self, display, data_file, audio): self._display = display self._images = {} self._buffers = {} @@ -78,7 +78,7 @@ def __init__(self, display, data_file, **kwargs): self._loading_group = displayio.Group() self._tile_size = 24 # Default tile size (length and width) self._digit_dims = (0, 0) - self._gamelogic = GameLogic(data_file, **kwargs) + self._gamelogic = GameLogic(data_file, audio) self._databuffer = DataBuffer() self._color_index = {} self._init_display() @@ -268,7 +268,8 @@ def _handle_commands(self): self.request_password() elif command == PREVIOUS_LEVEL: if self._gamelogic.current_level_number > 1: - if self._savestate.is_level_unlocked(self._gamelogic.current_level_number - 1): + if (self._gamelogic.current_level_number - 1 == 1 or + self._savestate.is_level_unlocked(self._gamelogic.current_level_number - 1)): self.reset_level() self._gamelogic.dec_level() self.save_level() @@ -412,10 +413,10 @@ def request_password(self): level = self._savestate.find_unlocked_level(password) if not 0 < level <= self._gamelogic.last_level: self.show_message("That is not a valid level number.") - elif (level and password and + elif (level > 1 and password and self._gamelogic.current_level.passwords[level] != password): self.show_message("You must enter a valid password.") - elif (self._savestate.is_level_unlocked(level) and + elif (level != 1 and self._savestate.is_level_unlocked(level) and self._savestate.find_unlocked_level(level) is None and self._savestate.find_unlocked_level(password) is None): self.show_message("You must enter a valid password.") @@ -850,5 +851,5 @@ def _draw_frame(self): y_pos * self._tile_size + VIEWPORT_OFFSET[1], top_tile, bottom_tile ) - self._draw_hint() self._draw_title_dialog() + self._draw_hint() diff --git a/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py b/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py index 5dcb9450e..e62ff21dc 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py +++ b/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py @@ -13,24 +13,6 @@ from level import Level, Tile from point import Point from slip import Slip -from audio import Audio - -SOUND_EFFECTS = { - "BUTTON_PUSHED": "/sounds/pop2.wav", - "DOOR_OPENED": "/sounds/door.wav", - "ITEM_COLLECTED": "/sounds/blip2.wav", - "BOOTS_STOLEN": "/sounds/strike.wav", - "WATER_SPLASH": "/sounds/water2.wav", - "TELEPORT": "/sounds/teleport.wav", - "CANT_MOVE": "/sounds/oof3.wav", - "CHIP_LOSES": "/sounds/bummer.wav", - "LEVEL_COMPLETE": "/sounds/ditty1.wav", - "IC_COLLECTED": "/sounds/click3.wav", - "BOMB_EXPLOSION": "/sounds/hit3.wav", - "SOCKET_SOUND": "/sounds/chimes.wav", - "TIME_LOW_TICK": "/sounds/click1.wav", - "TIME_UP": "/sounds/bell.wav" -} def is_ice(tile): return tile == TYPE_ICE or TYPE_ICEWALL_SOUTHEAST <= tile <= TYPE_ICEWALL_NORTHEAST @@ -73,7 +55,8 @@ class GameLogic: A class to represent the state of the game as well as control all the game movements and actions. """ - def __init__(self, data_file, **kwargs): + def __init__(self, data_file, audio): + self._audio = audio self._tileset = [Element() for _ in range(0x70)] self._chip = Creature() self._create_tileset() @@ -96,10 +79,7 @@ def __init__(self, data_file, **kwargs): self._current_time = 0 self._last_slip_dir = NONE self._controller_dir = NONE - self._audio = Audio(**kwargs) self._time_limit = 0 - for sound_name, file in SOUND_EFFECTS.items(): - self._audio.add_sound(sound_name, file) def dec_level(self): if self.current_level_number > 1: diff --git a/Metro/Metro_RP2350_Chips_Challenge/savestate.py b/Metro/Metro_RP2350_Chips_Challenge/savestate.py index 7235dc08e..c45c37bff 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/savestate.py +++ b/Metro/Metro_RP2350_Chips_Challenge/savestate.py @@ -60,7 +60,7 @@ def load(self): with open("/sd/" + SAVESTATE_FILE, "r") as f: data = json.load(f) self._levels = data["levels"] - except OSError: + except (OSError, ValueError): pass def set_level_score(self, level, score, time_left): diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/click1.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/click1.wav new file mode 100755 index 000000000..37e7ceb12 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/click1.wav differ