From b4a7cf88bbc041aaaf9c142e4a52985726db67e9 Mon Sep 17 00:00:00 2001 From: Melissa LeBlanc-Williams Date: Tue, 1 Apr 2025 16:12:51 -0700 Subject: [PATCH] Add Chips Challenge for guide --- Metro/Metro_RP2350_Chips_Challenge/CHIPS.DAT | Bin 0 -> 108569 bytes Metro/Metro_RP2350_Chips_Challenge/audio.py | 25 + .../bitmaps/background.bmp | Bin 0 -> 48120 bytes .../bitmaps/chipend.bmp | Bin 0 -> 47736 bytes .../bitmaps/digits.bmp | Bin 0 -> 9912 bytes .../bitmaps/info.bmp | Bin 0 -> 22680 bytes .../bitmaps/spritesheet_24_keyed.bmp | Bin 0 -> 93240 bytes Metro/Metro_RP2350_Chips_Challenge/code.py | 42 + .../Metro_RP2350_Chips_Challenge/creature.py | 132 ++ .../databuffer.py | 43 + .../definitions.py | 336 ++++ Metro/Metro_RP2350_Chips_Challenge/device.py | 9 + Metro/Metro_RP2350_Chips_Challenge/dialog.py | 544 +++++++ Metro/Metro_RP2350_Chips_Challenge/element.py | 13 + .../fonts/Arial-8.pcf | Bin 0 -> 204884 bytes .../fonts/Arial-Bold-10.pcf | Bin 0 -> 330244 bytes Metro/Metro_RP2350_Chips_Challenge/game.py | 854 ++++++++++ .../Metro_RP2350_Chips_Challenge/gamelogic.py | 1376 +++++++++++++++++ .../Metro_RP2350_Chips_Challenge/keyboard.py | 42 + Metro/Metro_RP2350_Chips_Challenge/level.py | 247 +++ Metro/Metro_RP2350_Chips_Challenge/point.py | 83 + .../Metro_RP2350_Chips_Challenge/savestate.py | 154 ++ .../settings.toml | 1 + Metro/Metro_RP2350_Chips_Challenge/slip.py | 10 + .../sounds/bell.wav | Bin 0 -> 10400 bytes .../sounds/blip2.wav | Bin 0 -> 1334 bytes .../sounds/bummer.wav | Bin 0 -> 2758 bytes .../sounds/chimes.wav | Bin 0 -> 15920 bytes .../sounds/click3.wav | Bin 0 -> 466 bytes .../sounds/ditty1.wav | Bin 0 -> 11262 bytes .../sounds/door.wav | Bin 0 -> 2022 bytes .../sounds/hit3.wav | Bin 0 -> 5964 bytes .../sounds/oof3.wav | Bin 0 -> 1562 bytes .../sounds/pop2.wav | Bin 0 -> 510 bytes .../sounds/strike.wav | Bin 0 -> 2708 bytes .../sounds/teleport.wav | Bin 0 -> 8062 bytes .../sounds/water2.wav | Bin 0 -> 7488 bytes 37 files changed, 3911 insertions(+) create mode 100755 Metro/Metro_RP2350_Chips_Challenge/CHIPS.DAT create mode 100755 Metro/Metro_RP2350_Chips_Challenge/audio.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/bitmaps/background.bmp create mode 100755 Metro/Metro_RP2350_Chips_Challenge/bitmaps/chipend.bmp create mode 100755 Metro/Metro_RP2350_Chips_Challenge/bitmaps/digits.bmp create mode 100755 Metro/Metro_RP2350_Chips_Challenge/bitmaps/info.bmp create mode 100755 Metro/Metro_RP2350_Chips_Challenge/bitmaps/spritesheet_24_keyed.bmp create mode 100755 Metro/Metro_RP2350_Chips_Challenge/code.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/creature.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/databuffer.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/definitions.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/device.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/dialog.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/element.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-8.pcf create mode 100755 Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-Bold-10.pcf create mode 100755 Metro/Metro_RP2350_Chips_Challenge/game.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/gamelogic.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/keyboard.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/level.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/point.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/savestate.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/settings.toml create mode 100755 Metro/Metro_RP2350_Chips_Challenge/slip.py create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/bell.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/blip2.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/bummer.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/chimes.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/click3.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/ditty1.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/door.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/hit3.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/oof3.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/pop2.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/strike.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/teleport.wav create mode 100755 Metro/Metro_RP2350_Chips_Challenge/sounds/water2.wav diff --git a/Metro/Metro_RP2350_Chips_Challenge/CHIPS.DAT b/Metro/Metro_RP2350_Chips_Challenge/CHIPS.DAT new file mode 100755 index 0000000000000000000000000000000000000000..db68c1238d80a3d5631d41c47813258969df1175 GIT binary patch literal 108569 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 literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/audio.py b/Metro/Metro_RP2350_Chips_Challenge/audio.py new file mode 100755 index 000000000..0fd1321ab --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/audio.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# 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) + self._wav_files = {} + + def add_sound(self, sound_name, file): + self._wav_files[sound_name] = file + + def play(self, sound_name, wait=False): + if not PLAY_SOUNDS: + return + if sound_name in self._wav_files: + with open(self._wav_files[sound_name], "rb") as wave_file: + wav = audiocore.WaveFile(wave_file) + self._audio.play(wav) + if wait: + while self._audio.playing: + pass diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/background.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/background.bmp new file mode 100755 index 0000000000000000000000000000000000000000..823b06d46e3d1dab82716eda5cd1aa6c6bcc7b73 GIT binary patch literal 48120 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 literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/chipend.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/chipend.bmp new file mode 100755 index 0000000000000000000000000000000000000000..3c1a56ec26299b4d4a8088a06d90f3aacaf5bb37 GIT binary patch literal 47736 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 a_7W^~y0IZvTnn451lV1^N1^G$*#8HnuqYk? literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/digits.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/digits.bmp new file mode 100755 index 0000000000000000000000000000000000000000..5100fa2d15abaf0b73870c22e8d7d04d528289ae GIT binary patch literal 9912 zcmdU!O_yCo6^1t*APM0kBtQ}rIz$Me5fM=kQCm7Qe(SB;A9d=sd&LiL{^Pp&c;{iW8(2?) z8yjX1*%_bz%QdqL=L&qHf9;v^pY83H2j7@r&p!Xx=k~=v|88k}%QCQ?ExQF0$iQ~t zAb|{Q9}W`8zz*Obfeh>r4id<~G8`n3f!QtpB)&7SO*lv(1KWm!1TwH4I7lD^+l7M! zGO&F(NFW0{fP(}wutPXVAOp*AkU$1FB#T{3AOqWkg9I|LZ8%6E1KWXv1TwH)I7lD^ z+lPY$GOz`_AhJyq$FuOxOcgW-p=W~aA;2?nvY#R;|$iQ~sAb|{Q7Y-80 z!1m!Ffeh>b4id<~4&fky3@pPz0$Da$kQsSo^1uce*fty_kb&*MK>``rE*vC~f$hUV z0vXr=93+r|9l}8ZS$4(-`SxwVGrtY~4E_pk5gv_%d)rG7xfu9ci(ZC-G{9$;{2=f#%ZKHm$`D@mx?1zG`^vC^PPMuJGtnUkC zZLHwLpRM=&n9@)vxK@;b{YW^!M|(2Gi2O9utvuCpMisUR{PBmoPbl757mF`~@;;=G zT$?A(U;9SAlE=e--gnpK{|V6{{*$AwSh|) z@5!mmLNA-@;cQ*W0NvloZ+lB-R0-1yM>ZVtNm)u6u=^p}EuO?nL||KFG>OuVUD zWcG3|rWmgr=ha(Te?9nnHN<;0LxVyb<&_ z!v1ds|8EYu@_RGr-wyg)L4QknO-T8DXQHqpdpqO@pN;R%nA!K>x)J3g&hd46Wbb%B zRVBi^E*2-s|6SK7{{5i87xedn{)0hRJ@2EB=ly=D=ZDld>Oaz^HZaB8gsdM2zP*C~ zBSK62^54f^lk zn$nOCZ`3D#AM*P{%cVXe|6^GHr3Xh;6|LUI#^9lGwk?Ei2V}bYWTL0AS{T+$-7b;V{-4|Ks|3m(CSTEi)#Dr@_ z8QAn|jq&845{~Kf{TGA(Rs5N-eu=jXc-pfeKKw zUOnnSE(iT`xZhE~GU%%3N{Ej>tLOPpFMRgC#M^|dvHyG!PCq)^FRm#Kne%@2$d31` zv*T62Ive8Uw_5%Vya?+P7^Q!$zhwV+=M{-tZ3hAjHyM%_~X+$NUvmxE3}&2p{u2mN)YZm7R5s;{txe%o_tU)RHW z_21nA26~^6HTK_%;Qe`XwxEywx%S`Si-!+cQCI(7Zj&z52L1d*nehI8)cFUE=FY9L zznA~0tG{m>s?})qw4`f}Wxmp%0o$)J$~EYCf1iT2?-}|*#rO)?hE|@MCjMLJUBl}r7UH+$c=k%}XN2_&^@Moqzdtp-2dZZwzgAt{ zzxMn>{r$ko`|k7s&zl?5K1!TyJ8i$$GSS}e+Up7D)eBgxXT1N)Z>Z8uc2|GJ`trOT zNC}1a`T2C(&ZU)ek7qBhB)V{a>Wcrp^HzoZc>St~xAWGqjNIu7bZyb7`y1^OMfDZ; zIO5s#wA>S2xIc9TfoAzLy%yfHDgK6fN`KlgBUjXJP;Bz8(AhPuIb(N6qElkJFP6>Yn=Y2f>l#Zt# z&UcCGgvv*1|MTI-I3Y>8KPIbD-?|RnLwK0tx@Ff`(AOTnIjogJO9rLzPTgoHQdfws z9INY@$2*=+4dH^;mQk%nANYOr3tc>QTJBH(xj}2dR^giBw}hws=k*hIoanUeYw6VI FzX6P}^#A|> literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/info.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/info.bmp new file mode 100755 index 0000000000000000000000000000000000000000..4310ee5419a8c8cf337b2411067d0e6ae0acc6b9 GIT binary patch literal 22680 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 literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/spritesheet_24_keyed.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/spritesheet_24_keyed.bmp new file mode 100755 index 0000000000000000000000000000000000000000..7820db71dce49dccdc35ccf6f6d855b980bf9fd6 GIT binary patch literal 93240 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 Km;3#VW%>W@g3eU{ literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/code.py b/Metro/Metro_RP2350_Chips_Challenge/code.py new file mode 100755 index 000000000..77e68eade --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/code.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT + +import time +import board +import picodvi +import framebufferio +import displayio +from game import Game +from definitions import SECOND_LENGTH, TICKS_PER_SECOND + +# Disable auto-reload to prevent the game from restarting +# TODO: Enable after testing +#import supervisor +#supervisor.runtime.autoreload = False + +# Change this to use a different data file +DATA_FILE = "CHIPS.DAT" + +displayio.release_displays() + +audio_settings = { + 'bit_clock': board.D9, + 'word_select': board.D10, + 'data': board.D11 +} + +fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN, + red_dp=board.D0P, red_dn=board.D0N, + green_dp=board.D1P, green_dn=board.D1N, + blue_dp=board.D2P, blue_dn=board.D2N, + color_depth=8) +display = framebufferio.FramebufferDisplay(fb) + +game = Game(display, DATA_FILE, **audio_settings) +tick_length = SECOND_LENGTH / 1000 / TICKS_PER_SECOND +while True: + start = time.monotonic() + game.tick() + while time.monotonic() - start < tick_length: + pass diff --git a/Metro/Metro_RP2350_Chips_Challenge/creature.py b/Metro/Metro_RP2350_Chips_Challenge/creature.py new file mode 100755 index 000000000..ba23b5155 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/creature.py @@ -0,0 +1,132 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from point import Point +from definitions import NONE, TYPE_BLOCK, TYPE_CHIP, NORTH, SOUTH, WEST, EAST + +DIR_UP = 0 +DIR_LEFT = 1 +DIR_DOWN = 2 +DIR_RIGHT = 3 + +# creatures should move based on chip, tiles near them, and their own AI +# creatures should be able to move in any direction assuming they are not blocked + +# Abstract class +class Creature: + def __init__(self, *, position=None, direction=NONE, creature_type=NONE): + self.cur_pos = position or Point(0, 0) + self.type = creature_type or TYPE_BLOCK + self.direction = direction + self.state = 0x00 + self.hidden = False + self.on_slip_list = False + self.to_direction = NONE + + def move(self, destination): + if destination.y < self.cur_pos.y: + self.direction = NORTH + elif destination.x < self.cur_pos.x: + self.direction = WEST + elif destination.y > self.cur_pos.y: + self.direction = SOUTH + elif destination.x > self.cur_pos.x: + self.direction = EAST + else: + self.direction = NONE + self.cur_pos = destination + + def image_number(self): + tile_index = 0 + if self.type == TYPE_CHIP: + tile_index = 0x6C + elif self.type == TYPE_BLOCK: + tile_index = 0x0A + else: + tile_index = 0x40 + ((self.type - 1) * 4) + + if self.direction == WEST: + tile_index += DIR_LEFT + elif self.direction == EAST: + tile_index += DIR_RIGHT + elif self.direction == NORTH: + tile_index += DIR_UP + elif self.direction in (SOUTH, NONE): + tile_index += DIR_DOWN + return tile_index + + def get_tile_in_dir(self, direction): + pt_dir = Point(self.cur_pos.x, self.cur_pos.y) + if direction == WEST: + pt_dir.x -= 1 + elif direction == EAST: + pt_dir.x += 1 + elif direction == NORTH: + pt_dir.y -= 1 + elif direction == SOUTH: + pt_dir.y += 1 + return pt_dir + + def left(self): + # return the point to the left of the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.x -= 1 + elif self.direction == WEST: + pt_dest.y += 1 + elif self.direction == SOUTH: + pt_dest.x += 1 + elif self.direction == EAST: + pt_dest.y -= 1 + return pt_dest + + def right(self): + # Return point to the right of the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.x += 1 + elif self.direction == WEST: + pt_dest.y -= 1 + elif self.direction == SOUTH: + pt_dest.x -= 1 + elif self.direction == EAST: + pt_dest.y += 1 + return pt_dest + + def back(self): + # Return point behind the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.y += 1 + elif self.direction == WEST: + pt_dest.x += 1 + elif self.direction == SOUTH: + pt_dest.y -= 1 + elif self.direction == EAST: + pt_dest.x -= 1 + return pt_dest + + def front(self): + # Return point in front of the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.y -= 1 + elif self.direction == WEST: + pt_dest.x -= 1 + elif self.direction == SOUTH: + pt_dest.y += 1 + elif self.direction == EAST: + pt_dest.x += 1 + return pt_dest + + def reverse(self): + if self.direction == NORTH: + return SOUTH + elif self.direction == SOUTH: + return NORTH + elif self.direction == WEST: + return EAST + elif self.direction == EAST: + return WEST + else: + return self.direction diff --git a/Metro/Metro_RP2350_Chips_Challenge/databuffer.py b/Metro/Metro_RP2350_Chips_Challenge/databuffer.py new file mode 100755 index 000000000..69a264099 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/databuffer.py @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +class DataBuffer: + def __init__(self): + self._dataset = {} + self._default_data = {} + + def set_data_structure(self, data_structure): + self._default_data = data_structure + self.reset() + + def reset(self, field=None): + # Copy the default data to the dataset + if field is not None: + if not isinstance(field, (tuple, list)): + field = [field] + for item in field: + self._dataset[item] = self.deepcopy(self._default_data[item]) + else: + self._dataset = self.deepcopy(self._default_data) + + def deepcopy(self, data): + # Iterate through the data and copy each element + new_data = {} + if isinstance(data, (dict)): + for key, value in data.items(): + if isinstance(value, (dict, list)): + new_data[key] = self.deepcopy(value) + else: + new_data[key] = value + elif isinstance(data, (list)): + for idx, item in enumerate(data): + if isinstance(item, (dict, list)): + new_data[idx] = self.deepcopy(item) + else: + new_data[idx] = item + return new_data + + @property + def dataset(self): + return self._dataset diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py new file mode 100755 index 000000000..19e0acaed --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -0,0 +1,336 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from micropython import const + +# Settings +PLAY_SOUNDS = False + +# Timing Constants +TICKS_PER_SECOND = const(20) +SECOND_LENGTH = const(1000) + +# Tile Constants +TYPE_NOTILE = const(-1) +TYPE_EMPTY = const(0x00) +TYPE_WALL = const(0x01) +TYPE_ICCHIP = const(0x02) +TYPE_WATER = const(0x03) +TYPE_FIRE = const(0x04) +TYPE_HIDDENWALL_PERM = const(0x05) +TYPE_WALL_NORTH = const(0x06) +TYPE_WALL_WEST = const(0x07) +TYPE_WALL_SOUTH = const(0x08) +TYPE_WALL_EAST = const(0x09) +TYPE_BLOCK_STATIC = const(0x0a) +TYPE_DIRT = const(0x0b) +TYPE_ICE = const(0x0c) +TYPE_SLIDE_SOUTH = const(0x0d) +TYPE_SLIDE_NORTH = const(0x12) +TYPE_SLIDE_EAST = const(0x13) +TYPE_SLIDE_WEST = const(0x14) +TYPE_EXIT = const(0x15) +TYPE_DOOR_BLUE = const(0x16) +TYPE_DOOR_RED = const(0x17) +TYPE_DOOR_GREEN = const(0x18) +TYPE_DOOR_YELLOW = const(0x19) +TYPE_ICEWALL_SOUTHEAST = const(0x1a) +TYPE_ICEWALL_SOUTHWEST = const(0x1b) +TYPE_ICEWALL_NORTHWEST = const(0x1c) +TYPE_ICEWALL_NORTHEAST = const(0x1d) +TYPE_BLUEWALL_FAKE = const(0x1e) +TYPE_BLUEWALL_REAL = const(0x1f) + +TYPE_THIEF = const(0x21) +TYPE_SOCKET = const(0x22) +TYPE_BUTTON_GREEN = const(0x23) +TYPE_BUTTON_RED = const(0x24) +TYPE_SWITCHWALL_CLOSED = const(0x25) +TYPE_SWITCHWALL_OPEN = const(0x26) +TYPE_BUTTON_BROWN = const(0x27) +TYPE_BUTTON_BLUE = const(0x28) +TYPE_TELEPORT = const(0x29) +TYPE_BOMB = const(0x2a) +TYPE_BEARTRAP = const(0x2b) +TYPE_HIDDENWALL_TEMP = const(0x2c) +TYPE_GRAVEL = const(0x2d) +TYPE_POPUPWALL = const(0x2e) +TYPE_HINTBUTTON = const(0x2f) +TYPE_WALL_SOUTHEAST = const(0x30) +TYPE_CLONEMACHINE = const(0x31) +TYPE_SLIDE_RANDOM = const(0x32) + +TYPE_CHIP_DROWNED = const(0x33) +TYPE_CHIP_BURNED = const(0x34) +TYPE_CHIP_BOMBED = const(0x35) + +TYPE_EXITED_CHIP = const(0x39) +TYPE_EXIT_EXTRA_1 = const(0x3a) +TYPE_EXIT_EXTRA_2 = const(0x3b) + +TYPE_BLOCK = const(0xd0) +TYPE_CHIP_SWIMMING = const(0x3c) +TYPE_BUG = const(0x40) +TYPE_FIREBALL = const(0x44) +TYPE_BALL = const(0x48) +TYPE_TANK = const(0x4c) +TYPE_GLIDER = const(0x50) +TYPE_TEETH = const(0x54) +TYPE_WALKER = const(0x58) +TYPE_BLOB = const(0x5c) +TYPE_PARAMECIUM = const(0x60) + +TYPE_KEY_BLUE = const(0x64) +TYPE_KEY_RED = const(0x65) +TYPE_KEY_GREEN = const(0x66) +TYPE_KEY_YELLOW = const(0x67) + +TYPE_BOOTS_WATER = const(0x68) +TYPE_BOOTS_FIRE = const(0x69) +TYPE_BOOTS_ICE = const(0x6a) +TYPE_BOOTS_SLIDE = const(0x6b) + +TYPE_CHIP = const(0x6c) +TYPE_NOTHING = const(0xff) + +# Map Directional Constants +NONE = const(-1) +NORTH = const(1) +WEST = const(2) +SOUTH = const(4) +EAST = const(8) +NWSE = const(NORTH | WEST | SOUTH | EAST) + +# Command Constants +UP = const(0) +LEFT = const(1) +DOWN = const(2) +RIGHT = const(3) +NEXT_LEVEL = const(4) +PREVIOUS_LEVEL = const(5) +RESTART_LEVEL = const(6) +GOTO_LEVEL = const(7) +PAUSE = const(8) +QUIT = const(9) +OK = const(10) +CANCEL = const(11) +CHANGE_FIELDS = const(12) +DELCHAR = const(13) + +# Keycode Constants +UP_ARROW = const("\x1b[A") +DOWN_ARROW = const("\x1b[B") +RIGHT_ARROW = const("\x1b[C") +LEFT_ARROW = const("\x1b[D") +SPACE = const(" ") +CTRL_G = const("\x07") # Ctrl+G +CTRL_N = const("\x0E") # Ctrl+N +CTRL_P = const("\x10") # Ctrl+P +CTRL_Q = const("\x11") # Ctrl+Q +CTRL_R = const("\x12") # Ctrl+R +BACKSPACE = const("\x08") +TAB = const("\x09") +ENTER = const("\n") +ESC = const("\x1b") + +# Mapping Buttons to Commands for different modes +GAMEPLAY_COMMANDS = { + UP_ARROW: UP, + LEFT_ARROW: LEFT, + DOWN_ARROW: DOWN, + RIGHT_ARROW: RIGHT, + SPACE: PAUSE, + CTRL_G: GOTO_LEVEL, + CTRL_N: NEXT_LEVEL, + CTRL_P: PREVIOUS_LEVEL, + CTRL_Q: QUIT, + CTRL_R: RESTART_LEVEL, +} + +MESSAGE_COMMANDS = { + ENTER: OK, + SPACE: OK, +} + +# Password commands include only letters, enter, tab, and backspace +PASSWORD_COMMANDS = { + ESC: CANCEL, + TAB: CHANGE_FIELDS, + ENTER: OK, + BACKSPACE: DELCHAR, +} + +# The rest are input characters +for i in range(65, 91): + PASSWORD_COMMANDS[chr(i)] = chr(i) +for i in range(97, 123): + PASSWORD_COMMANDS[chr(i)] = chr(i) +for i in range(48, 58): + PASSWORD_COMMANDS[chr(i)] = chr(i) + +# Can Make Move Constants +CMM_NOLEAVECHECK = const(0x0001) +CMM_NOEXPOSEWALLS = const(0x0002) +CMM_CLONECANTBLOCK = const(0x0004) +CMM_NOPUSHING = const(0x0008) +CMM_TELEPORTPUSH = const(0x0010) +CMM_NOFIRECHECK = const(0x0020) +CMM_NODEFERBUTTONS = const(0x0040) + +# Creature States +CS_RELEASED = const(0x01) +CS_CLONING = const(0x02) +CS_HASMOVED = const(0x04) +CS_TURNING = const(0x08) +CS_SLIP = const(0x10) +CS_SLIDE = const(0x20) +CS_DEFERPUSH = const(0x40) +CS_MUTANT = const(0x80) + +#Floor State Constants +FS_BUTTONDOWN = const(0x01) +FS_CLONING = const(0x02) +FS_BROKEN = const(0x04) +FS_HASMUTANT = const(0x08) +FS_MARKER = const(0x10) + +# Status Flag Constants +SF_CHIPWAITMASK = const(0x0007) +SF_CHIPOKAY = const(0x0000) +SF_CHIPBURNED = const(0x0010) +SF_CHIPBOMBED = const(0x0020) +SF_CHIPDROWNED = const(0x0030) +SF_CHIPHIT = const(0x0040) +SF_CHIPTIMEUP = const(0x0050) +SF_CHIPBLOCKHIT = const(0x0060) +SF_CHIPNOTOKAY = const(0x0070) +SF_CHIPSTATUSMASK = const(0x0070) +SF_DEFERBUTTONS = const(0x0080) +SF_COMPLETED = const(0x0100) +SF_SHOWHINT = const(0x10000000) + +# Game Mode Constants +GM_NONE = const(0) # No mode (not sure if this should be a mode) +GM_PAUSED = const(1) # Paused +GM_CHIPDEAD = const(2) # Chip is dead +GM_GAMEWON = const(3) # Game is won +GM_LEVELWON = const(4) # Level is won +GM_LOADING = const(5) # Not sure +GM_MESSAGE = const(6) # Message is displayed +GM_NEWGAME = const(7) # Not sure +GM_NORMAL = const(8) # Normal gameplay + +# Key Constants +RED_KEY = const(0) +BLUE_KEY = const(1) +YELLOW_KEY = const(2) +GREEN_KEY = const(3) + +# Boot Constants +ICE_BOOTS = const(0) +SUCTION_BOOTS = const(1) +FIRE_BOOTS = const(2) +WATER_BOOTS = const(3) + +death_messages = { + SF_CHIPHIT: "Ooops! Look out for creatures!", + SF_CHIPDROWNED: "Ooops! Chip can't swim without flippers!", + SF_CHIPBURNED: "Ooops! Don't step in the fire without fire boots!", + SF_CHIPBOMBED: "Ooops! Don't touch the bombs!", + SF_CHIPTIMEUP: "Ooops! Out of time!", + SF_CHIPBLOCKHIT: "Ooops! Watch out for moving blocks!", +} + +decade_messages = { + 10: ("After warming up on the first levels of the challenge, " + "Chip is raring to go! 'This isn't so hard,' he thinks."), + 20: ("But the challenge turns out to be harder than Chip thought. " + "The Bit Busters want it that way -- to keep out lobotomy heads."), + 30: ("Chip's thick-soled shoes and pop-bottle glasses speed him through " + "the mazes while his calculator watch keeps track of time."), + 40: "Chip reads the clues so he won't lose.", + 50: ("Picking up chips is what the challenge is all about. But on ice, " + "Chip gets chapped and feels like a chump instead of a champ."), + 60: ("Chip hits the ice and decides to chill out. Then he runs into a " + "fake wall and turns the maze into a thrash-a-thon!"), + 70: ("Chip is halfway through the world's hardest puzzle. If he suceeds, " + "maybe the kids will stop calling him computer breath!"), + 80: ("Chip used to spend his time programming computer games and making " + "models. But that was just practice for this brain-buster!"), + 90: ("'I can do it! I know I can!' Chip thinks as the going gets tougher. " + "Besides, Melinda the Mental Marvel waits at the end."), + 100: ("Besides being an angel on earth, Melinda is the top scorer in the " + "Challenge--and the president of the Bit Busters."), + 110: ("Chip can't wait to join the Bit Busters! The club's already figured " + "out the school's password and accessed everyone's grades!"), + 120: ("If Chip's grades aren't as good as Melinda's, maybe she'll come " + "over to his house and help him study!"), + 130: ("'I've made it this far,' Chip thinks. 'Totally fair, with my " + "mega-brain.' Then he starts the next maze. 'Totally unfair!' he yelps."), + 140: "Groov-u-loids! Chip makes it almost to the end. He's stoked!", + 144: ("Melinda herself offers Chip membership in the exclusive Bit Busters " + "computer club, and gives him access to the club's computer system. " + "Chip is in heaven!"), + 149: ("Melinda herself offers Chip membership in the exclusive Bit Busters " + "computer club, and gives him access to the club's computer system. " + "Chip is in heaven!"), +} + +victory_messages = { + 0: "Yowser! First Try!", + 2: "Go Bit Buster!", + 4: "Finished! Good Work!", + 5: "At last! You did it!", +} + +winning_message = ( + "You completed {completed_levels} levels, and your total score for the " + "challenge is {total_score} points.\n\n" + "You can still improve your score, by completing levels that you skipped, " + "and getting better times on each level. When you replay a level, if your " + "new score is better than your old, your score will be adjusted by the " + "difference. Select Best Times from the Game menu to see your scores for " + "each level." +) + +# This will show the game won sequence for any of these levels +# -1 represents the last level +final_levels = [144, -1] + +def left(direction): + return ((direction << 1) | (direction >> 3)) & 15 + +def back(direction): + return ((direction << 2) | (direction >> 2)) & 15 + +def right(direction): + return ((direction << 3) | (direction >> 1)) & 15 + +def creature_id(tile_id): + return tile_id & ~3 + +def idx_dir(index): + return 1 << (index & 3) + +def dir_idx(direction): + return (0x30210 >> (direction * 2)) & 3 + +def creature_dir_id(tile_id): + return idx_dir(tile_id & 3) + +def cr_tile(tile_id, direction): + return tile_id | dir_idx(direction) + +def is_key(tile): + return TYPE_KEY_BLUE <= tile <= TYPE_KEY_YELLOW + +def is_boots(tile): + return TYPE_BOOTS_WATER <= tile <= TYPE_BOOTS_SLIDE + +def is_creature(tile): + return ((0x40 <= tile <= 0x63) or (TYPE_BLOCK <= tile <= TYPE_BLOCK + 3) or + (TYPE_CHIP_SWIMMING <= tile <= TYPE_CHIP_SWIMMING + 3) or + (TYPE_CHIP <= tile <= TYPE_CHIP + 3)) + +def is_door(tile): + return TYPE_DOOR_BLUE <= tile <= TYPE_DOOR_YELLOW diff --git a/Metro/Metro_RP2350_Chips_Challenge/device.py b/Metro/Metro_RP2350_Chips_Challenge/device.py new file mode 100755 index 000000000..d016f8090 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/device.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from point import Point + +class Device: + def __init__(self, button=None, device=None): + self.button = button if button else Point(0, 0) + self.device = device if device else Point(0, 0) diff --git a/Metro/Metro_RP2350_Chips_Challenge/dialog.py b/Metro/Metro_RP2350_Chips_Challenge/dialog.py new file mode 100755 index 000000000..6527b3db0 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/dialog.py @@ -0,0 +1,544 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from micropython import const +import displayio +import bitmaptools +from adafruit_display_text import bitmap_label +from adafruit_display_text.text_box import TextBox + +BORDER_STYLE_INSET = 0 +BORDER_STYLE_OUTSET = 1 +BORDER_STYLE_FLAT = 2 +BORDER_STYLE_LIGHT_OUTLINE = 3 +BORDER_STYLE_DARK_OUTLINE = 4 + +class InputFields: + + ALPHANUMERIC = const(0) + ALPHA = const(1) + NUMERIC = const(2) + + """Class to keep track of input fields in a dialog""" + def __init__(self): + self._input_fields = [] + self._active_field = 0 + + def add(self, label, field_type=ALPHANUMERIC, value=""): + value_type = int if isinstance(value, int) else str + if value in ("", 0): + value = " " + if value_type not in (str, int): + raise ValueError("value_type must be str or int") + key = label.lower().replace(" ", "_") + focused = len(self._input_fields) == 0 + self._input_fields.append({ + "key": key, + "label": label, + "font": None, + "value": str(value), + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "color_index": None, + "bgcolor_index": None, + "padding": 10, + "redraw": True, # This is to keep track of whether to redraw the field or not + "max_length": None, + "type": field_type, + "buffer": None, + "focused": focused, + "value_type": value_type, + }) + + def redraw_all(self): + for field in self._input_fields: + field["redraw"] = True + + def clear(self): + self._active_field = 0 + self._input_fields = [] + + def get_field(self, key): + for field in self._input_fields: + if field["key"] == key: + return field + return None + + def next_field(self): + self._input_fields[self._active_field]["focused"] = False + self._input_fields[self._active_field]["redraw"] = True + self._active_field = (self._active_field + 1) % len(self._input_fields) + self._input_fields[self._active_field]["focused"] = True + self._input_fields[self._active_field]["redraw"] = True + + def get_value(self, key): + field = self.get_field(key) + if field is None: + return None + value = field["value"] + if value == " ": + return "" if field["value_type"] == str else 0 + return field["value_type"](value) + + @property + def active_field(self): + return self._input_fields[self._active_field] + + @property + def active_field_value(self): + if self.active_field["value"] == " ": + return "" + return self.active_field["value"] + + @active_field_value.setter + def active_field_value(self, value): + if value == "": + value = " " + self.active_field["value"] = value + self.active_field["redraw"] = True + + @property + def fields(self): + return self._input_fields + +class Dialog: + def __init__(self, color_index, shader): + self._color_index = color_index + self.shader = shader + + def _reassign_indices(self, bitmap, foreground_color_index, background_color_index): + # This will reassign the indices in the bitmap to match the palette + new_bitmap = displayio.Bitmap(bitmap.width, bitmap.height, len(self.shader)) + if background_color_index is not None: + for x in range(bitmap.width): + for y in range(bitmap.height): + if bitmap[(x, y)] == 0: + new_bitmap[(x, y)] = background_color_index + if foreground_color_index is not None: + for x in range(bitmap.width): + for y in range(bitmap.height): + if bitmap[(x, y)] == 1: + new_bitmap[(x, y)] = foreground_color_index + return new_bitmap + + def _add_border(self, bitmap, border_color_ul, border_color_br): + if border_color_ul is not None: + for x in range(bitmap.width): + bitmap[x, 0] = border_color_ul + for y in range(bitmap.height): + bitmap[0, y] = border_color_ul + if border_color_br is not None: + for x in range(bitmap.width): + bitmap[x, bitmap.height - 1] = border_color_br + for y in range(bitmap.height): + bitmap[bitmap.width - 1, y] = border_color_br + return bitmap + + def _convert_padding(self, padding): + if isinstance(padding, int): # Top, Right, Bottom Left (same as CSS) + padding = { + "top": padding // 2, + "right": padding // 2, + "bottom": padding // 2, + "left": padding // 2 + } + elif isinstance(padding, (tuple, list)) and len(padding) == 2: # Top/Bottom, Left/Right + padding = { + "top": padding[0], + "right": padding[1], + "bottom": padding[0], + "left": padding[1] + } + elif isinstance(padding, (tuple, list)) and len(padding) == 4: # Top, Right, Bottom, Left + padding = { + "top": padding[0], + "right": padding[1], + "bottom": padding[2], + "left": padding[3] + } + return padding + + def _text_bounding_box(self, text, font, line_spacing=0.75): + temp_label = bitmap_label.Label( + font, + text=text, + line_spacing=line_spacing, + background_tight=True + ) + return temp_label.bounding_box + + def _draw_button(self, buffer, text, font, x_position, y_position, + width=None, height=None, center_button=True, **kwargs): + del kwargs["center_dialog_vertically"] + del kwargs["center_dialog_horizontally"] + if "padding" not in kwargs: + kwargs["padding"] = 10 + return self.display_simple( + text, + font, + width, + height, + x_position, + y_position, + buffer, + border_dark_index=self._color_index["dark_gray"], + background_color_index=self._color_index["light_gray"], + center_dialog_horizontally=center_button, + center_dialog_vertically=False, + **kwargs) + + def _draw_background( + self, + x_position, + y_position, + width, + height, + buffer, + *, + border_style=BORDER_STYLE_OUTSET, + background_color_index=None, + border_light_index=None, + border_dark_index=None, + ): + # Draw a background for the dialog + # This will be a simple rectangle with a border + + if border_light_index is None: + # The index of the light border color in the palette + border_light_index = self._color_index["bounding_box_light"] + if border_dark_index is None: + # The index of the dark border color in the palette + border_dark_index = self._color_index["bounding_box_dark"] + if background_color_index is None: + background_color_index = self._color_index["dialog_background"] + + if border_style == BORDER_STYLE_OUTSET: + (border_color_ul, border_color_br) = (border_light_index, border_dark_index) + elif border_style == BORDER_STYLE_INSET: + border_color_ul, border_color_br = border_dark_index, border_light_index + elif border_style == BORDER_STYLE_DARK_OUTLINE: + border_color_ul, border_color_br = border_dark_index, border_dark_index + elif border_style == BORDER_STYLE_LIGHT_OUTLINE: + border_color_ul, border_color_br = border_light_index, border_light_index + else: + border_color_ul, border_color_br = None, None + + background_bitmap = displayio.Bitmap(width, height, len(self.shader)) + background_bitmap.fill(background_color_index) + background_bitmap = self._add_border(background_bitmap, border_color_ul, border_color_br) + bitmaptools.blit(buffer, background_bitmap, x_position, y_position) + + def _calculate_dialog_size(self, text, font, width, height, padding): + # Calculate the size of the dialog based on the text and font + if text is not None: + text_width = self._text_bounding_box(text, font)[2] + if width is None: + width = text_width + padding["right"] + padding["left"] + if height is None: + height = self._text_bounding_box(text, font)[3] + padding["top"] + padding["bottom"] + else: + if width is None: + width = 0 + if height is None: + height = 0 + return width, height + + def display_simple( + self, + text, # the text to display in the dialog + font, # the font to use for the dialog + width, # the width of the dialog + height, # the height of the dialog + x_position, # the x coordinate the dialog should be centered on in the buffer + y_position, # the y coordinate the dialog should be centered on in the buffer + buffer, + *, + center_dialog_horizontally=False, # x position in center of the dialog + center_dialog_vertically=False, # y position in center of the dialog + horizontal_text_alignment=TextBox.ALIGN_CENTER, # The alignment of the text + center_text_vertically=True, # whether the text should be centered vertically + background_color_index=None, # the index of the background color in the palette + font_color_index=None, # the index of the font color in the palette + padding=10, # the padding around the text + border_light_index=None, + border_dark_index=None, + line_spacing=0.75, # Space between each line of text in pixels + border_style=BORDER_STYLE_OUTSET, # The style of the border + ): + #pylint: disable=too-many-locals, too-many-branches + + border_width = 1 + if horizontal_text_alignment is None: + horizontal_text_alignment = TextBox.ALIGN_CENTER + if font_color_index is None: + font_color_index = self._color_index["default_dialog_text_color"] + if background_color_index is None: + background_color_index = self._color_index["dialog_background"] + + padding = self._convert_padding(padding) + + if text is not None: + text_area_padding = (0, 0) + if width is None: + # Create a regular bitmap label with the text to get the width + text_width = self._text_bounding_box(text, font, line_spacing=line_spacing)[2] + text_area_padding = (-padding["left"], -padding["right"]) + else: + text_width = width - padding["right"] - padding["left"] - border_width * 2 + # Colors don't matter for bitmap fonts + text_area = TextBox( + font, + text_width, + TextBox.DYNAMIC_HEIGHT, + align=horizontal_text_alignment, + text=text, + background_tight=True, + line_spacing=line_spacing, + padding_left=text_area_padding[0], + padding_right=text_area_padding[1], + ) + + text_bmp = self._reassign_indices( + text_area.bitmap, font_color_index, background_color_index + ) + if width is None: + width = text_bmp.width + padding["right"] + padding["left"] + border_width * 2 + if height is None: + height = text_bmp.height + padding["top"] + padding["bottom"] + border_width * 2 + + text_bitmap_position = [padding["left"] + border_width, padding["top"] + border_width] + if center_text_vertically: + text_bitmap_position[1] = (height - text_bmp.height) // 2 + else: + text_bmp = None + if width is None: + width = padding["right"] + padding["left"] + border_width * 2 + if height is None: + height = padding["top"] + padding["bottom"] + border_width * 2 + + if x_position is None: + x_position = (buffer.width - width) // 2 + elif center_dialog_horizontally and x_position is not None: + x_position = x_position - width // 2 + + if y_position is None: + y_position = (buffer.height - height) // 2 + elif center_dialog_vertically and y_position is not None: + y_position = y_position - height // 2 + + # Draw the background + self._draw_background( + x_position, + y_position, + width, + height, + border_style=border_style, + background_color_index=background_color_index, + border_light_index=border_light_index, + border_dark_index=border_dark_index, + buffer=buffer, + ) + if text_bmp: + bitmaptools.blit( + buffer, text_bmp, x_position + text_bitmap_position[0], + y_position + text_bitmap_position[1] + ) + + # return the width and height of the dialog in a tuple + return width, height, text_bmp.height if text_bmp else 0 + + def display_message(self, text, font, width, height, x_position, y_position, buffer, **kwargs): + #pylint: disable=too-many-locals + button_font = font + button_text = "OK" + if "button_font" in kwargs: + button_font = kwargs.pop("button_font") + if "button_text" in kwargs: + button_text = kwargs.pop("button_text") + padding = self._convert_padding(kwargs.get("padding", 5)) + control_spacing = 5 + button_height = button_font.get_bounding_box()[1] + control_spacing + padding["bottom"] + + # Draw dialog and text + dialog_width, dialog_height, _ = self.display_simple( + text, + font, + width, + height, + x_position, + y_position, + buffer, + padding=( + padding["top"], padding["right"], + button_height + padding["bottom"], padding["left"] + ), + center_text_vertically=False, + border_light_index=self._color_index["light_gray"], + border_dark_index=self._color_index["black"], + **kwargs + ) + + if x_position is None: + if kwargs.get("center_dialog_horizontally", True): + x_position = buffer.width // 2 + else: + x_position = (buffer.width - dialog_width) // 2 + + # Draw a button + if y_position is None: + y_position = (buffer.height - dialog_height) // 2 + y_position += dialog_height - button_height + self._draw_button(buffer, button_text, button_font, x_position, y_position, **kwargs) + + def draw_field(self, field, first_draw=False): + # Draw a singular field + # A field should draw a label and a box to enter text + # The label should be on the left of the coordinates + # 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 first_draw: + # draw the label + label = TextBox( + field["font"], + self._text_bounding_box(field["label"], field["font"])[2], + TextBox.DYNAMIC_HEIGHT, + align=TextBox.ALIGN_RIGHT, + text=field["label"], + background_tight=True, + line_spacing=0.75, + padding_left=-field["padding"]["left"], + padding_right=-field["padding"]["right"], + ) + label_bmp = self._reassign_indices( + label.bitmap, + field["color_index"], + field["bgcolor_index"], + ) + bitmaptools.blit( + field["buffer"], label_bmp, field["x"] - label_bmp.width - 3, field["y"] + ) + if field["redraw"]: + # draw the text box + # This will draw a border around the text box + textbox = TextBox( + field["font"], + field["width"], + TextBox.DYNAMIC_HEIGHT, + align=TextBox.ALIGN_LEFT, + text=field["value"], + line_spacing=0.75, + padding_left=field["padding"]["left"], + padding_right=field["padding"]["right"], + padding_top=-7, + padding_bottom=-1, + ) + textbox_bmp = self._reassign_indices( + textbox.bitmap, + field["color_index"], + field["bgcolor_index"], + ) + col_index = self._color_index + if field["focused"]: + border_color_ul, border_color_br = col_index["black"], col_index["black"] + else: + border_color_ul, border_color_br = col_index["light_gray"], col_index["light_gray"] + textbox_bmp = self._add_border(textbox_bmp, border_color_ul, border_color_br) + bitmaptools.blit(field["buffer"], textbox_bmp, field["x"], field["y"] - 2) + field["redraw"] = False + + def display_input(self, text, font, fields, buttons, width, + height, x_position, y_position, buffer, **kwargs): + #pylint: disable=too-many-locals + button_font = font + padding = 10 + if "button_font" in kwargs: + button_font = kwargs.pop("button_font") + padding = self._convert_padding(kwargs.get("padding", 10)) + control_spacing = 8 + button_height = button_font.get_bounding_box()[1] + control_spacing + padding["bottom"] + + # Calculate total field height + field_height = self._text_bounding_box(fields[0]["label"], font, line_spacing=0.75)[3] + field_area_height = (field_height + control_spacing )* len(fields) + + # Draw dialog (and text if present) + dialog_width, dialog_height, message_height = self.display_simple( + text, + font, + width, + height, + x_position, + y_position, + buffer, + padding=( + padding["top"], padding["right"], + field_area_height + button_height + padding["bottom"], padding["left"] + ), + center_text_vertically=False, + border_light_index=self._color_index["light_gray"], + border_dark_index=self._color_index["black"], + **kwargs + ) + + max_field_label_width = 0 + for field in fields: + max_field_label_width = max( + max_field_label_width, + self._text_bounding_box( + field["label"], font)[2] + padding["right"] + padding["left"] + ) + + if x_position is None: + if kwargs.get("center_dialog_horizontally", True): + x_position = buffer.width // 2 + else: + x_position = (buffer.width - dialog_width) // 2 + + if y_position is None: + y_position = buffer.height // 2 + if kwargs.get("center_dialog_vertically", True): + y_position -= dialog_height // 2 + + y_position += padding["top"] + message_height + + # Add field parameters and draw + field_width = 100 + y_position += control_spacing + field_x_position = (x_position + ( + max_field_label_width - (field_width + padding["right"] + padding["left"]) + ) // 2) + for field in fields: + field["font"] = font + field["width"] = field_width + field["height"] = field_height + field["y"] = y_position + field["x"] = field_x_position + field["color_index"] = self._color_index["default_dialog_text_color"] + field["bgcolor_index"] = self._color_index["dialog_background"] + field["padding"] = padding + field["max_length"] = 9 + field["buffer"] = buffer + y_position += field_height + control_spacing + self.draw_field(field, True) + + # Draw buttons + # Figure out the maximum width of the buttons by checking the bounding box of their text + total_button_width = 0 + for button_text in buttons: + total_button_width += self._text_bounding_box( + button_text, button_font)[2] + padding["right"] + padding["left"] + 2 + + button_spacing = (dialog_width - total_button_width) // (len(buttons) + 1) + if kwargs.get("center_dialog_horizontally", True): + x_position -= dialog_width // 2 + x_position += button_spacing + for button_text in buttons: + # Calculate X-position so that the buttons are spaced evenly apart and within the width + button_width, _, _ = self._draw_button( + buffer, button_text, button_font, x_position, + y_position, None, None, False, **kwargs + ) + x_position += button_spacing + button_width diff --git a/Metro/Metro_RP2350_Chips_Challenge/element.py b/Metro/Metro_RP2350_Chips_Challenge/element.py new file mode 100755 index 000000000..b472629bf --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/element.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +class Element: + def __init__(self, walkable=(0, 0, 0)): + self.chip_walk = walkable[0] + self.block_move = walkable[1] + self.creature_walk = walkable[2] + + def set_walk(self, chip_walk, block_move, creature_walk): + self.chip_walk = chip_walk + self.block_move = block_move + self.creature_walk = creature_walk diff --git a/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-8.pcf b/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-8.pcf new file mode 100755 index 0000000000000000000000000000000000000000..bdc475829f7302997325c3028eec670b091eba65 GIT binary patch literal 204884 zcmeF4513q4dH?U90auAQYSdMtTrlXO0SAe&YJ?kD!Uh6aAZUOng9Hp3V8tLC$e+8r zvzyr@=&Dgyj5^xXMoZgmOWU+f>qu8kTiT{AZPQBIsZCqjQr)(+UE5TCpYNS>vNyxb z&RW|(_W7N|^SSSP-uFH4Ip@89=FVnA{M&Es@9;d&hg0Ej;CW>vBJHn7t_?jer#?Z| z(>(7WeT`B4rURb0<#f-BOh3=a=|A$k*z}ja6y-?ZC8j@pp64z7HrdIg@yfqA3R4|b z(dk;0|AkuAE8*2r-T)U!Sq2wLSq0Zgc{kh&-YIaGls?!jMfpdq@-YQ}8a^XSH~hFP z2jOc{{t%8x`4)>&? z?z#2`Z^b>g-L__P|83ri3Ty@*}JMO*H zyKdF;tJiqfde>dH<{c}0*7Vk$SKocloy0Hi>ACs3H8-rftZw!CR<6Bl)y>zfyzw%x zZ}rNn*VNT(FS~B_s_WORTz&P;YrRb82JgDQ<(IC!`f}>C{Oy-ryZrLYZcgX$F6~`@ zEfd~+?PZs*ylxF^UU}W>^9mO%z2La#va2s$-J_xBd6%y4yWv``+taRYzvb53qDQ|J zt=Vu}bk*H=-MtB0bm`sq^xu8YEt~GR`>v>e-N6uW=nn58c$)~IreOvlb(Td>Qz7I+H>j^KIfeC&O4`@84Gp#&Uw=X z=h$MLbDlY2nWB1YZ|+S`qIb>p%X>^Y>({of0@I$0$tU=Z(6dPqv8@|MBT z(b4S;8ysTT@HS~AP!=T^ESW3`an{yEs|ODak7@;@L-nMiqa)ku+K5u^+*KY*moccd z4DKi&Kd3vZLwU^F(tV`E(%^J0v);O<9i>`1O{MPf%=P{5JihaE`{^9)jjd{f%rTUV zjFh*q`t3u5L#6Wl$;c>MNH-{rZn|l-bOg4c!E{wrGA(DO%jy}M4x^^ZGD>=lD3#Jw zCQCgejVqU}LviWkI(e)mT_hSy8`)}3ZK*!FY?O%++icm>IBly`-khi!^;0`CI-+Ha zY)emV-7z{kHo$_?3uH%nscg}(ExID^SJE`SR#4iCEg6<$OD5l#&XEpDs*Ubo#EuemL2@>sJ2!&vEdd%Y-WdG?UbtFFDS zDD0TdWy66jjEoXIwzGZ~hAAf@*@I5<@K`c9%z^c#2W;j9Gz8Cf(-782akNqrWDn`Q zW4cLn{ppaFDZSRxBBm=X?~p^6kM@?X{sfJMr&nTwH@(nRzxpE6%;|E|%-S1uVXUz+ zhpyA~q@dwd#WmZ|30i$N*~-Isch*|NM3U>q!p(SN;S%* zrwb%4Z2A;PuP|Nh?8sIl-T7<{Qf(L4ZnBdLgq4z@R8obMlzVzOV>^D{>Xocd&OWG> zCfEIuPOiPFF2nWPC0%%W%F@joUnI*-uknV>q+7s|jia2pN?2riDyY4k&0JTb$0r}v ziBC_|ahuLZ{VeE;7^>gcJ9OEmcek|T`RpA!WUrF?)np56S2epnmTOj;)oi{8^<-ep zV>?YgZkO~H(sNP|BOUbM*?%S4dct9FY%U$~T_c6uKT4|9&p9ZFqBMs(2KIHa=IFJSW-RsVFU-^n8* zdWLZy>1t0OEo^m&(@3{|&QpgjM5+NTc% z-H1w`h8+Kd&;y`;Qf7-itJU-AaVV{RNb8(B(0KkSU%GJ8YnQfrd~AKWI*n=lOvP2n z^picU9|xsZu{jlK{Wzp&5SzRzqA6_JO;1HSwtkM%GpJKRUDC4KGo!KTyT#ZT-t;qN zHdUHs_B|r426fg;2Ul@Dvl65)EPBZ35vivIHuBkPgUgIyE;B}O7~v-7scasq=`Pda z=!(!IS0VN?OZTfv)-NQp0iA`0POZ*h{amK? zvxlv`Z;bM~H8QFqd5j~_+jbWUW zZLE1jQ>KR z^XMocJ9dyop8>3|l)gs{GC6OhY33a}NX0?JcJT-w<}k!r<1n^aPcwCgbUE%E&_Ug? z;~D`aUR*h7xjJyEs7oPO&{lmh*(xn{q+Mxae3dDcw%1F?h^;D#7Rg!$6Fy01>z9^J z^XemTJ8Pz#>49w#T4rx){YaoL@53hU+ z+fJQddoau3R8T~cHXbNDm!3IrDw>=;yy?l)TbfR-P8pX4!Rae|+D%WlIgQ+=rpqND zF9#mx#}8CvY>e&+2c_C+9HXOLlN@w2r3XsFb*}@ZV=X$QT_!4xaQUQ{6dwuNd5Jr+ z#0lVj(^+7IIi$O^C&g^qZr@&9y24T$2W)z);!qwd=|i3UrdO=4$*sf5&il9V+`E4} zXH$nU9ZVMom*ei;6l|9cB)dO7%mx!OIJlih{QbI4^`se7K9hwzd1pd!GL(+6W1C;a z>7{HB=>?p^lvoc{K2!8*rPnAk$Ftti$!Bb>HIsQv z-)y+M^}#o{#%$>)onA>eQGC+PzHw_Tn=x7D(ioe*L7AGS)lHuanR9f!;&{1DbPaJX zu@3S^%SFw%hi%EOUG~72-jYi4fISSR6?#B#$j1--C`TXB>47KV=vIF8qDwOwRnpNx z=GdV_xqcu$pJi!MZbW6_rv~XkpU%2DH*YKP);BxCCdj5DZihZF7?B=!>ow2(M1;Fr zw)zjE^u|4yz6A1ffi3BWfBiF*>pp!z>GT*)_kywQ+BLFW9|YV6R%2V(^zhYzuUhE~ z%MKp2x?a-vNj~FCThrBZHSt!UN0r{gwhfK#+98efJcrT;lpcpHjYpN1yQ6+EpYePY z4Ug;?8|EcrjORKctq;JFkU~<()4m@ter?n<<*pW{wbBw7^_q|q?#OQT>T)& zu(4^)C3)+akH=91{TxXL^Gd>J%C21{6|tP?uwCV>Yw1}~uzvbcKX66p9Z6$}8yy@P z+s*4y`o_JZ%qz)`a{38D#d(;UU_K%EG#I7JIpRG>FRtmsO^59|)9Ha{@rO1ujQbkho>Sbg#2+vnKk^xNkHTlflk{{tM-?yN>WV@pG3gIVtOq4bd2 zSlafX2Q+Vbm|X$)s(EiuH?5b??dd0&UdmN9imfZV@t_Z3UEccfN%J>fy?k=V>kCX8 zLbvHl@9e8?{ppwn*I!}v0c2KSUvSftmp&A9-pI_kOb_YHSo#{k#j2Mq4#UItFn?S6 zGRA>h#~jS7n(d|z^Ge5i9Y4r32c9qHjVE13>S$(5-=BG%(LrH2!2+7T~VC)k?B z)ort{gXycdJ*4l6y5lpigXvq)39mxw`uH}cI1W_OyqoRZX~*)IOKn`&J9)T~PxIRM zwT8Ia9hp}(Ziv|mnYT3ZrLXqs`&xRAN+k-BzRjgiexp%?^zCbmXJ!2rjQ37`$dMpD zWcSwaa(BWmvoFG_gW0k#hS<_~JuYYcK+Rq>>5CyY{fIyPF2o^yMsU!Vi{1JP@SqO6 z2Y5#Cshb{H8s8y~f5A#OJ$rS|em6+JG;lR(N34L42~A|KCVhq;zy4H+`nNH=jPxQ* zzj^U(LeF9j!^8H_?20|%YHD_crQdAK>vXyn4(VHc`sL#IVN4o}%)VXQw`TL*uYOUR zd|Y9AwNE!_uQ2n?kU0C5Vq5)-V)|_{{Zg17xQ5L4#<{ihD*y{hpBB25`An&QnHovI zZZa>|m9AoYFm+BBl)f2pn6;%}M$; zr$7JJpWvmUeuxlDK!3E|592Ti`XlP2{F(9sSOf*&&%yl|dVoLX_Dir2rr;=l+?a#K z&;#qC1p9zo!4ohI$M_@3JdiJ33j;6#2jB?IcwVj(x?wF0zyutCBQV4IJE0ra!T?Ob z0XPCPo_BI5bi-O0fC;EV&GVkaAM-z_6BfZ@SO)806YPP9;W2p1^E%jj#}Zfr_&e}- zJPcFt1RV3c=PrV!unIN;dw%X-cmy7Ur#$a@IamT~U<(kFvJXkj^Atm_Q^<8n4{U^f z7>5dw>lD_1$`l-hC*f(&TRwNwp zAlIqPeJb`-*8^iuJqXP6f`zaQHozWW9WTJ1?|`LHgxzoej`AB63m}3R*vAVeU<#h{ zyccysH>`y%Pyu`|BHxS2_u>Nd0^?rH8eaSe9Dy0nTgdtrl5-*JTUdg9a0tlzl02}M zmyq`*1F#$LzXbnF@V^xQOUeDxb->t{J`9h;)1LP-*7~v@*a(b!*#UUM^Ez2i=Mq>0 zn}D@;PQkS2y_|e6C*RBafcaiN0r+12r02Z?-z)IFVlCi%#XeviuVAjznCrAvfc-S` zore81?28ryxfW5AMSI~Okn5ETU@5GD1jzNu$AB@fS_JrBh3{32d)0n;-1GRw81Hn} zeR>b{1Nly8p3@lx?Nl>Un44JCmGet^(G6 zCOOX}=b2COi!uvfF|htulk?RTVBD*x`7N7;5W{*H2j*JLTxXH*Eap0kxz1v)vmS;c zFyncz>4a`z%xlUp35VgB=e;%p*6>>9d2I!l=e4Y%i#2pHrfVHAri*#Hp76Z0J75Vg z&)JMQn=xlI=Io=M_qrV5d)+En4<%qoJInLb!dto0u4CFrd z02~44IG22HVE#8S*Bh3=D%c3S;bC|TraiBahXV9LKa9g99ENGnJ1-9f=!1S3he
s|)yfU(_-?PhHEQO|pG4hn$p%_Z0eQ*hMt-jahQz`SqS2)p57U~g}k z@w~UP@3(ftS{Q%{H~>drhF=rwglg$+=K{ZNG(F#ig2tmpt@S9HQ6h@cDD--@Nc{43bQ zie6X+YhW#`g8|qA2~5Bw90KyMnDM;J$$L4uE{}mRm-hqlm+yr~;Bk1$^Llfz7?uI~ zdx`5Ehy6glUh=KrOyek-U1$nPn1?0Sfm@6KJDjb2Q zJnu^8zA^&lzOo3LfVr<^?kk!5${Me4#H?Bb#H?Ba8-bWr2Z3Cx9*3tr@2Wg3g;lTt zSl?B|T}7^|rhvGsj)G#3dEV9Jy?OyG1lDl%VkiLfT-^)npdZRmfk`0G)vW#Mr#x>p z<5x3gHDgvYW_2GhX7wgu?$vvN^{qY%)BGAGbM-9+V){xz&b|Y17|3@G`L0<6#9Xrq z$Z-uZ*Bk`qyw(H!*LK5NV4iEo;Q%}i%yC^F3eX1wuov)OhyObKYgogYC4heo3P@Vzn(o^zXpmx%=P0y4X>}l5t#A3x3iA7FNIaG9@x*@_rYWEl;^#JJnvWn zH#`PUd)|%2+(?ca z$#G)|_QE6ZIN-l&AuNR+Am%3W+_VXZy=e~+e-rs`IsnXl(;=Agymei`y4Mw;8yLTC z74*S6*Z|~NN1k;L!y|AI$gz&KtvdowdEPrc=mhe-vlkfq&VFFrJDK~P#J{uVdGA^P z%=xYuHo`cN?_KzA?f`r@GxyDmy_s=0Gwx>c7s*{@ZAI)w?8QUywCCLt!5T>5VPHM) z&OrgzK^a){yKDTC??Q-S17N=u`>n*UCw_ewkY_!4){|#F_S>-EMxNWqa~tuu9fT)6 z?{@Os-VH^-e)}XGhGU-ho(NXK0PF+o@4>!-{2R!>f&3eocSFtd?pOfizk~dDV84TT z?;!pT;@?Z2_x8dD7>7xC!t>te!4l|$El`2SVA}IGE`k^sv#|`!v$5uRcXmJ*F#nwi zFwdRr?@q?tm4^cK0sgzz!a5+wU7LXTyLQ6_u%Ejo;UFCKyt@}bCou2b-N5*}8FM$W zcN25>6YwNF&DT-Z&`(_dGGLAUMJU03I0WQ-e-65UT<>2C13<3#Gw1u+an(wUvaUW#eA6yE|^}!85%m)tuc|JJpdG{>55ilG2$li!4m0oYMkv8PV9YRar5r2<)>mR(CDv17 z4JGC)k-KyRraf<@0~W$kSOw%7DZyS~JtNFL@)UndfqbLn8)e?nH9*|xZg?0TgQq-i z#{wt->)Npa5}1HVI0QAA;csx{p$lSI3;j@r3LJpL@TBLBdC&<3SOpt^wT%%sM%);2 zW7GT<2j<<$+IF(Go$Fu#_P`_@f*Kt2yj|qlwFF`yZWnR8#$i890dc!#Ja2a%h}+!@ z>mh*(RDqZWJz%~E@juuP6Tn;#9s>Ev@u5!WhP5yN``|FJjt_SMV?VqB%CH~E{oy0^ zAE}LZA$y<*2~>dm;|GEBG5(b2eZ+%2u#S%~&qsQJJ$;0^KC%~x{m2t=%=13F2*~%* zjW7<60KSjqfPH?f4>rMW*awGzIrc07^6yy&YhWX=o;`bjHSd`M^6Z)RypMN4C-gu+ zkn7`np$aw6`$P`N^@&x$T%VW#e4jY#d7otLC-HqUhPA->PnLj~Pd*I9eewuA?RgW# zPAq}~^uRhG-vskb>;qyaSkuI`=Y1*%5iEmVSOWvF7bal}$or|MJntd$KC~E!eTcY+ z$obG7VE%`Qd+0Eb_tPE__i5rjP28t9LJ7u!yq`V@ievu0IamZsVHK>0EkNGAC;0KK}?j z0nGb_JU{oioOkO^^n&O26cdl9Z4)r1_8PJX73eZBiPvk8-Us6_08E<3_aha*7@h?A zA~*{BU_Ts!m%&*E7Up%s2IztUDEDKq3hsxhAwk9h?=0FXBnBHVyB)7J_CgE?;1KkHZ1T-O9wI}G%rZb~8Jo^C7k9cY z#mkpKV@oiI#+G2PbfDYuMf6V4TGb>IkUtwYO@AEnP=E+xP%FYka7)5n3}1vVz&^uQ zJYvx=MrwSQVF|Jaw!jJ)0?l7GNZ$=5Bh?>(DPv2JLVnrg%Z`!VqCE2H{3ZtVtu85F z)|S<6oYp!8w*Mh?t@}}suarUgvVG}E8&vZ~RF5Oj58B5BOhOIDL4C!v%dh=tonJS6 z5&31qL&%SUa!eWaA@>;Uc^EK0?Kz9a$fr4MtgU&1&9V&r-LM?KYFLT99dvzYe90hv z0_@&K(FaUFLDrxXa-cDa{~qWXYlY3-Oe(kbbP4nr79+b1%DFq{nG08lgrBq+&O@Hz z)yJ+!YK+zY?H8=1zYT)og|C?F&F6zF+% zBfJ-Ghs9uH6(=H<^qKt0sRcz~F z0uoS5T42}PkAD&>P=&)FTVm)&YVWaO+DJQ(`r`)aB~ZL5fbO?^MkeT4=%y{U>RHjpMlTAkAlv#Z1NRBYnV3lAuAcwp8@3+HLy8<5ncHtzXUd? z_Em+7kr7hJE-BR1FG2({)Sw8Fp@xhhf$=72&GLyY@T6e_va1CNb`e80gZiQfb}s1^ zPz@~VKMGUOYj_dzHE=mx0$IPt={v_6#TwaeT4ack36!B9 z@&-hz+r8S)L)Bsh3_+)fL9~rkUgc7=y86xX>iU{*?0nuifK?xFrblK#KKyws~uD+VC$HXv`(PfiQV*BblK$7xm^otC73eoLpHt}N7z(*HG6J{(6eZ~ ze2SZIY=KyNZMMssUGIEiN!@m>n}NuHNb6Q=A#E)p z1=3o@$*$Of0ns+LPeHVHIXj5Sr;+tN^q{wTKTq%p?a}6yE}Q6waYMz(GIBp0fC%hd z+D|WZ8>u+i4{6s%H?5C+ zvPF;w<+VEM@p${(vhj))YBpzMjB*LJRxw?5cT0a2e{5nTTan;XOIi?PuYg+If(mxE zxCL6P_R|5{&nhT^tw|sHB&bcpcoQOQc~G-8QI2dL`P;=5h!JY7@@Tzl(}=la=E`B` z(79DpU-M1CemG>9M#d0<+ISNb6B!UKV~Y5MTB|&Lb$3gD9)DzF%E(@W#uXqk#K^=j zjT{HX3+b{YhCZZPyL{dCu=E^up^IkkLaL*hWG`r(WEo`BxK2>ZgZiRbu3qc~P-~U1 zU5T@SP0GBh)n46zKX*4ANzjPjL~b*>xr8LTi?-0NtRbzQ!s?VvsIdvsmRw z3^w2Qvo?mdTvr!9txat{>&nJ9TUQ@>ib_VCf!(0JWsyz3=NUAwa+M9zWz)ORT<=NC z@OPNlX5*DZ%|5debj>Sik(HL;zO668)-0FC*w|M2B4X6q<;vH?j-NXl zZ`Wn}331KVqVbDhu61zXED;3u@Ta;x^RqtHmv-U@wAN z+=dGN8mPrBNU*n~YGM#`#?Ch`nIq3AzDB-?Z6EA~3aC|D5MeJuC+KGeYP!}MDPubV z{ZNGpsKs-T;M22y0w$pby7tspz7pgO1!Q7SYz3-Dsy_~qp@?jZsbEt~Y(N~(mo(95 zu*JrXI6h9cW+d2Kp9(TN3mv%3C#L?X7g>$@(-t+m~JeNlT0_`i-m_ z86))^lgv_W=;!H2pjLt@!#-rQpH)QI)uut~ZKPce&8KU#0MkvzD_;>JBNZpq+U4#i zrl>&LG>kVP!6sDO_0ZFR>{C!`!UVQfdGq)R&<$z>pgcnj$R?jqlk5dMpLE%}K>5_v zpDUNfWMhBOe2sHA%XeQ=|6LNTdk4B*|6}y;tJZ&0Qh(;T16@Ap4pw=#Tl^CH`gQN)&Hla2E+Ft@S z=!6`UKyzuW5vcWpVvC?S>9R$jHLA7CS0F}X)FhkbYnLNpTpo(hDo2FR#`K}9uhuTN zVhd?x>)h@BY+l1Pw}=h3jBag3Y-+Kg3#l<`?dIqsM${l~ph&-Qyq>$tZHduEtwG9G z1g&K)sOeg0h3ctwOoG~Y6Q;2#POViQ*%hN$wN`n0@fFgD_PLa!XkuICQ?5RcY`3-| zF%^(hYn4;AQ$DqJIW>1hfwWfn+U1BC+d0ShJibM+08Rz9-SOPN|Dk+Bt<|4X%dfqv zJqkUr1iC?UW+~7YYGu%Q6n!9jWQdXT&6y`wsOkF7K?ledK@nm&2G)j}KG(E%Ym1F- zzPTde)n=es9<6`Ax%!DMfLg13ReZ@D4B*o>5`gaeA<$>l6v(G@uk~~rDLrbSMt?JW z4TeEEEH;n+tmF#NTteqh`9}Lp`8#x&pKg*$bei zoW0O(WZBp%$Qab(HdOFeK`m~9=G3~>H0Km(Em>rfPit#jpRIw`+8ASf&7@+B2E_52 zjc4>}bUR-kdb2#%rhJN5Q>@x}6BLt&2oz_>H|dN#Jz zpHF4i(C*JPwZ=#j)3m+`*bj#c(@48+&8_FB_8?mkYEU&OwgN>+pqjz<4`Zu9pOIB$ zY)FvSU(48JZ)^z$OKkKAsqxCKJ#;~{bCh8J3RED1i;a{n)c?HU4AYm)QlT%R797O> zEm#g;HAsIqEQ85}zYT&s1@v=jdtR-y<1fXhapDp<6ZB`05ooV!Q48|eRfAS_n88;z zNZ$=5Bh?ql95l<{L%i0h&mLVXiJ>uc4WsKss2{A!w0 zbGO=$oma7&K=YIh(q)Sv2DKU_P&HEeG(-l(oIkJ8e2D>ZT(>qWBYcNJZM+GZv(@}zwSwW6Nl%as$XV89>TQQAHV@nK*QLG(TK#!mXiJ_R$ zWvf9RB2Zm4zGRRto9@ZQP3Xs_{c2tzeHs!&H!?OPMrutRAh``RN8^0T5j9~PTO*3q z{rPs#{VLXg=FS^5hbUy|H?}fzUlRtfMTX@_JwwI}Hy}R<6;O*?&?hHtyb06T@&-i9 z+DG_eP-~T^1D{Z9wbs76yY1(r&b3|F>C%%r3z7Pr)yRN&*0VjqmPIwxxs`3&Na<4` zpHTf1s6i*>pae6Jw4s7uEpCIYPgZK)BhU}JetHa-SJ9(czCmBHmS+-l+2XqVF#X1w zy%3wNn`FVO*9~#}`A|Wxg5)?%fad4|)j@3t?7CzZc|#GYI<-Qd(~&`A?09|7D5v(k z0yIaq*3x%_@=B^N%7#|{1b-`*;ahCb+*wpRtwCtbi9z#NT~fZODu0)g&ROWM0?FIx z_rO$Kzs9uA4p7Y{g>2JM0_|xp?16o76sADFKF~Nd_2-J6z&{QZs2Zuh?3!;2^t3?p zJqlkpd=c5~Jx*&7+Pl@Q9KbdOs#_M>Om8Ni zA+DL-+Vm{&3^mlqpgo+CLH)rD-$mE|L14s4^^*+E&W&oW^QE<`Zgvl{$@gIxPwGro zx!%F{<=Y0TsnB}f2xpr9qe$iGg>ECu#-_PqH~^2q6!gFh z7<$QI{jw#X7}@k5z6La>*`lR77QdnCBy$X^- z_AQ{jXPKg}bD-KhZg>Q_4>U$hXLR-L9!u!L?y)gWvBKK5H(_lFy0H0d-{zaa7d1gS z6eIee0Ffa^b{MuJS3)_dBV9J@&yH6Ptk!PrI-iYvuZc}Dx;K48 z4H<#1)x`$sw!TlJ?=eVE4AV%vR_XnqHFbm5R0i4hf}YXef-e|dHm$wapfS=9K^Lf5 z|1tCg(ls}@k!SlvX`L<$|YU41k{oiRIsbXbI{J8 z5U>S$;Bq=W)jHomAIBziUhQ}7&!SI53|hPP&`1$m3~G~5fvSaW=?=fx-bQ^gsQujw- zm_Uw01*%4>FS}~gVVFc#plYOa#pMl(KMWP98mayfP@YMsLDfj<<50?=`yksNrEk}% zSTSv+bj@kkr*XZ80#f8NXbsliXZ(tZ42|QpmS*EM){fWM0g$`|)HOc0{U7w1RaJcq<9>3-gJE|G~|$F*bh&F=I(+HNHWZz>ocd6Awd_@Fx~{^QoPow zdv6F-|0$49^g<3)8|l`raf-L&q&JSU=hlu(h!KaO4{8t@SwtpKH8kq#TVnKlrZ0O9 zs*ubR!cJ%jJ=I9-nuZFfKLP4@f@*Hj-iig**sSHS94Y4JeP+ zWyf1N*^#zC>usQmegUd54daHx$b17e<5Mo{mrZ-CqEs9uZ6#e zKZXdF!D6t_;$HL!8tn--t+@y>BpEbk1ZqV{V6NCI{t(o()}e%J1N3>Vwg9Bt>q~Xf z9C=s@i$F2bhhQ5t)>nPiQe!1Gz6cRemJ`;myg7s7EgBO;#ZX0dLYI-6V;q#P)jiS5 z-p!a8l8lVdt57jAMkdfGWfQTHRU_4xZi&$oLsplq3X)l3`XYfE#2G5+(~v;ifNUZ* zvWhH%Y9nff2$?0JFMkD!5F08;AzvPfP=Ojm8RWP97+oZW$&7Aol2xcd1*VOxB7GPH zJ)>G(e+j-As-TuY+yeQkpq4<~Kr@?-k*^9dBnGQjO+U#CvqCLfL-{nHTGpP`<+JNnezmM$Hu<$s*K1ErPtE9~m1Wq^Lm^;tUbGsDWB+C?acMTZE$A%BvPZ71UxwgcLQ14G~h* zK&=Xik%*>oHS9%DiwxO))vy&oEiz>NvUNf?sM+h%O4U&NP>jZ@S)Y|Q#`dk0eV|Fa z{H?~!rCP69_QXFchI|9C0oFkTdKN8)V-Q0T)QXUR_FIG)k_^h@!w^Qji)3}oX9lN&a;dfY4C=(EXO>#4809+|axesg2|w2b<<_-Ogo`0b z>UPCH2Tp=)ykbSGcdiIu_ZP4v(s^$e*XVDSt3V#*6I!#-To$csE?qwVPKE)_D2l^dj+4|r$ zvFH6pv5s`v_C?2+jk`&T`kuSB-}Aw_m`9UGc1ymR)hp}KNTT{1Q?Ra z0c6$aH6szJt%@u{1Wc30*N{Tjdk)mv{hhHqF+%NApx=qU5#9^8!(vdb`R3Ey?egjR zRcp64{hUax)w(oKmthIA2Xw8jfFV#*jOy46-A0y;4Us-GI+1qG?Q#|}v90pj8fb0p z^2slhSE#khE5BmrlQ$wx%qOq*FXoe1`68H4-frU7!hG^7MzQnBn>RTT$Lpc-b6o@T z$*X*d>j1626YN~A^2;xJL1WbhKz-$qEQ4(F%hm}R(`9J3?#RSwe7n5LH{ZO<6~TP+ zDyP;spYQbdKIhv9fQO$lhI|9Pc4E0P+l7^T{bnHA6qN+ZA^mR zET>{MMy*xe4fy)fi1zuqh+Au7TjkSynpZj7txvHwUSrf+<&E$urVrZXRjg2aySz4L zK6w>8-@N_APQrZh+PW&gP-|5O`IS?xT^$q?!F=*6HV;)uKrLxQ6@LtBaSIacbAkJ~ zKdU#6u|Cyh3iMf;MK<}=v=3Xq61vFVN2*6RC{C?iPQ_T}6vaamiHJeG3Oz6LSz&8T9xBUpoL z)Oihh;>}V+uNop`Y;?&85<{HPC(%Wv0lKMu8kvI*$QvSLY)Ft*kQ7xTrDv(q&yw|7 zU4E;#l5@q#H%D-3>ZIeOsR&=0m233}Ps zEemNa=b5k^cEBz01yG(R;grPlUWkm4m%^jy&BkAb-Hunj#gH9;W>O!o{NI|x zFQ3M1ey!2YZ^y^j5_qOsuU(8@1IbpT18{1LbkvsAj8FAQ62^e^7>b~C8#keru@%wV z#VNiUx}d}8+HV=gp$K`y2BdsFPy#(yv%il%M86e^O(2E{Y)cBuss_IMs7#Hh~MS1jRWRl-6*)=wfohF~^){Mqj z+gHA3@v=>Wjcb&1tz)iyt$eCSD_<-7Tw~h#m@YjB73BAe-Mf_uIkM;)tF%DA1P-?F zPh;19t!&)8=Im;Le7b+0Y~fF^H)8i7S!qG5{b&yf$ltim>>jk2xz^mwr#*ClU0;Hp z#oDdR`lMG{(5mip#V6!yHLl&hoB5mVS2pdrm9Lpy@f~xF(>Ryn&Szg)f*zdH6 zX|^vrrd{41b^fFHgY?CgVZO#1W z<9y5p7+p5on)!bjr`~UE?WD_Q`;C6tb#FJLjNKxCwFS@A$Pe~<>LyNXG3Z@JR6(`Y zb4>jis6hhi+ju+P<~teRt6-any9jwI1Q0==!LHTz<*ZK|` zDg9}qSCN)w=#Rn|V93aI$Zn8NYyA`W9=r>-Kqriw{=1PHHw>2;eg!!Ix;89YyVe;Q z00%*)J*kJk^({0fDbd9Vr{a&PE#TH{zd=YA(yrKv(bV3(I z8EWXlp0_j6Ew4ep3ywk&5>Sg=X6U+z zq1AOEfA1Xr1fK;p)yI)VkhGwt_p5Sc(fvOSIZ)e|VG6wr{g8lKD}S!;KEeMuwzc!U4K#hJLw4Sv_uOSn|3{t*6P+Vk~L>_`N z>^JfNvIdc%Vq^{34-;TxrOP%A;|A&Z25QEqc#T8 zIzZzkMfQ5kUQaXl78{ltIfYC>Eoni&oV4tGb}oC($X|mzXiY+T4T_*vgK?OE!(jah zy3ksdzyS1t_OuFOsDfGoaSN*0)shB^^nDnF?Vx7Y-^v~n6G08s;tUab4b);oV;=2a zbF{K+Tm&^xt3hmtkTp=NK@83EESkfvF%i^2tqK*0A%YsHRiOep7h11ccCJ?TDseHW z#SlRast|)(3=z~o^$=>={H^R&;)GfZ5!9e+K%8LLI`s~-Ob%Lhj=6jZu|=qXS_~1? zAb}#(KrMy{Y7jsOYMN^(ssFvAR(9Mc?59G%2ocmEfhwpKp<-kWsd>VL11&pOD|?kV zp%z00iV#5!ss_Zf<{H2jK^4XgF;aF>fXAQ$lMsXKMd$=Q57Z(<5!uYHF%eYZ03;BD z?845Ipie^#vKOHf>^zEVW>ahgRX70S5QFT(=2z}Xh(Y!ubb`&_hpyNnG_z|=1Xb7% z6A**!LSt30X_$l1Ge25MD<^wT%_Qq&-UDyYSV2q|h1LlJ7A7D3+7kBp%RHBgHn>zA%NsM%+=l@r*MV?Hqv zamv#TYBq*{ITFukw&(5d(MVN#b5-5V~(?+V_=r3TK&-{d?HC%vfw$|)g6svhHMfApb<(mez z$RJx08eo}jnF#z=~&39^d>bk2m%m)a8e zJNPrGLIO1-t4P}tl(-31Y-&jpirC_e9W`w+$1Dkb3+i!Qwjx9j8;NLn4MzB4kW_1R zt;YBo!Iat(WGjmJ)RGKwMn4(7+4Y@`AtZf{HeTm8Mp7+?2x<^RVkF`OpX~FcNURTo zkp1~UGh0kd1T|2L4H2>iYB5wnEryDrW+WnQMUEAyLH0S3omX{J%i3zG<;49qv$e|E z%3dXJvplWr_BkZK&RYU8$Sw--7$hKn46+xY6YO`N2)zi6HpNCzg~SjeWf$4}3H=yk zFG43Me^yt#nqnfTLSl%KHYe(F-L5~u78`qnR4am=Cqh>%g0;oyA~MvFu^~c=8YG|= z8zQ8rK>}*AAwr58*k_iN6WIFau;=lq*?24MxOV=Nk`w=~bD3P4ua!NAPv|^k^?-hu zaGSG88l=5J-svDn;r=I>%NZa`yO*tNzU(D%En?tAstYFs!D6u2bc`Os4{Gmik>|h5o{(SHR}o@JGN|^HKHbOKjJ=9(eF?hOG7UwDK)R$_ z5fYedjtIZnTysTfL_H=!w{ynEUPMNqxkFI%VJNBp+^?A}#;+Db1&R}C>d0fcK!-6YB5xx2ocnv0%}F57+FK+LEm2%f##Jy1o|#Bm#=_7h6IYB z*lB2G@4(kc8JqSesr@zj)o+Z6u{Ba{VpELlMTnpuk_<)k2pa8qY}$kDhoMY>@_E;J?Waz*u9{=%GN5j8(*{d0`?dpsDWAyVu+vyYBi{WTCc(GAx~er=7>Qp z2K7~Q&8z3(KS7c~dsnVjd2B2p>F+G)9?Ry^-bEi2AToMCGKR!R>CM)HIgOKFD3|Di z0z^jdN5;@B$2W`26M5bR1pGGoZ@~pg-6o%Y=ZB^rZ@@D@U?Yp~1zzaoypuT9&*8Rw zF8|A!Qz*;xnd${xhA;G9#6N7c(0hsZQvM=9r}uL272at)LSD(QBc0Bc&fwQtUd>0= zS>9{B*HZekz1MlK=WEqD-nrfz*!Fq+Q!3~4sCkojfp;NWezW%$@2#A^xAD)cTud33 z^Q%9X@@wmt@xSu8oYS|GzxH`0e;jy~ceS^g(p|$pWpW+AnsYt>gxNdzhYRBl{)Z^<^EP^S@=H2*b0fXqyT|(g z|5)F>{G(>~aZ_yOFIzsqFUxG@!MUA_VvvXEFgMHyf6-zG53w=+;>a!@=nr}y;-8%v z=bse)DF2kh9`EDcC%jMc0rn~W$19)aCi{%{S?_b)#GmIEsD6Y$%>7aR5se??4;Q|~ zUpo15?_uvJyr1-bikttZy`S-ZmS2|tIq&DaU*HcpevyAz^OyPMtY6_Tq&=&Sq^ z*01r0s$b(DO!@|Y!2RpqZ+O4S3;Az(zwP}F54PXsABXvU{)hU1;QgWZNBn~Xf6Oms zeUo3n|5Lv7{y8_|U+|YL{*qrt`YZ3Ry}#j?G5(e>#DDKS<^2P{6!je*H2=tr_RstR z*uQxH>irwPAn;xOa?F45g7TmI^3OBA=lg!(hknjK$v@eDj^E)w*MFXWiod{rzJIF! z0zdD+(0`HtVt=9k691+C%luCN<^C)D)BHvLEB#mbr~8qAhJU92YJahRmj4?6wSJd> zw*NZ+_5Kq79RFPZ4SvBt&wrzTzQ5FelYfDKq2KMl*?)`wR)3lQHvgizuK@pI`Te+c zl)v1+WDf78eot%f+#dfje}#X!-|MgRukf$*SNT`@SNp5|KK~m3TK_tK&D^8s^7_~N zZ};Efuk~;6Z=5UchtucZ^uxKXAAD8*I{%$qZF4@A{G0uve~bTa|5ktf4?ZKa-R9rU z@jbJ-{0+1Ed^P`$`9}UQ#rf}@U5)=ff1`h=f0uu^-|xSlirfPq@HhGQ`XBV~^9TIR z{{8*~{uY0$zs=w7C;p&6^#8~|;{UP#C;m76 zC;UJ4|IGh$zvlmi|1JM7{iFV0`G4*IjsK+oxBlPxfA2r#|AYT+|2zJ)|BwDZ`Ty)c z?f;Aaul~RJGyZq|fA{~xKj#0Z|2_YifcKNY4}u^Ja=}T#$-#4ij^Me$^MX@?1$dqx zoccdkmwM*l1wlS|VelgLf)@u1Q~8qMrNPUB&Uys)mj|z~dR7Lf1&e}L2CoWE4X9cgBYfSLkpldF_^ZoBuAUHdCUGVx~NpMbZZt#Yn5S$mhF*rY1 z8oVjEAhnf{|b}*b$V2v0!JgE7%=87^T8K_9|`saKN@^7__1Jr@TK6(!H)+I2R{+~ zWbjkLWbo6$&jddkJQDm|@bkeh1P6j&41Ov2<=|lOE5WY@UkR$gSA$1`Ukj#!uLWNZ zz7ZS>em(e&;5UQEg5L^$JNTX8aPYgq?*+dfJRbZ(@Q1-41xJEE4*n$gX7EJtr@@~E ze;(9=zX-k+{AF-7_^aTrgTD!$4E{FwyWsDGr-FY7z8!ogm=69i_^05XgQtUk3H~+s zw_qmtZt(BHe+0*Z{|vqtJQI4M9|mC<=E9T0lf&nP9pQ7s=Y^+)3&Q7zr-m;G^Wh7_ z7lkhl7ltnhUmCtF>bEK*M?o;+2QNL z*N01H>*zFB0apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ6 z0apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ60apQ6fgk1ygy)3k zhHnT9;d$X3|10YZ&kvV|ZwfC6FATfGH-~Qt-x@9p-xgjJUL3~Z^6--I(y%AIEL;&@ z9`=SS!z;oo!&Tu`;nm^lurItOyf(ZpToYa&zCCt`BbuZx7!SZV2xP-y6O!+!)>&-WA>*_J{8e?+HH;ZVK-WKN#K@4uqS-`@;vq zE#cO1Tev+;!ohGT91ct2NH`kq2+QGExHH@p?*6ar(~bH6s{-MJ;fKNxhvW5KhaU+) z8h(twO|mEac=(C%li@`8sqmrj(^&R~p9w!}qCRJ2CH#E&h44qhefWPAz8L;k-J@f; zKl~EMFT;;#tPjuXKd2V|MEH~8Plc1=Pls*(24(oOKj>Wb@!=!k&q)h^K0W?Icp&`6 zy66ASG5n?0YYl%n-Pgh95#g`Y?IC|>G~2?jWP3k|9#+GzX2*w*hQAh0g? z>)|)TL*cK7zY+fCd}atAn@`jaS4{X@_4S0m-MFsscethxhrcU(_F{5|e+~aFoC&`h{(JZz;j!>P!|#R9ub!V|2K@>Ysu1;JKN-ZUGDY&^^9($tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3tAMM3 ztAMM3tAMM3tAMM3tAMM(|9=(8EyAi z+}hj?xf^pg<<{linR{36=3Fs%OYYtO-79waTm@VOTm@VOTm@VOTm@VOTm@VOTm@VO zTm@VOTm@VOTm@VOTm@VO=2L;(t-1B{iEE6>-IlvO_nzE_Mms-Cz9aYE-1~AHb9d(M z%H5s&f9>35bmT~yw&Cn9shOFX(UFqEcC*t?H#0LcGcz+YGcz+YGcz+Y)ZVu$<>PTz zSI_KxKjzyrwdZw#jzM_B^*kvSYGSvU9QvKktg&lHI9$ zBzsc#O7>3nN%l?lOZHC=NDfR6N)ApANe)d8OAb$tNRCX7N{&vBNsdj9OO8)YNKQ;n zN={BrNlr~pOHNPDNX|^oO3qHsNzP5qOU_R&NG?n+N-j<=NiIz;OD<2YNUlt-O0G_> zNv=(-r?r1JIUOz?J{^=M|Lp7k6JM96=?LkF=}76w|A}Y!-*fuAE0B(oj{0}6`S0`p z{uM|^`}Z^cuO_6Ur(>jJremdJr{kpKrsJjKrxTuHweX_3aXJ?%(4)49^Q(|OW) z)A`c*(*@G5w2^kFJ!v!TO&3fTN*7KSNf%8QOBYX@%-Nmor*OIJ_VNY_l)O4m-;N!Lx+OV>{~NHvm zUjNJ$NDmqEs#&nZ7=Sg-Lse1723@8#peI{KdK`GN2Mi{H!ZLGE82`|?`31HW(o z-^;bx8VlbyTx&j;^R)W>)_3necl}=Gl*iWGE1$2v%fMs5@A+5f?R+W6%=0jF;ITTN zVI0eI;`#FZ9;^BFcjM6S`RW}0VLbohGy8w%@_X^R>R7$sbMST5_Z~PtfBAdsGpp;; zm+Q4}tftto9ECvkMdak&hzDayuPi+{Js1x{NDfP z>UodlOc1!j{$tXdX3MO=Qotslky6@z(V!bE@}O$NrhE$IL15 zzW$kgeYW4V==;8{^Xq@z`hKp?rQiGfKGpMm->>z&zn70y=T^OMKu-V9_WF9=JXYu4 z|1+wetIsUwV71@&JD2kL0iRP|d(Xl18QQV+`s#a_{cmv&R2i+gP@aFkxmC^+e{Y>r zHD^5k@;mrA`d(LE!`89yb=Bj32VdWMe|hvg{JlCCkNoa6F0Xg%XW!@V&bjhD%xYbe z>e}^XwDPMlc8;rhU3DzSvH!g1Jk2PtL+iZC@80@sKesxsVI8adf96=7bNSlV_u*59 z`Z?8gE6=I={(p6>uK7@o)n^X#*t&+*XAbRHU0;s_uW|q9`u|*AlYe-O>swvt{*U+n zxq9EQj-I2>SM#y&`~A&#sXp6dnbA6*>hm4za_q~28G5O{|InWuGM=7K_0P{5_-|O> zt^aeLS2dr@aUr+tq0EJW$MU;52mDU|fyZi1RY$*@=lQ=n@*T_f4dd9?Gg@oy?_OU$ z|997KXk%IKtNty=_ZiqP`sQY<-}o9I^F2fRS3d4MbkeCZMAO7&v$ONKEtstA8Vag-_N|i z{Mn;g=Tjd2`TsYq?@^7H-+!R~{igiRyvNu3x^i5+f2h8<*Q>fV)wScf{@1hY2aJW+ zzI<)#b=5ii#WeZPeAw?$oxgi8|H|v-W7RdOj@9+3USG|7uV=NF^IUbUs_W!6^4e6N zVK@wtJ&|1;;} zHSu+xLwW4?d-ZvJW6(N}zTaEDuR8zg^Qtka9spRWHJ|)^bN#H=v3h;~ z$ExT09|yfLq$&BI8JGW3>L?f!<6&Ydm+V_u?Tuj%V;9Uc=k?0H5M3e2-r+nDI$4GWd$a zjf;seIi|skm<<6Db7KKCu?UvLa#$H_U|o2imK8ZY2gyoLAi3BJU4_!)mNu7fZVM#ngq5RUiMm;tk*4F%@H{OG~L zSOUvpC9IBhupu_X)^N`3ioLKu4#AN)4kzOboQsQaIj+HtxD9vX0X&MQ@H}3@n|Kc& z;|qL?pYS`qc6f}4(J(e9z@(T8(_iY99)RYa5Zkgt+)&K;}JZG=kPM#z`OVepW_?+h~MZR!(jxBim@<0Cc%`L z4l`p8Waz-WXkbAshNZCrR>fLaADduHY=@n(2lmB5I2^~|M4X1RaRDyHRk$9v;7;6! zhw%iS#Y=b{@8CmxhOhAhe&xS6s)3S@f-x~3CdL$)7BgXX)X|Q4(1l(silwkTR>7KB z4;y0(Y>S<+JNChWI1ESQ1e}Vqa6T@_XIN?0B1U_)$%t+4}k#a`GShu}yYhm&yz&c#Kz9M|AR+=jdH03O9tcpk6d zO}vMX@dducPx!r78);boV+E{=wXi-m!Isz#J7W**i-T}Dj=_mI4QJy5T#Bo3 zJ#N9BxDOBG2|SCJ@H*bXhxiO%;|KgYWZNGl$ z!tz)JYhpcYj4iM&cEax12M6LX9E}rjD$c_BxCB??I^2vqa4#Oh<9G%y;x)XD5AZ3z z!uR+EgKM=>6O4>8FfJy-RuZ z0GnbfY>!>AC-%d^I0DDwB%F?Oa3LthpaiS4j6_Q1Y42#4bsoQTtK zHZH)WxC+)w;~jj6&+s*Vz^_AY`NvE-j)E~U9wx>Vm=-f(cGS_1 zdC-MkEQ+PDJXXP)SPvUx3v7#>usim_fjA6D;{=?Fvv58x!IiiUH{%Z6i-+(yp23TF z4R7NEe2TB|J$}L9T5YTZBV!DVi-|BfrooJu4FM5zV*xa=2$sZhSQ%?zU2KHSu?=>_ zZrB?K;7}Ze<8cbk#CfimK8ZY2gyoLAi3BJU4_!)oHYGV(=NEjXC zU_wlWsWAg)MH>pth56Bgg|P&d#Y$Km>tI7{hOMy!cEw)UABW&b9EX!}2F}GrxE$Bu zM%;$G@cAyEKb7dI0qNvGF*)ta4YV@{dfdV;yJvG zH}Eb#!sqw~KjODqZKB~Y0!GDH7$1{hN=%2DF$XeqU|uw^AQr>YSOKeIEv%1CuqC#` z&e#L{;vgK3V{jr)!`Zk1m*Og1k6Umj?!&`)0?*i=D7L_Q8QT3`gSxoQkt>J}$wP zxDGet4%~}}@Hn2qi+Bxh;{$w(ukby7!QfhLk_01T42+A3Fgd2djF=4p5p!b!G_eSl z#Bx{}YhYb$gw3%HcEoPj8wcP}9EIa?3eLoNxENR9THJ)&aStBEV|W@b;8nbZ_wfn7 z#CP}^f7EJ|4#G$n9phj^Oopj317<}V3e1K1(SwDt1eV20SRLzNLu`hvu>*F+Uf3Up z;7A;YlW_*l#YMOr*Wkvswt8EQ5-fE~X2~suC0g1o9hOc@m!)Cpw)9wb(`01UblJO=5?FbZC7t9Oh z1@nS=!MtEzFfW)F%nRlP^MZN7ykK51FPLX*3AUDCYYDcNU~37smSAfMww7RP3AUDC zYYDcNU~37smSAfMww7RP3AUDCYYDcNU~37smSAfMww7RP3AUDCYYDcNU~37smSAfM zww7RP3AUDCYYDcNU~37smSAfMww7RP3AUDCYYDcNU~37smSAfMww7RP3AUDCYYDcN zU~37smSAfMww7RP3AUDCYYDcNU~37smSAfMww7RP3AUDCYYDcNU~37smSAfMww7RP z3AUDCYYDcNU~37smSAfMww7RP3AUDCYYDcNU~37smSAfMww7RP3AUDCYYDcNU~37s zmSAfM?dEk@I*qc^1UpUW@-Z7laB&6~XK--_7iVyB1{Y^=aRwJ>aB&6~XK--_7iVyB z1{Y^=aRwJ>a4iJaLU1hv*FtbD1lK~{%UQQ&)NL7cyG7lox>0qb>PFR#s=LlJS5M~Z z$y_*@>mzfDW`4n}gHy{oIJK;U(5!>dtb@F)!`F3?mvs=8b(AmW46;u1I?eNvWSvHJ zn$l@XrzxGLbehs>N~bBEoK@CoRHtXvX0&Yi5elQnm;=1$h!$(lP^b0=o*#LS(Txf3&Yb?2_`-2FFq|1ErP;d=|;Tln6> ziC#F-3nzNvL@&%M%qz?*%qyJeg%iDSq8Co|!iiou(F-Sf;Y2TNWQC2au#puuvcg7I z*vJYSSz#k9Jio&8E9^dn-KVho6n3A&yNtrSjKaH&!n=&ZyNtrSjKaH&!n=&ZyNtrS zjKXhOl;6_3jKZ6V!kdZ0n~B1kiNc$S=+cPJ?C4aE&f@4Sj?UufERN3N=q!%T;^-`n z&f@4Sj?UufERN3N=q!%T;^-`n&f@4Sj?UufERN3N=q!%T;^-`n&f@4Sj!xF-WQ|VN z=wyvf*63u7PS)sTjZW6+WQ|VN=wyvf*63u7PS)sTjc&8i85^Ck(HR?^vC$bD-87?{ zW^~hxZko|eGrDO;H_hm#8QnCan`U&=jBc9IO*6V_MmNpqrWxHdqnl=Q(~NGK(M>bD zX+}5A=%yLnG^3klbkmG(n$b-&x@kuDl<1}zJIw1aufx0!^W1Ern@x1HiEcL0%_h3p zL^qq*VV*lq>@d%5C%XSe7hQDGMHgLk(M7kN=(ZDGe$nL@-FBkePIMtg7h-fFMi*jq z+lg*F(QPNX?L-%6ba6)ap6K2a-Fu>YPjv5z?mf}HC%X4U_nzq96J5^HYPjv5z z?mf}HC%X4U_nzq96Wx2Fdrx%liQbn)mveMEN0)PSIY*asbU8tjJcgTM9>YyBkKv}6$8b~3W4I~iG29gM7;cJr{EbL4 zkAbI{$G}s}W8f*~G4K@g7}|hOS`4R;ybwap)@SMmwO+I z@8!0K5-fE~wD@AS1d1=!knV|S$<{HI!FvBRk!@p+h{xM47g#25QQvO7We`Qg4uYX5Td>GO6o)8w+`LFC8CZ@i8wQFSKw%b+1sJEwx@}tEBL0b+)W}ogIhb+t_C) zye%^{H6rLy?vchKz$Ea{*3WuU#cc%Cg`zpns*zPC>u-#Gk3WeXd zV7sGm;srNo6jQiCqj0)~SEKN16kd(Ot5I;5Rxdo=!qY9-ASvc~;)N$(ut8GHV}qoa z=Li;#VBrWBG!%;OV2`5snAf@RIu~B&!s}enS|~o|fEEsD;edK?M)5ILe7#^fQ~Z@x zOYtOGeiT2PB~3C`K`46r<<| zy$!~V;u&xgNb$Yg|55ld4Hgr{_j3P7@x9#tQ9KRq|0tdY3xZ+_3xZ-43xeWluplVr zu^=esu^=esu^=esu^=esF^4GTu^=esu^=esF{LQxu^=esF~cb4u^=es(b6d9amPq8 zk2^++dE7Bl%;S!cVjg#l6!W-aq?pGYBgH)K7%Aql-YDj=fm6(5`BBW{j*(&>tC38c$yAR)8T14JWYqE>F{`mM={Ug@eYq-p2O30 zc)Y`-nCI|#het8b;qeZSVxGg}9UjFz`Z&cr?(it)afe4Sk2^eyd9-?pdGvdVdEDVq z%;OG^Vjg#R6!X{;DCTj8M=_5(Jc@bj6%_Nh!=sqT9UjFz?(it)afe4S&pG5B9>qN8 zkau_#^PEH8;Ze+U4ta-1G0!>V9UjFz=a6@J6!V-z-r-Tq;|`Bv9(Q;Y^SHyKn8zJn zuXlJ9^UCSN9UecK#~mKUJnrx)=5dEdF^^k&3VFSh*8h*7TJ?|rezZ0`1`Yms@UQ%z TO$;9VBfllJ(fFS+IM)6LzWbO2 literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-Bold-10.pcf b/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-Bold-10.pcf new file mode 100755 index 0000000000000000000000000000000000000000..ea6a221abf41884526e50d4bdb08b73960c2cd8b GIT binary patch literal 330244 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

X*f5W7Z$?L!q3C`;TPeT;ev2s_*M9I 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 i: + return victory_messages.get(i, "Something went wrong!") + return None + +class Game: + def __init__(self, display, data_file, **kwargs): + self._display = display + self._images = {} + self._buffers = {} + self._message_group = displayio.Group() + 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._databuffer = DataBuffer() + self._color_index = {} + self._init_display() + self._databuffer.set_data_structure({ + "info_drawn": False, + "title_visible": False, + "level": -1, + "time_left": 0, + "chips_needed": -1, + "keys": [False, False, False, False], + "boots": [False, False, False, False], + "viewport_tiles_top": [[-1]*9 for _ in range(9)], + "viewport_tiles_bottom": [[-1]*9 for _ in range(9)], + "hint_visible": False, + "pause_visible": False, + "message_shown": False, + }) + self.dialog = Dialog(self._color_index, self._shader) + self._input_fields = InputFields() + self._show_loading() + self._savestate = SaveState() + self._current_command_set = GAMEPLAY_COMMANDS + self._keyboard = KeyboardBuffer(self._current_command_set.keys()) + self._deaths = 0 + self._pw_request_level = None + + def _init_display(self): + # Set up the Shader and Color Index + self._shader = self._load_images() + self.extract_color_indices() + self._shader.make_transparent(self._color_index["key_color"]) + + # Create the Buffers and add key color for transparency + buffer_group = displayio.Group() + self._buffers["main"] = displayio.Bitmap(self._display.width, self._display.height, 256) + self._buffers["main"].fill(self._color_index["key_color"]) + self._buffers["loading"] = displayio.Bitmap(self._display.width, self._display.height, 256) + self._buffers["loading"].fill(self._color_index["key_color"]) + + buffer_group.append( + displayio.TileGrid( + self._images["background"], + pixel_shader=self._shader, + width=2, + height=2, + ) + ) + buffer_group.append( + displayio.TileGrid( + self._buffers["main"], + pixel_shader=self._shader, + ) + ) + buffer_group.append(self._message_group) + buffer_group.append(self._loading_group) + + self._display.root_group = buffer_group + + def _load_images(self): + self._images["spritesheet"], shader = adafruit_imageload.load(SPRITESHEET_FILE) + self._images["background"], _ = adafruit_imageload.load(BACKGROUND_FILE) + self._tile_size = self._images["spritesheet"].height // 16 + self._images["info"], _ = adafruit_imageload.load(INFO_FILE) + self._images["digits"], _ = adafruit_imageload.load(DIGITS_FILE) + self._images["chipend"], _ = adafruit_imageload.load(CHIPEND_FILE) + self._digit_dims = (self._images["digits"].width, self._images["digits"].height // 24) + return shader + + def extract_color_indices(self): + for key, color in colors.items(): + self._color_index[key] = self.get_color_index(color) + + def get_color_index(self, color, shader=None): + if shader is None: + shader = self._shader + for index, palette_color in enumerate(shader): + if palette_color == color: + return index + return None + + def reset_level(self, reset_deaths=True): + self._show_loading() + if reset_deaths: + self._deaths = 0 + self._gamelogic.reset() + self._remove_all_message_layers() + self._databuffer.reset(( + "viewport_tiles_top", + "level", + "time_left", + "chips_needed", + "keys", + "boots", + "viewport_tiles_top", + "title_visible", + "message_shown", + "pause_visible", + )) + self._databuffer.reset() + self._keyboard.clear() + self._pw_request_level = None + + def change_input_commands(self, commands): + previous_commands = self._current_command_set + self._current_command_set = commands + self._keyboard.set_valid_sequences(commands.keys()) + return previous_commands + + def input(self): + key = self._keyboard.get_key() + if key: + return self._current_command_set[key] + return NONE + + def wait_for_valid_input(self): + # Wait for a valid input (useful for dialogs) + while True: + key = self._keyboard.get_key() + if key: + return self._current_command_set[key] + + def save_level(self): + self._savestate.add_level_password( + self._gamelogic.current_level_number, + self._gamelogic.current_level.password + ) + + def tick(self): + """ + This is the main game function. It will be responsible for handling game states + and handling keyboard input. + """ + game_mode = self._gamelogic.get_game_mode() + if game_mode == GM_NEWGAME: + self._draw_frame() + self.reset_level() + level = nvm[0] + level_password = self._gamelogic.current_level.password + save_password = "" + for byte, _ in enumerate(level_password): + save_password += chr(nvm[1 + byte]) + if level_password != save_password: + level = 1 + self._gamelogic.set_level(level) + self.save_level() + + command = self._handle_commands() + + # Handle Game Modes + if game_mode == GM_NORMAL: + if command == PAUSE: + self._gamelogic.set_game_mode(GM_PAUSED) + self._draw_pause_screen() + self._gamelogic.advance_game(command) + elif game_mode == GM_CHIPDEAD: + self.show_message(self._gamelogic.get_death_message()) + self.reset_level(False) + self._gamelogic.set_level(self._gamelogic.current_level_number) + elif game_mode == GM_PAUSED: + if command == PAUSE: + self._draw_pause_screen(False) + self._gamelogic.revert_game_mode() + elif game_mode == GM_LEVELWON: + self.handle_win() + + # Draw every other tick to increase responsiveness + if not self._gamelogic.get_tick() or self._gamelogic.get_tick() & 1: + self._draw_frame() + + def _handle_commands(self): + command = self.input() + self._keyboard.clear() + # Handle Commands + if command == QUIT: + sys.exit() + elif command == NEXT_LEVEL: + if self._gamelogic.current_level_number < self._gamelogic.last_level: + if self._savestate.is_level_unlocked(self._gamelogic.current_level_number + 1): + self.reset_level() + self._gamelogic.inc_level() + self.save_level() + else: + self._input_fields.clear() + self._input_fields.add("Password", InputFields.ALPHANUMERIC) + self._databuffer.dataset["message_shown"] = False + self._pw_request_level = self._gamelogic.current_level_number + 1 + 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): + self.reset_level() + self._gamelogic.dec_level() + self.save_level() + else: + # If not, load the password dialog + self._input_fields.clear() + self._input_fields.add("Password", InputFields.ALPHANUMERIC) + self._databuffer.dataset["message_shown"] = False + self._pw_request_level = self._gamelogic.current_level_number - 1 + self.request_password() + elif command == RESTART_LEVEL: + self.reset_level() + self._gamelogic.set_level(self._gamelogic.current_level_number) + elif command == GOTO_LEVEL: + # We need to establish fields to keep track of where we are typing and the values + self._input_fields.clear() + self._input_fields.add("Level number", InputFields.NUMERIC, 0) + self._input_fields.add("Password", InputFields.ALPHANUMERIC) + self.request_password() + return command + + def show_score_tally(self): + time_left = (self._gamelogic.current_level.time_limit - + math.ceil(self._gamelogic.get_tick() / TICKS_PER_SECOND)) + time_left = max(time_left, 0) + level = self._gamelogic.current_level_number + score = self._savestate.calculate_score(level, time_left, self._deaths) + previous_score = self._savestate.level_score(self._gamelogic.current_level_number) + best_score = self._savestate.set_level_score(level, score[2], time_left) + score_message = "" + if previous_score[0] == 0: + score_message = "\n\nYou have established a time record for this level!" + elif best_score[1] < previous_score[1]: + difference = previous_score[1] - best_score[1] + score_message = ( + f"\n\nYou beat the previous time record by {difference} seconds!" + ) + elif best_score[0] > previous_score[0]: + difference = best_score[0] - previous_score[0] + score_message = ( + f"\n\nYou increased your score on this level by {difference} points!" + ) + # Update the score (with new total score) + score = self._savestate.calculate_score(level, time_left, self._deaths) + + message = f"""Level {self._gamelogic.current_level_number} Complete! +{get_victory_message(self._deaths)} + +Time Bonus: {score[0]} +Level Bonus: {score[1]} +Level Score: {score[2]} +Total Score: {score[3]}""" + message += score_message + self.show_message(message, button_text="Onward") + + def handle_win(self): + self._draw_frame() + # Show the level score tally + self.show_score_tally() + + # Check if we are at the last level and set game mode appropriately + level_check = self._gamelogic.current_level_number + if self._gamelogic.current_level_number == self._gamelogic.last_level: + level_check = -1 + if level_check in final_levels: + self._show_winning_sequence() + + # check for decade message + decade_message = self._gamelogic.get_decade_message() + if decade_message: + self.show_message(decade_message) + + if self._gamelogic.get_game_mode() == GM_GAMEWON: + # Show winning message + self.show_message(winning_message.format( + completed_levels=self._savestate.total_completed_levels, + total_score=self._savestate.total_score, + ), width=200) + self.change_input_commands(GAMEPLAY_COMMANDS) + else: + # Go to the next level + self.reset_level() + self._gamelogic.inc_level() + self.save_level() + + def show_message(self, message, *, button_text="OK", width=150): + buffer = self._add_message_layer() + self.dialog.display_message( + message, + SMALL_FONT, + width, + None, + None, + None, + buffer, + center_dialog_horizontally=True, + center_dialog_vertically=True, + button_text=button_text, + ) + current_commands = self.change_input_commands(MESSAGE_COMMANDS) + # Await input + self.wait_for_valid_input() + # Clear message + self._remove_message_layer() + # Set input commands to previous + self.change_input_commands(current_commands) + # Maybe remove item from sequence later + + def request_password(self): + #pylint: disable=too-many-branches + current_commands = self.change_input_commands(PASSWORD_COMMANDS) + self._draw_pause_screen() + while True: + command = NONE + while command not in (OK, CANCEL): + self._draw_password_dialog() + command = self.wait_for_valid_input() + if command == CHANGE_FIELDS: + self._input_fields.next_field() + elif command == DELCHAR: + self._input_fields.active_field_value = ( + self._input_fields.active_field_value[:-1] + ) + elif isinstance(command, str): + command = command.upper() + active_field = self._input_fields.active_field + if (active_field["max_length"] is None or + 0 <= len(active_field["value"]) < active_field["max_length"]): + if active_field["type"] == InputFields.NUMERIC and command.isdigit(): + self._input_fields.active_field_value += command + elif active_field["type"] == InputFields.ALPHA and command.isalpha(): + self._input_fields.active_field_value += command + elif active_field["type"] == InputFields.ALPHANUMERIC: + self._input_fields.active_field_value += command + if command == OK: + level = self._input_fields.get_value("level_number") + if level is None and self._pw_request_level is not None: + level = self._pw_request_level + password = self._input_fields.get_value("password") + if level == 0 and self._savestate.find_unlocked_level(password) is not None: + 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 + self._gamelogic.current_level.passwords[level] != password): + self.show_message("You must enter a valid password.") + elif (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.") + else: + self._remove_all_message_layers() + self.change_input_commands(current_commands) + self.reset_level() + self._gamelogic.set_level(level) + self.save_level() + return + elif command == CANCEL: + self._remove_all_message_layers() + self.change_input_commands(current_commands) + return + + def _draw_number(self, value, offset, yellow_condition = None): + yellow = False + if yellow_condition is not None: + yellow = yellow_condition(value) + + buffer = self._buffers["main"] + + if value < 0: + # All digits are hyphens + for slot in range(3): + bitmaptools.blit( + buffer, + self._images["digits"], + offset[0] + slot * self._digit_dims[0], + offset[1], + 0, + 0, self._digit_dims[0], + self._digit_dims[1] + ) + return + + color_offset = 0 if yellow else self._digit_dims[1] * 12 + + calc_value = value + for slot in range(3): + if (value < 100 and slot == 0) or (value < 10 and slot == 1): + tile_offset = self._digit_dims[1] # a space + else: + tile_offset = (11 - (calc_value // (10 ** (2 - slot)))) * self._digit_dims[1] + calc_value -= (calc_value // (10 ** (2 - slot)) * (10 ** (2 - slot))) + bitmaptools.blit( + buffer, + self._images["digits"], + offset[0] + slot * self._digit_dims[0], + offset[1], + 0, + tile_offset + color_offset, self._digit_dims[0], + tile_offset + self._digit_dims[1] + color_offset + ) + + def _add_message_layer(self): + # Add the message layer to the display group + # Erase any existing stuff + + buffer = displayio.Bitmap(self._display.width, self._display.height, 256) + buffer.fill(self._color_index["key_color"]) + + self._message_group.append( + displayio.TileGrid( + buffer, + pixel_shader=self._shader, + ) + ) + + return buffer + + def _remove_message_layer(self): + # Remove the message layer from the display group + if len(self._message_group) == 0: + return + self._message_group.pop() + + def _remove_all_message_layers(self): + # Remove all message layers from the display group + while len(self._message_group) > 0: + self._message_group.pop() + + def _show_loading(self): + while len(self._loading_group) > 0: + self._loading_group.pop() + self.dialog.display_simple( + "Loading...", + LARGE_FONT, + None, + None, + None, + None, + self._buffers["loading"], + center_dialog_horizontally=True, + background_color_index=self._color_index["white"], + font_color_index=self._color_index["purple"], + padding=10, + ) + self._loading_group.append( + displayio.TileGrid( + self._buffers["loading"], + pixel_shader=self._shader, + ) + ) + + def _show_winning_sequence(self): + #pylint: disable=too-many-locals + self._gamelogic.set_game_mode(GM_GAMEWON) + + def get_frame_image(frame): + # Create a tile sized bitmap + tile_buffer = displayio.Bitmap(self._tile_size, self._tile_size, 256) + self._draw_tile(tile_buffer, 0, 0, frame[0], frame[1]) + return tile_buffer + + # Get chips coordinates + chip = self._gamelogic.get_chip_coords_in_viewport() + viewport_size = self._tile_size * 9 + + # Get centered screen coordinates of chip + chip_position = Point( + VIEWPORT_OFFSET[0] + chip.x * self._tile_size + self._tile_size // 2, + VIEWPORT_OFFSET[1] + chip.y * self._tile_size + self._tile_size // 2 + ) + + viewport_center = Point( + VIEWPORT_OFFSET[0] + viewport_size // 2 - 1, + VIEWPORT_OFFSET[1] + viewport_size // 2 - 1 + ) + + # Chip Frames + frames = { + "cheering": (TYPE_EXITED_CHIP, TYPE_EMPTY), + "standing_1": (TYPE_CHIP + DOWN, TYPE_EXIT), + "standing_2": (TYPE_CHIP + DOWN, TYPE_EXIT_EXTRA_1), + "standing_3": (TYPE_CHIP + DOWN, TYPE_EXIT_EXTRA_2), + } + + # Chip Sequences + zoom_sequence = ( + get_frame_image(frames["standing_1"]), + get_frame_image(frames["standing_2"]), + get_frame_image(frames["standing_3"]), + ) + + cheer_sequence = ( + get_frame_image(frames["cheering"]), + get_frame_image(frames["standing_1"]), + ) + + viewport_upper_left = Point( + VIEWPORT_OFFSET[0], + VIEWPORT_OFFSET[1] + ) + viewport_lower_right = Point( + VIEWPORT_OFFSET[0] + viewport_size, + VIEWPORT_OFFSET[1] + viewport_size + ) + + for i in range(32): + source_bmp = zoom_sequence[i % len(zoom_sequence)] + scale = 1 + ((i + 1) / 32) * 8 + scaled_tile_size = math.ceil(self._tile_size * scale) + x = chip_position.x + y = chip_position.y + + # Make sure the scaled tile is within the viewport + scaled_tile_upper_left = Point( + x - scaled_tile_size // 2, + y - scaled_tile_size // 2 + ) + scaled_tile_lower_right = Point( + x + scaled_tile_size // 2, + y + scaled_tile_size // 2 + ) + if scaled_tile_upper_left.y < viewport_upper_left.y: + y += viewport_upper_left.y - scaled_tile_upper_left.y + elif scaled_tile_lower_right.y > viewport_lower_right.y: + y -= scaled_tile_lower_right.y - viewport_lower_right.y + if scaled_tile_upper_left.x < viewport_upper_left.x: + x += viewport_upper_left.x - scaled_tile_upper_left.x + elif scaled_tile_lower_right.x > viewport_lower_right.x: + x -= scaled_tile_lower_right.x - viewport_lower_right.x + + bitmaptools.rotozoom(self._buffers["main"], source_bmp, ox=x, oy=y, scale=scale) + sleep(0.1) + + for i in range(randint(16, 20)): + source_bmp = cheer_sequence[i % len(cheer_sequence)] + bitmaptools.rotozoom( + self._buffers["main"], + source_bmp, + ox=viewport_center.x, + oy=viewport_center.y, + scale=9 + ) + sleep(random() * 0.5 + 0.25) # Sleep for a random time between 0.25 and 0.75 seconds + + bitmaptools.blit( + self._buffers["main"], + self._images["chipend"], + VIEWPORT_OFFSET[0], + VIEWPORT_OFFSET[1], + ) + self.show_message("Great Job Chip! You did it! You finished the challenge!") + + def _hide_loading(self): + while len(self._loading_group) > 0: + self._loading_group.pop() + self._buffers["loading"].fill(self._color_index["key_color"]) + + def _draw_title_dialog(self): + if self._gamelogic.get_game_mode() != GM_NORMAL: + return + + data = self._databuffer.dataset + if self._gamelogic.get_tick() > 0: + if data["title_visible"]: + data["title_visible"] = False + self._remove_message_layer() + return + + if not data["title_visible"]: + data["title_visible"] = True + text = ( + self._gamelogic.current_level.title + + "\nPassword: " + + self._gamelogic.current_level.password + ) + buffer = self._add_message_layer() + self.dialog.display_simple( + text, + LARGE_FONT, + None, + None, + VIEWPORT_OFFSET[0] + 108, + 160, + buffer, + center_dialog_horizontally=True, + background_color_index=self._color_index["black"], + font_color_index=self._color_index["title_text_color"], + padding=10, + ) + self._hide_loading() + + def _draw_password_dialog(self): + data = self._databuffer.dataset + message = None + if not data["message_shown"]: + data["message_shown"] = True + buttons = ("OK", "Cancel") + if self._pw_request_level is not None: + message = f"Enter a password\nfor level {self._pw_request_level}." + else: + message = "Enter a level number\n and/or password." + buffer = self._add_message_layer() + self.dialog.display_input( + message, + SMALL_FONT, + self._input_fields.fields, + buttons, + 200, + None, + None, + None, + buffer, + center_dialog_horizontally=True, + center_dialog_vertically=True, + ) + + # Update fields if needed + for field in self._input_fields.fields: + if field["redraw"]: + self.dialog.draw_field(field) + + def _draw_hint(self): + data = self._databuffer.dataset + if not self._gamelogic.status & SF_SHOWHINT: + if data["hint_visible"]: + data["hint_visible"] = False + self._remove_message_layer() + return + + if not data["hint_visible"]: + data["hint_visible"] = True + buffer = self._add_message_layer() + self.dialog.display_simple( + "Hint: " + self._gamelogic.current_level.hint, + SMALL_FONT, + 100, + 120, + HINT_OFFSET[0], + HINT_OFFSET[1], + buffer, + center_text_vertically=False, + font_color_index=self._color_index["hint_text_color"], + background_color_index=self._color_index["black"], + padding=10, + line_spacing=0.75, + ) + + def _draw_pause_screen(self, show=True): + data = self._databuffer.dataset + if show: + if not data["pause_visible"]: + data["pause_visible"] = True + buffer = self._add_message_layer() + self.dialog.display_simple( + "Paused", + LARGE_FONT, + 216, + 216, + VIEWPORT_OFFSET[0], + VIEWPORT_OFFSET[1], + buffer, + font_color_index=self._color_index["paused_text_color"], + background_color_index=self._color_index["black"], + padding=10, + line_spacing=5, + ) + return + + if data["pause_visible"]: + data["pause_visible"] = False + self._remove_message_layer() + + def _draw_tile(self, buffer, x, y, top_tile, bottom_tile): + # Create a bitmap of the tile size + tile_size = self._tile_size + if 0xD0 <= top_tile <= 0xD3: + top_tile -= 0xC2 + + # Bottom Layer + if top_tile > 0x40 and bottom_tile != TYPE_EMPTY: # Bottom Tile not visible + if 0xD0 <= bottom_tile <= 0xD3: + bottom_tile -= 0xC2 + top_tile += 48 # Make top tile transparent + x_src = (bottom_tile // 16) * tile_size + y_src = (bottom_tile % 16) * tile_size + bitmaptools.blit( + buffer, self._images["spritesheet"], x, y, x_src, y_src, + x_src + tile_size, y_src + tile_size + ) + + # Top Layer + x_src = (top_tile // 16) * tile_size + y_src = (top_tile % 16) * tile_size + bitmaptools.blit( + buffer, self._images["spritesheet"], x, y, x_src, y_src, + x_src + tile_size, y_src + tile_size, + skip_source_index=self._color_index["key_color"] + ) + + def _draw_frame(self): + """ + This will be responsible for drawing everything to the buffer. + """ + #pylint: disable=too-many-locals, too-many-branches + game_mode = self._gamelogic.get_game_mode() + buffer = self._buffers["main"] + data = self._databuffer.dataset + + if game_mode in (GM_NORMAL, GM_LEVELWON, GM_CHIPDEAD, GM_PAUSED): + # Draw Info Window + if not data["info_drawn"]: + data["info_drawn"] = True + bitmaptools.blit(buffer, self._images["info"], INFO_OFFSET[0], INFO_OFFSET[1]) + + # Draw Level Number + if self._gamelogic.current_level_number != data["level"]: + data["level"] = self._gamelogic.current_level_number + self._draw_number(self._gamelogic.current_level_number, LEVEL_DIGITS_OFFSET) + + # Draw Time Left + time_elapsed = math.ceil(self._gamelogic.get_tick() / TICKS_PER_SECOND) + time_left = self._gamelogic.current_level.time_limit - time_elapsed + if self._gamelogic.current_level.time_limit == 0: + time_left = -1 + if time_left != data["time_left"]: + data["time_left"] = time_left + self._draw_number( + time_left, + TIME_DIGITS_OFFSET, + lambda x: x <= 15, + ) + + # Draw Chips Needed + if self._gamelogic.get_chips_needed() != data["chips_needed"]: + data["chips_needed"] = self._gamelogic.get_chips_needed() + self._draw_number( + self._gamelogic.get_chips_needed(), + CHIPS_DIGITS_OFFSET, lambda x: x < 1 + ) + + # Draw Keys Collected + keys_images = (0x65, 0x64, 0x67, 0x66) + for i in range(4): + if self._gamelogic.keys[i] != data["keys"][i]: + data["keys"][i] = self._gamelogic.keys[i] + tile_id = keys_images[i] if self._gamelogic.keys[i] else TYPE_EMPTY + self._draw_tile( + buffer, ITEMS_OFFSET[0] + i * self._tile_size, + ITEMS_OFFSET[1], tile_id, 0 + ) + + # Draw Boots Collected + boot_images = (0x6A, 0x6B, 0x69, 0x68) + for i in range(4): + if self._gamelogic.boots[i] != data["boots"][i]: + data["boots"][i] = self._gamelogic.boots[i] + tile_id = boot_images[i] if self._gamelogic.boots[i] else TYPE_EMPTY + self._draw_tile( + buffer, ITEMS_OFFSET[0] + i * self._tile_size, + ITEMS_OFFSET[1] + self._tile_size, tile_id, 0 + ) + + if game_mode in (GM_NORMAL, GM_LEVELWON): + view_port = self._gamelogic.get_view_port() + for x_pos, x in enumerate(range(view_port.x - 4, view_port.x + 5)): + for y_pos, y in enumerate(range(view_port.y - 4, view_port.y + 5)): + tile_position = Point(x, y) + cell = self._gamelogic.current_level.get_cell(tile_position) + top_tile = cell.top.id + bottom_tile = cell.bottom.id + if (data["viewport_tiles_top"][x_pos][y_pos] != top_tile or + (top_tile >= 0x40 and + data["viewport_tiles_bottom"][x_pos][y_pos] != bottom_tile)): + data["viewport_tiles_top"][x_pos][y_pos] = top_tile + data["viewport_tiles_bottom"][x_pos][y_pos] = bottom_tile + self._draw_tile( + buffer, x_pos * self._tile_size + VIEWPORT_OFFSET[0], + y_pos * self._tile_size + VIEWPORT_OFFSET[1], top_tile, bottom_tile + ) + + self._draw_hint() + self._draw_title_dialog() diff --git a/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py b/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py new file mode 100755 index 000000000..d896ef45e --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py @@ -0,0 +1,1376 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +# SPDX-License-Identifier: GPL-1.0-or-later +# Based on Pocket Chip's Challenge (https://github.com/makermelissa/PocketChipsChallenge) +# and Tile World 1.3.2 (https://www.muppetlabs.com/~breadbox/software/tworld/) +# +# pylint: disable=too-many-lines, wildcard-import, unused-wildcard-import +import random +from definitions import * +from creature import Creature +from element import Element +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" +} + +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): + self._tileset = [Element() for _ in range(0x70)] + self._chip = Creature() + self._create_tileset() + self._game_mode = [GM_NEWGAME] + self.last_level = 149 + self._chip.type = 0 + self._sliplist = [] + self._creature_pool = [] + self._block_pool = [] + self.current_level = Level(data_file) + self._current_input = NONE + self._chips_needed = 0 + self._moving = False + self.dead_creatures = 0 + self.dead_blocks = 0 + self.keys = [0] * 4 + self.boots = [False] * 4 + self.status = SF_CHIPOKAY + self.current_level_number = 2 + 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: + self.set_level(self.current_level_number - 1) + + def inc_level(self): + if self.current_level_number < self.last_level: + self.set_level(self.current_level_number + 1) + + def set_level(self, level): + self.set_game_mode(GM_LOADING) + if not 1 <= level <= self.last_level: + level = 1 + self.reset() + self.current_level_number = level + self.current_level.load(level) + self.last_level = self.current_level.last_level + self._time_limit = int(self.current_level.time_limit * + TICKS_PER_SECOND * (1000 / SECOND_LENGTH)) + self._chips_needed = self.current_level.chips_required + self._extract_creatures() + self.set_game_mode(GM_NORMAL) + + def _possesion(self, key): + return { + TYPE_KEY_BLUE: self.keys[BLUE_KEY], + TYPE_KEY_RED: self.keys[RED_KEY], + TYPE_KEY_YELLOW: self.keys[YELLOW_KEY], + TYPE_KEY_GREEN: self.keys[GREEN_KEY], + TYPE_DOOR_BLUE: self.keys[BLUE_KEY], + TYPE_DOOR_RED: self.keys[RED_KEY], + TYPE_DOOR_YELLOW: self.keys[YELLOW_KEY], + TYPE_DOOR_GREEN: self.keys[GREEN_KEY], + TYPE_BOOTS_WATER: self.boots[WATER_BOOTS], + TYPE_BOOTS_FIRE: self.boots[FIRE_BOOTS], + TYPE_BOOTS_ICE: self.boots[ICE_BOOTS], + TYPE_BOOTS_SLIDE: self.boots[SUCTION_BOOTS], + TYPE_ICE: self.boots[ICE_BOOTS], + TYPE_ICEWALL_NORTHWEST: self.boots[ICE_BOOTS], + TYPE_ICEWALL_NORTHEAST: self.boots[ICE_BOOTS], + TYPE_ICEWALL_SOUTHWEST: self.boots[ICE_BOOTS], + TYPE_ICEWALL_SOUTHEAST: self.boots[ICE_BOOTS], + TYPE_SLIDE_NORTH: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_WEST: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_SOUTH: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_EAST: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_RANDOM: self.boots[SUCTION_BOOTS], + TYPE_FIRE: self.boots[FIRE_BOOTS], + TYPE_WATER: self.boots[WATER_BOOTS] + }.get(key, False) + + def _collect(self, key): + def add_key(key): + self.keys[key] += 1 + + def set_boots(boot): + self.boots[boot] = True + + functions = { + TYPE_KEY_BLUE: lambda: add_key(BLUE_KEY), + TYPE_KEY_RED: lambda: add_key(RED_KEY), + TYPE_KEY_YELLOW: lambda: add_key(YELLOW_KEY), + TYPE_KEY_GREEN: lambda: add_key(GREEN_KEY), + TYPE_DOOR_BLUE: lambda: add_key(BLUE_KEY), + TYPE_DOOR_RED: lambda: add_key(RED_KEY), + TYPE_DOOR_YELLOW: lambda: add_key(YELLOW_KEY), + TYPE_DOOR_GREEN: lambda: add_key(GREEN_KEY), + TYPE_BOOTS_WATER: lambda: set_boots(WATER_BOOTS), + TYPE_BOOTS_FIRE: lambda: set_boots(FIRE_BOOTS), + TYPE_BOOTS_ICE: lambda: set_boots(ICE_BOOTS), + TYPE_BOOTS_SLIDE: lambda: set_boots(SUCTION_BOOTS), + TYPE_ICE: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHWEST: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHEAST: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHWEST: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHEAST: lambda: set_boots(ICE_BOOTS), + TYPE_SLIDE_NORTH: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_WEST: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_SOUTH: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_EAST: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_RANDOM: lambda: set_boots(SUCTION_BOOTS), + TYPE_FIRE: lambda: set_boots(FIRE_BOOTS), + TYPE_WATER: lambda: set_boots(WATER_BOOTS) + } + if key in functions: + functions[key]() + + def _discard(self, key): + def rem_key(key): + self.keys[key] -= 1 + + def unset_boots(boot): + self.boots[boot] = False + + functions = { + TYPE_KEY_BLUE: lambda: rem_key(BLUE_KEY), + TYPE_KEY_RED: lambda: rem_key(RED_KEY), + TYPE_KEY_YELLOW: lambda: rem_key(YELLOW_KEY), + TYPE_DOOR_BLUE: lambda: rem_key(BLUE_KEY), + TYPE_DOOR_RED: lambda: rem_key(RED_KEY), + TYPE_DOOR_YELLOW: lambda: rem_key(YELLOW_KEY), + TYPE_BOOTS_WATER: lambda: unset_boots(WATER_BOOTS), + TYPE_BOOTS_FIRE: lambda: unset_boots(FIRE_BOOTS), + TYPE_BOOTS_ICE: lambda: unset_boots(ICE_BOOTS), + TYPE_BOOTS_SLIDE: lambda: unset_boots(SUCTION_BOOTS), + TYPE_ICE: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHWEST: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHEAST: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHWEST: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHEAST: lambda: unset_boots(ICE_BOOTS), + TYPE_SLIDE_NORTH: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_WEST: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_SOUTH: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_EAST: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_RANDOM: lambda: unset_boots(SUCTION_BOOTS), + TYPE_FIRE: lambda: unset_boots(FIRE_BOOTS), + TYPE_WATER: lambda: unset_boots(WATER_BOOTS) + } + if key in functions: + functions[key]() + + def _get_slide_dir(self, floor): + if floor == TYPE_SLIDE_NORTH: + return NORTH + elif floor == TYPE_SLIDE_WEST: + return WEST + elif floor == TYPE_SLIDE_SOUTH: + return SOUTH + elif floor == TYPE_SLIDE_EAST: + return EAST + elif floor == TYPE_SLIDE_RANDOM: + return 1 << random.randint(0, 3) + return NONE + + def _ice_wall_turn(self, floor, direction): + if floor == TYPE_ICEWALL_NORTHEAST: + return EAST if direction == SOUTH else NORTH if direction == WEST else direction + elif floor == TYPE_ICEWALL_SOUTHWEST: + return WEST if direction == NORTH else SOUTH if direction == EAST else direction + elif floor == TYPE_ICEWALL_NORTHWEST: + return WEST if direction == SOUTH else NORTH if direction == EAST else direction + elif floor == TYPE_ICEWALL_SOUTHEAST: + return EAST if direction == NORTH else SOUTH if direction == WEST else direction + return direction + + def get_view_port(self): + """ + This function lines up the edge of the map to the edge of the screen + """ + ptTile = Point(self._chip.cur_pos.x, self._chip.cur_pos.y) + if ptTile.x <= 4: + ptTile.x = 4 + elif ptTile.x >= 27: + ptTile.x = 27 + if ptTile.y <= 4: + ptTile.y = 4 + elif ptTile.y >= 27: + ptTile.y = 27 + return ptTile + + def get_chip_coords_in_viewport(self): + chip = Point(self._chip.cur_pos.x, self._chip.cur_pos.y) + viewport = self.get_view_port() + x_pos = 4 + y_pos = 4 + if chip.x < viewport.x: + x_pos = chip.x + elif chip.x > viewport.x: + x_pos = chip.x - viewport.x + 4 + if chip.y < viewport.y: + y_pos = chip.y + elif chip.y > viewport.y: + y_pos = chip.y - viewport.y + 4 + return Point(x_pos, y_pos) + + def _can_make_move(self, creature, direction, flags): + #pylint: disable=too-many-branches, too-many-return-statements + ptTo = creature.get_tile_in_dir(direction) + if not (0 <= ptTo.x < 32 and 0 <= ptTo.y < 32): + return False + + if not flags & CMM_NOLEAVECHECK: + nBottomTile = self.current_level.get_cell(creature.cur_pos).bottom.id + if nBottomTile == TYPE_WALL_NORTH and direction == NORTH: + return False + elif nBottomTile == TYPE_WALL_WEST and direction == WEST: + return False + elif nBottomTile == TYPE_WALL_SOUTH and direction == SOUTH: + return False + elif nBottomTile == TYPE_WALL_EAST and direction == EAST: + return False + elif nBottomTile == TYPE_WALL_SOUTHEAST and direction in (SOUTH, EAST): + return False + elif nBottomTile == TYPE_BEARTRAP and not creature.state & CS_RELEASED: + return False + + if creature.type == TYPE_CHIP: + floor = self._floor_at(ptTo) + if not self._tileset[floor].chip_walk & direction: + return False + if (floor == TYPE_SOCKET and self._chips_needed > 0): + return False + if (is_door(floor) and not self._possesion(floor)): + return False + if is_creature(self.current_level.get_cell(ptTo).top.id): + tile_id = creature_id(self.current_level.get_cell(ptTo).top.id) + if tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING, TYPE_BLOCK): + return False + if floor in (TYPE_HIDDENWALL_TEMP, TYPE_BLUEWALL_REAL): + if not flags & CMM_NOEXPOSEWALLS: + self._set_floor_at(ptTo, TYPE_WALL) + return False + if floor == TYPE_BLOCK_STATIC: + if not self._push_block(ptTo, direction, flags): + return False + elif flags & CMM_NOPUSHING: + return False + if ((flags & CMM_TELEPORTPUSH) and self._floor_at(ptTo) == TYPE_BLOCK_STATIC and + self.current_level.get_cell(ptTo).bottom.id == TYPE_EMPTY): + return True + return self._can_make_move(creature, direction, flags | CMM_NOPUSHING) + elif creature.type == TYPE_BLOCK: + floor = self.current_level.get_cell(ptTo).top.id + if is_creature(floor): + tile_id = creature_id(floor) + return tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING) + if not self._tileset[floor].block_move & direction: + return False + else: + floor = self.current_level.get_cell(ptTo).top.id + if is_creature(floor): + tile_id = creature_id(floor) + if tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING): + floor = self.current_level.get_cell(ptTo).bottom.id + if is_creature(floor): + tile_id = creature_id(floor) + return tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING) + if is_creature(floor): + if ((flags & CMM_CLONECANTBLOCK) and + floor == cr_tile(creature.type, creature.direction)): + return True + return False + if not self._tileset[floor].creature_walk & direction: + return False + if floor == TYPE_FIRE and (type in (TYPE_BUG, TYPE_WALKER)): + if not flags & CMM_NOFIRECHECK: + return False + + if self.current_level.get_cell(ptTo).bottom.id == TYPE_CLONEMACHINE: + return False + + return True + + def _push_block(self, ptPos, direction, flags): + creature = self._get_block(ptPos) + if creature is None: + return False + if creature.state & (CS_SLIP | CS_SLIDE): + slip_dir = self._get_slip_dir(creature) + if direction == slip_dir or direction == back(slip_dir): + if not flags & CMM_TELEPORTPUSH: + return False + return False + if (not (flags & CMM_TELEPORTPUSH) and + self.current_level.get_cell(ptPos).bottom.id == TYPE_BLOCK_STATIC): + self.current_level.get_cell(ptPos).bottom.id = TYPE_EMPTY + if not flags & CMM_NODEFERBUTTONS: + creature.state |= CS_DEFERPUSH + result = self._advance_creature(creature, direction) + if not flags & CMM_NODEFERBUTTONS: + creature.state &= ~CS_DEFERPUSH + if not result: + creature.state &= ~(CS_SLIP | CS_SLIDE) + return result + + def _make_tile(self, tile_id, state): + tile = Tile() + tile.id = tile_id + tile.state = state + return tile + + def _update_creature(self, creature): + if creature.hidden: + return + tile = self.current_level.get_cell(creature.cur_pos).top + creature_type = creature.type + if creature_type == TYPE_BLOCK: + tile.id = TYPE_BLOCK_STATIC + return + elif creature_type == TYPE_CHIP: + if self._get_chip_status(): + if self._get_chip_status() == SF_CHIPBURNED: + tile.id = TYPE_CHIP_BURNED + return + elif self._get_chip_status() == SF_CHIPDROWNED: + tile.id = TYPE_CHIP_DROWNED + return + elif self._get_chip_status() == SF_CHIPBOMBED: + tile.id = TYPE_CHIP_BOMBED + return + elif self.current_level.get_cell(creature.cur_pos).bottom.id == TYPE_WATER: + creature_type = TYPE_CHIP_SWIMMING + + direction = creature.direction + if creature.state & CS_TURNING: + direction = right(direction) + tile.id = cr_tile(creature_type, direction) + tile.state = 0 + + def re_set_buttons(self): + for x in range(32): + for y in range(32): + self.current_level.get_cell(Point(x, y)).top.state &= ~FS_BUTTONDOWN + self.current_level.get_cell(Point(x, y)).bottom.state &= ~FS_BUTTONDOWN + + def handle_buttons(self): + for x in range(32): + for y in range(32): + top = self.current_level.get_cell(Point(x, y)).top + bottom = self.current_level.get_cell(Point(x, y)).bottom + if top.state & FS_BUTTONDOWN: + top.state &= ~FS_BUTTONDOWN + tile_id = top.id + elif bottom.state & FS_BUTTONDOWN: + bottom.state &= ~FS_BUTTONDOWN + tile_id = bottom.id + else: + continue + if tile_id == TYPE_BUTTON_BLUE: + self._toggle_tanks(None) + self._audio.play("BUTTON_PUSHED") + elif tile_id == TYPE_BUTTON_GREEN: + self.current_level.toggle_blocks() + elif tile_id == TYPE_BUTTON_RED: + self._activate_cloner(Point(x, y)) + self._audio.play("BUTTON_PUSHED") + elif tile_id == TYPE_BUTTON_BROWN: + self._spring_trap(Point(x, y)) + self._audio.play("BUTTON_PUSHED") + + def _is_ice(self, tile): + return (tile == TYPE_ICE or TYPE_ICEWALL_SOUTHEAST <= tile <= TYPE_ICEWALL_NORTHEAST) + + def _is_slide(self, tile): + return (tile in (TYPE_SLIDE_SOUTH, TYPE_SLIDE_RANDOM) or + TYPE_SLIDE_NORTH <= tile <= TYPE_SLIDE_WEST) + + def _start_floor_movement(self, creature, floor): + creature.state &= ~(CS_SLIP | CS_SLIDE) + + if self._is_ice(floor): + direction = self._ice_wall_turn(floor, creature.direction) + elif self._is_slide(floor): + direction = self._get_slide_dir(floor) + elif floor == TYPE_TELEPORT: + direction = creature.direction + elif floor == TYPE_BEARTRAP and creature.type == TYPE_BLOCK: + direction = creature.direction + else: + return + + if creature.type == TYPE_CHIP: + creature.state |= (CS_SLIDE if self._is_slide(floor) else CS_SLIP) + self._prepend_to_slip_list(creature, direction) + creature.direction = direction + self._update_creature(creature) + else: + creature.state |= CS_SLIP + self._append_to_slip_list(creature, direction) + + def _end_floor_movement(self, creature): + creature.state &= ~(CS_SLIP | CS_SLIDE) + self._remove_from_slip_list(creature) + + def _update_slip_list(self): + for slip in reversed(self._sliplist): + if not slip.creature.state & (CS_SLIP | CS_SLIDE): + self._end_floor_movement(slip.creature) + + def _floor_movements(self): + #pylint: disable=too-many-branches + slip_count = len(self._sliplist) + for n in range(slip_count): + saved_count = len(self._sliplist) + slip = self._sliplist[n] + creature = slip.creature + if not creature.state & (CS_SLIP | CS_SLIDE): + continue + slip_direction = slip.dir + if slip_direction == NONE: + continue + if creature.type == TYPE_CHIP: + self._last_slip_dir = slip_direction + if self._advance_creature(creature, slip_direction): + if creature.type == TYPE_CHIP: + creature.state &= ~CS_HASMOVED + else: + floor = self.current_level.get_cell(creature.cur_pos).bottom.id + if self._is_slide(floor): + if creature.type == TYPE_CHIP: + creature.state &= ~CS_HASMOVED + elif self._is_ice(floor): + # Go back + slip_direction = self._ice_wall_turn(floor, back(slip_direction)) + if creature.type == TYPE_CHIP: + self._last_slip_dir = slip_direction + if self._advance_creature(creature, slip_direction): + if creature.type == TYPE_CHIP: + creature.state &= ~CS_HASMOVED + elif creature.type == TYPE_CHIP: + if floor in (TYPE_TELEPORT, TYPE_BLOCK_STATIC): + self._last_slip_dir = slip_direction = back(slip_direction) + if self._advance_creature(creature, slip_direction): + creature.state &= ~CS_HASMOVED + if creature.state & (CS_SLIP | CS_SLIDE): + self._end_floor_movement(creature) + self._start_floor_movement( + creature, + self.current_level.get_cell(creature.cur_pos).bottom.id + ) + if self._check_for_ending(): + return + # If creature is not slipping or sliding and the creature is not + # chip and the slip list is one less than the saved count + if (not (creature.state & (CS_SLIP | CS_SLIDE)) and + creature.type != TYPE_CHIP and len(self._sliplist) == saved_count + 1): + n += 1 + + def get_death_message(self): + # To be shown after dying + for status, message in death_messages.items(): + if self._get_chip_status() == status: + return message + return None + + def get_decade_message(self): + # To be shown after beating a level + if self.current_level_number in decade_messages: + return decade_messages[self.current_level_number] + return None + + def _advance_creature(self, creature, direction): + if direction == NONE: + return True + if creature.type == TYPE_CHIP: + self._reset_chip_wait() + if not self._start_movement(creature, direction): + if creature.type == TYPE_CHIP: + self._audio.play("CANT_MOVE") + self.re_set_buttons() + return False + self._end_movement(creature) + if creature.type == TYPE_CHIP: + self.handle_buttons() + + return True + + def _start_movement(self, creature, direction): + floor = self.current_level.get_cell(creature.cur_pos).bottom.id + if not self._can_make_move(creature, direction, 0): + if (creature.type == TYPE_CHIP or + (floor != TYPE_BEARTRAP and floor != TYPE_CLONEMACHINE + and not creature.state & CS_SLIP)): + creature.direction = direction + self._update_creature(creature) + return False + + creature.state &= ~CS_RELEASED + creature.direction = direction + return True + + def _end_movement(self, creature): + #pylint: disable=too-many-branches, too-many-statements + dead = False + old_pos = creature.cur_pos + new_pos = creature.front() + cell = self.current_level.get_cell(new_pos) + tile = cell.top + floor = tile.id + + if creature.type == TYPE_CHIP: + if floor in (TYPE_EMPTY, TYPE_DIRT, TYPE_BLUEWALL_FAKE): + self.current_level.pop_tile(new_pos) + elif floor == TYPE_WATER: + if not self._possesion(TYPE_BOOTS_WATER): + self._set_chip_status(SF_CHIPDROWNED) + elif floor == TYPE_FIRE: + if not self._possesion(TYPE_BOOTS_FIRE): + self._set_chip_status(SF_CHIPBURNED) + elif floor == TYPE_POPUPWALL: + tile.id = TYPE_WALL + elif floor in (TYPE_DOOR_RED, TYPE_DOOR_BLUE, TYPE_DOOR_YELLOW, TYPE_DOOR_GREEN): + self._discard(floor) + self.current_level.pop_tile(new_pos) + self._audio.play("DOOR_OPENED") + elif floor in (TYPE_KEY_RED, TYPE_KEY_BLUE, TYPE_KEY_YELLOW, TYPE_KEY_GREEN, + TYPE_BOOTS_ICE, TYPE_BOOTS_SLIDE, TYPE_BOOTS_FIRE, TYPE_BOOTS_WATER): + if is_creature(cell.bottom.id): + self._set_chip_status(SF_CHIPHIT) + self._collect(floor) + self.current_level.pop_tile(new_pos) + self._audio.play("ITEM_COLLECTED") + elif floor == TYPE_THIEF: + for item in range(4): + self.boots[item] = False + self._audio.play("BOOTS_STOLEN") + elif floor == TYPE_ICCHIP: + self._chips_needed -= 1 + self.current_level.pop_tile(new_pos) + self._audio.play("IC_COLLECTED") + elif floor == TYPE_SOCKET: + if self._chips_needed == 0: + self.current_level.pop_tile(new_pos) + elif floor == TYPE_BOMB: + self._set_chip_status(SF_CHIPBOMBED) + self._audio.play("BOMB_EXPLOSION") + else: + if is_creature(floor): + self._set_chip_status(SF_CHIPHIT) + elif creature.type == TYPE_BLOCK: + if floor == TYPE_EMPTY: + self.current_level.pop_tile(new_pos) + elif floor == TYPE_WATER: + tile.id = TYPE_DIRT + dead = True + self._audio.play("WATER_SPLASH") + elif floor == TYPE_BOMB: + tile.id = TYPE_EMPTY + dead = True + self._audio.play("BOMB_EXPLOSION") + elif floor == TYPE_TELEPORT: + if not tile.state & FS_BROKEN: + new_pos = self._teleport_creature(creature, new_pos) + else: + if is_creature(floor): + tile = cell.bottom + floor = tile.id + if floor == TYPE_WATER: + if creature.type != TYPE_GLIDER: + dead = True + elif floor == TYPE_FIRE: + if creature.type != TYPE_FIREBALL: + dead = True + elif floor == TYPE_BOMB: + tile.id = TYPE_EMPTY + dead = True + self._audio.play("BOMB_EXPLOSION") + elif floor == TYPE_TELEPORT: + if not tile.state & FS_BROKEN: + new_pos = self._teleport_creature(creature, new_pos) + + if (self.current_level.get_cell(old_pos).bottom.id != TYPE_CLONEMACHINE or + creature.type == TYPE_CHIP): + self.current_level.pop_tile(old_pos) + + if dead: + self._remove_creature(creature) + if self.current_level.get_cell(old_pos).bottom.id == TYPE_CLONEMACHINE: + self.current_level.get_cell(old_pos).bottom.state &= ~FS_CLONING + return + + if creature.type == TYPE_CHIP and floor == TYPE_TELEPORT and not tile.state & FS_BROKEN: + pos = new_pos + new_pos = self._teleport_creature(creature, new_pos) + if pos != new_pos: + self._audio.play("TELEPORT") + if self._floor_at(new_pos) == TYPE_BLOCK_STATIC: + if self._last_slip_dir == NONE: + creature.direction = NORTH + self.current_level.get_cell(new_pos).top.id = cr_tile(TYPE_CHIP, NORTH) + floor = TYPE_EMPTY + else: + creature.direction = self._last_slip_dir + + + creature.cur_pos = new_pos + self._add_creature_to_map(creature) + creature.cur_pos = old_pos + + tile = cell.bottom + if floor == TYPE_BUTTON_BLUE: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self._toggle_tanks(creature) + self._audio.play("BUTTON_PUSHED") + elif floor == TYPE_BUTTON_GREEN: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self.current_level.toggle_blocks() + elif floor == TYPE_BUTTON_RED: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self._activate_cloner(new_pos) + self._audio.play("BUTTON_PUSHED") + elif floor == TYPE_BUTTON_BROWN: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self._spring_trap(new_pos) + self._audio.play("BUTTON_PUSHED") + + creature.cur_pos = new_pos + + if self.current_level.get_cell(old_pos).bottom.id == TYPE_CLONEMACHINE: + self.current_level.get_cell(old_pos).bottom.state &= ~FS_CLONING + + if floor == TYPE_BEARTRAP: + if self._is_trap_openr(new_pos, old_pos): + tile.state |= CS_RELEASED + elif self.current_level.get_cell(new_pos).bottom.id == TYPE_BEARTRAP: + for trap in self.current_level.traps: + if trap.device == new_pos: + creature.state |= CS_RELEASED + break + + if creature.type == TYPE_CHIP: + if self._get_chip_status() != SF_CHIPOKAY: + return + if cell.bottom.id == TYPE_EXIT: + self.status |= SF_COMPLETED + return + else: + if is_creature(cell.bottom.id): + if (creature_id(cell.bottom.id) == TYPE_CHIP or + creature_id(cell.bottom.id) == TYPE_CHIP_SWIMMING): + self._set_chip_status(SF_CHIPHIT) + return + + was_slipping = creature.state & (CS_SLIP | CS_SLIDE) + + if floor == TYPE_TELEPORT: + self._start_floor_movement(creature, floor) + elif (self._is_ice(floor) and + (creature.type != TYPE_CHIP or not self._possesion(TYPE_BOOTS_ICE))): + self._start_floor_movement(creature, floor) + elif (self._is_slide(floor) and + (creature.type != TYPE_CHIP or not self._possesion(TYPE_BOOTS_SLIDE))): + self._start_floor_movement(creature, floor) + elif floor == TYPE_BEARTRAP and creature.type == TYPE_BLOCK and was_slipping: + self._start_floor_movement(creature, floor) + else: + creature.state &= ~(CS_SLIP | CS_SLIDE) + + if (not was_slipping and (creature.state & (CS_SLIP | CS_SLIDE)) and + creature.type != TYPE_CHIP): + self._controller_dir = self._get_slip_dir(creature) + + def _add_creature_to_map(self, creature): + if creature.hidden: + return + self.current_level.push_tile(creature.cur_pos, self._make_tile(TYPE_EMPTY, 0)) + self._update_creature(creature) + + def _cloner_from_button(self, pos): + for cloner in self.current_level.cloners: + if cloner.button == pos: + return cloner.device + return Point(-1, -1) + + def _is_trap_openr(self, pos, skip_pos): + for trap in self.current_level.traps: + if (trap.device == pos and trap.button != skip_pos and + self._is_trap_button_down(trap.button)): + return True + return False + + def _trap_from_button(self, pos): + for trap in self.current_level.traps: + if trap.button == pos: + return trap.device + return Point(-1, -1) + + def _activate_cloner(self, button_pos): + cloner_position = self._cloner_from_button(button_pos) + if not 0 <= cloner_position.x < 32 or not 0 <= cloner_position.y < 32: + return + tile_to_clone = self.current_level.get_cell(cloner_position).top.id + if not is_creature(tile_to_clone) or creature_id(tile_to_clone) == TYPE_CHIP: + return + if creature_id(tile_to_clone) == TYPE_BLOCK: + creature = self._get_block(cloner_position) + if creature.direction != NONE: + self._advance_creature(creature, creature.direction) + else: + if self.current_level.get_cell(cloner_position).bottom.state & FS_CLONING: + return + dummy_creature = Creature( + position=cloner_position, + direction=creature_dir_id(tile_to_clone), + type=creature_id(tile_to_clone) + ) + if not self._can_make_move( + dummy_creature, dummy_creature.direction, CMM_CLONECANTBLOCK): + return + creature = self._awaken_creature(cloner_position) + if not creature: + return + creature.state |= CS_CLONING + if self.current_level.get_cell(cloner_position).bottom.id == TYPE_CLONEMACHINE: + self.current_level.get_cell(cloner_position).bottom.state |= FS_CLONING + + def _awaken_creature(self, pos): + tile = self.current_level.get_cell(pos).top.id + if not is_creature(tile) or creature_id(tile) == TYPE_CHIP: + return None + add_function = self._add_block if creature_id(tile) == TYPE_BLOCK else self._add_creature + return add_function(pos, creature_dir_id(tile), creature_id(tile)) + + def _spring_trap(self, button_position): + trap_position = self._trap_from_button(button_position) + if not 0 <= trap_position.x < 32 or not 0 <= trap_position.y < 32: + return + tile = self.current_level.get_cell(trap_position).top.id + if (tile == TYPE_BLOCK_STATIC or + self.current_level.get_cell(trap_position).bottom.state & FS_HASMUTANT): + creature = self._get_block(trap_position) + if creature: + creature.state |= CS_RELEASED + elif is_creature(tile): + creature = self._get_creature(trap_position, True) + if creature: + creature.state |= CS_RELEASED + + def _teleport_creature(self, creature, start_position): + orig_pos = creature.cur_pos + dest = Point(start_position.x, start_position.y) + while True: + dest.x -= 1 + if dest.x < 0: + dest.y -= 1 + dest.x = 31 + if dest.y < 0: + dest.y = 31 + if dest == start_position: + break + tile = self.current_level.get_cell(dest).top + if tile.id != TYPE_TELEPORT or (tile.state & FS_BROKEN): + continue + creature.cur_pos = dest + can_move = self._can_make_move( + creature, + creature.direction, + CMM_NOLEAVECHECK | CMM_NOEXPOSEWALLS | CMM_NODEFERBUTTONS | + CMM_NOFIRECHECK | CMM_TELEPORTPUSH) + creature.cur_pos = orig_pos + if can_move: + break + return dest + + # We may remove this as I believe it has to do with path finding based on mouse clicks + def _get_chip_walk_cmd(self): + choices = [0, 0] + pt_tile = self._chip.destination + x = pt_tile.x - self._chip.cur_pos.x + y = pt_tile.y - self._chip.cur_pos.y + n = NORTH if y < 0 else SOUTH if y > 0 else NONE + if y < 0: + y = -y + m = WEST if x < 0 else EAST if x > 0 else NONE + if x < 0: + x = -x + if x > y: + choices[0] = m + choices[1] = n + else: + choices[0] = n + choices[1] = m + index = 0 + while index < 2: + if choices[index] != NONE and self._can_make_move(self._chip, choices[index], 0): + return dir_idx(choices[index]) + index += 1 + self._chip.walking = False + return NONE + + def reset(self): + self.set_game_mode(GM_NORMAL) + self._moving = False + self._current_time = 0 + self.keys = [0] * 4 + self.boots = [False] * 4 + self.status = SF_CHIPOKAY + self._chip.walking = False + self._chip.state = 0 + self._creature_pool = [] + self._block_pool = [] + self._set_button(NONE) + self.dead_creatures = 0 + self.dead_blocks = 0 + + def _extract_creatures(self): + for creature_position in self.current_level.creatures: + tile = self.current_level.get_cell(creature_position).top.id + if is_creature(tile): + self._add_creature(creature_position, creature_dir_id(tile), creature_id(tile)) + for x in range(32): + for y in range(32): + tile2 = self.current_level.get_cell(Point(x, y)).top.id + if creature_id(tile2) == TYPE_CHIP: + self._chip.cur_pos = Point(x, y) + self._chip.type = TYPE_CHIP + self._chip.direction = creature_dir_id(tile2) + + def _append_to_slip_list(self, creature, direction): + # Append the given creature to the end of the slip list + for slip in self._sliplist: + if slip.creature == creature: + slip.dir = direction + return creature + + slip = Slip() + slip.creature = creature + slip.dir = direction + self._sliplist.append(slip) + return creature + + def _prepend_to_slip_list(self, creature, direction): + # Prepend the given creature to the start of the slip list + if len(self._sliplist) > 0 and self._sliplist[0].creature == creature: + self._sliplist[0].dir = direction + return creature + + slip = Slip() + slip.creature = creature + slip.dir = direction + self._sliplist.insert(0, slip) + return creature + + def _remove_from_slip_list(self, creature): + if len(self._sliplist) == 0: + return + + for slip in self._sliplist: + if slip.creature == creature: + self._sliplist.remove(slip) + break + + def _get_slip_dir(self, creature): + for slip in self._sliplist: + if slip.creature == creature: + return slip.dir + return NONE + + def _add_creature(self, tile_pos, direction, creature_type): + new_creature = Creature( + position=tile_pos, + direction=direction, + creature_type=creature_type + ) + self._creature_pool.append(new_creature) + return new_creature + + def _remove_creature(self, creature): + if creature.type == TYPE_BLOCK: + self.dead_blocks += 1 + else: + self.dead_creatures += 1 + creature.state &= ~(CS_SLIP | CS_SLIDE) + if creature.type == TYPE_CHIP: + if self.status == SF_CHIPOKAY: + self.status = SF_CHIPNOTOKAY + creature.hidden = True + + def _remove_dead_creatures(self): + for creature in self._creature_pool: + if creature.hidden and not creature.on_slip_list: + self._remove_creature(creature) + self.dead_creatures -= 1 + + def _get_creature(self, pos, include_chip): + for creature in self._creature_pool: + if creature.cur_pos == pos: + return creature + if include_chip and self._chip.cur_pos == pos: + return self._chip + return None + + def _add_block(self, tile_pos, direction, creature_type): + new_block = Creature() + new_block.cur_pos = tile_pos + new_block.direction = direction + new_block.type = creature_type + self._block_pool.append(new_block) + return new_block + + def _remove_dead_blocks(self): + for block in self._block_pool: + if block.hidden and not block.on_slip_list: + self._block_pool.remove(block) + self.dead_blocks -= 1 + + def _get_block(self, pos): + for block in self._block_pool: + if block.cur_pos == pos and not block.hidden: + return block + tile = self.current_level.get_cell(pos).top.id + if creature_id(tile) == TYPE_BLOCK: + creature_dir = creature_dir_id(tile) + elif tile == TYPE_BLOCK_STATIC: + creature_dir = NONE + else: + return None + + new_block = self._add_block(pos, creature_dir, TYPE_BLOCK) + if self.current_level.get_cell(pos).bottom.id == TYPE_BEARTRAP: + for trap in self.current_level.traps: + if trap.device == new_block.cur_pos: + new_block.state |= CS_RELEASED + break + return new_block + + def _random_p(self, array, level): + for index in range(5 - level, level + 1): + number = random.randint(0, index - 1) + array[number], array[index - 1] = array[index - 1], array[number] + + def _toggle_tanks(self, mid_move): + for creature in self._creature_pool: + if creature.hidden or creature.type != TYPE_TANK: + continue + creature.direction = back(creature.direction) + if not creature.state & CS_TURNING: + creature.state |= CS_TURNING | CS_HASMOVED + if creature != mid_move: + if creature_id(self.current_level.get_cell(creature.cur_pos).top.id) == TYPE_TANK: + self._update_creature(creature) + else: + if creature.state & CS_TURNING: + creature.state &= ~CS_TURNING + self._update_creature(creature) + creature.state |= CS_TURNING + creature.direction = back(creature.direction) + + def set_game_mode(self, mode, push=True): + game_mode = self.get_game_mode() + if game_mode != mode: + if not push and len(self._game_mode) > 0: + self._game_mode.pop() + self._game_mode.append(mode) + # Housekeeping + while len(self._game_mode) > 4: + self._game_mode.pop(0) + + def revert_game_mode(self): + self._game_mode.pop() + + def get_game_mode(self): + last = len(self._game_mode) - 1 + if last < 0: + return None + return self._game_mode[last] + + def _choose_chip_move(self, creature, _discard): + creature.to_direction = NONE + if creature.hidden: + return + if not self.get_tick() & 3: + creature.state &= ~CS_HASMOVED + if creature.state & CS_HASMOVED: + return + direction = self._current_input + self._set_button(NONE) + + if not NORTH <= direction <= EAST: + direction = NONE + if _discard or ((creature.state & CS_SLIDE) and direction == creature.direction): + return + creature.to_direction = direction + + def _choose_move(self, creature): + if creature.type == TYPE_CHIP: + self._choose_chip_move(creature, creature.state & CS_SLIP) + else: + if creature.state & CS_SLIP: + creature.to_dir = NONE + else: + self._choose_creature_move(creature) + + def _choose_creature_move(self, creature): + #pylint: disable=too-many-branches, too-many-statements, too-many-return-statements + choices = [NONE, NONE, NONE, NONE] + creature.to_direction = NONE + creature_type = creature.type + if creature.hidden: + return + if creature_type == TYPE_BLOCK: + return + if self.get_tick() & 2: + return + if creature_type in (TYPE_TEETH, TYPE_BLOB): + if self.get_tick() & 4: + return + if creature.state & CS_TURNING: + creature.state &= ~(CS_TURNING | CS_HASMOVED) + self._update_creature(creature) + if creature.state & CS_HASMOVED: + self._controller_dir = NONE + return + if creature.state & (CS_SLIP | CS_SLIDE): + return + floor = self._floor_at(creature.cur_pos) + next_direction = current_direction = creature.direction + if floor in (TYPE_CLONEMACHINE, TYPE_BEARTRAP): + if creature_type in (TYPE_TANK, TYPE_BALL, TYPE_GLIDER, TYPE_FIREBALL, TYPE_WALKER): + choices[0] = current_direction + elif creature_type == TYPE_BLOB: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = back(current_direction) + choices[3] = right(current_direction) + self._random_p(choices, 4) + elif creature_type in (TYPE_BUG, TYPE_PARAMECIUM, TYPE_TEETH): + choices[0] = self._controller_dir + creature.to_direction = self._controller_dir + return + else: + raise ValueError("Invalid creature type") + else: + if creature_type == TYPE_TANK: + choices[0] = current_direction + elif creature_type == TYPE_BALL: + choices[0] = current_direction + choices[1] = back(current_direction) + elif creature_type == TYPE_GLIDER: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = right(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_FIREBALL: + choices[0] = current_direction + choices[1] = right(current_direction) + choices[2] = left(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_WALKER: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = back(current_direction) + choices[3] = right(current_direction) + self._random_p(choices[1:], 3) + elif creature_type == TYPE_BLOB: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = back(current_direction) + choices[3] = right(current_direction) + self._random_p(choices, 4) + elif creature_type == TYPE_BUG: + choices[0] = left(current_direction) + choices[1] = current_direction + choices[2] = right(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_PARAMECIUM: + choices[0] = right(current_direction) + choices[1] = current_direction + choices[2] = left(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_TEETH: + x = self._chip.cur_pos.x - creature.cur_pos.x + y = self._chip.cur_pos.y - creature.cur_pos.y + n = NORTH if y < 0 else SOUTH if y > 0 else NONE + if y < 0: + y = -y + m = WEST if x < 0 else EAST if x > 0 else NONE + if x < 0: + x = -x + if x > y: + choices[0] = m + choices[1] = n + else: + choices[0] = n + choices[1] = m + next_direction = choices[0] + else: + raise ValueError("Invalid creature type") + for n in range(4): + creature.to_direction = choices[n] + self._controller_dir = creature.to_direction + if self._can_make_move(creature, choices[n], 0): + return + if creature_type == TYPE_TANK: + if ((creature.state & CS_RELEASED) or floor not in (TYPE_BEARTRAP, TYPE_CLONEMACHINE)): + creature.state |= CS_HASMOVED + creature.to_direction = next_direction + + def _prepare(self): + if not self.get_tick() & 3: + for creature in self._creature_pool: + if creature.state & CS_TURNING: + creature.state &= ~(CS_TURNING | CS_HASMOVED) + self._update_creature(creature) + self.status = (self.status & ~SF_CHIPWAITMASK) | ((self.status & SF_CHIPWAITMASK) + 1) + if self.status & SF_CHIPWAITMASK > 3: + self._reset_chip_wait() + self._chip.direction = SOUTH + self._update_creature(self._chip) + + def advance_game(self, input_command): + #pylint: disable=too-many-branches + dir_cmd = NONE + if input_command == NONE: + # Check if chip is autopathing + if self._chip.walking: + dir_cmd = self._get_chip_walk_cmd() + if dir_cmd != NONE: + input_command = dir_cmd + else: + self._chip.walking = False + + # Don't start level until we have movement + if self.get_tick() or (UP <= input_command <= RIGHT): + self._current_time += 1 + + if UP <= input_command <= RIGHT: + self._set_button(idx_dir(input_command)) + else: + self._set_button(NONE) + + self._prepare() + + if self.get_tick() and not self.get_tick() & 1: + self._controller_dir = NONE + for creature in self._creature_pool: + if creature.hidden or (creature.state & CS_CLONING) or creature.type == TYPE_CHIP: + continue + self._choose_move(creature) + if creature.to_direction != NONE: + self._advance_creature(creature, creature.to_direction) + if self._check_for_ending(): + self._finalize() + return + if self.get_tick() and not self.get_tick() & 1: + self._floor_movements() + if self._check_for_ending(): + self._finalize() + return + + self._update_slip_list() + + if self._time_limit: + if self.get_tick() >= self._time_limit: + if self.status == SF_CHIPOKAY: + self.status = SF_CHIPNOTOKAY + self._set_chip_status(SF_CHIPTIMEUP) + self.set_game_mode(GM_CHIPDEAD) + self._audio.play("TIME_UP") + return + elif (self._time_limit - self.get_tick() <= 15 * TICKS_PER_SECOND and + self.get_tick() % TICKS_PER_SECOND == 0): + self._audio.play("TIME_LOW_TICK") + self._choose_move(self._chip) + if self._chip.to_direction != NONE: + if self._advance_creature(self._chip, self._chip.to_direction): + if self._check_for_ending(): + self._finalize() + return + self._chip.state |= CS_HASMOVED + self._update_slip_list() + self._create_clones() + self._finalize() + + def _create_clones(self): + for creature in self._creature_pool: + if creature.state & CS_CLONING: + creature.state &= ~CS_CLONING + + def _finalize(self): + if self.dead_creatures: + self._remove_dead_creatures() + if self.dead_blocks: + self._remove_dead_blocks() + if self.current_level.get_cell(self._chip.cur_pos).bottom.id == TYPE_HINTBUTTON: + self.status |= SF_SHOWHINT + else: + self.status &= ~SF_SHOWHINT + + def _check_for_ending(self): + if self.status & SF_COMPLETED: + self._audio.play("CHIP_WINS") + self.set_game_mode(GM_LEVELWON) + return True + if self.status & SF_CHIPNOTOKAY: + self._audio.play("CHIP_LOSES") + self.set_game_mode(GM_CHIPDEAD) + return True + return False + + def _create_tileset(self): + #pylint: disable=too-many-statements + # Chip, Block, Creature + self._tileset[TYPE_EMPTY].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_WALL].set_walk(0, 0, 0) + self._tileset[TYPE_ICCHIP].set_walk(NWSE, 0, 0) + self._tileset[TYPE_WATER].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_FIRE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_WALL_NORTH].set_walk( + WEST | NORTH | EAST, + WEST | NORTH | EAST, + WEST | NORTH | EAST + ) + self._tileset[TYPE_WALL_WEST].set_walk( + NORTH | SOUTH | WEST, + NORTH | SOUTH | WEST, + NORTH | SOUTH | WEST + ) + self._tileset[TYPE_WALL_SOUTH].set_walk( + SOUTH | WEST | EAST, + SOUTH | WEST | EAST, + SOUTH | WEST | EAST + ) + self._tileset[TYPE_WALL_EAST].set_walk( + NORTH | EAST | SOUTH, + NORTH | EAST | SOUTH, + NORTH | EAST | SOUTH + ) + self._tileset[TYPE_WALL_SOUTHEAST].set_walk(SOUTH | EAST, SOUTH | EAST, SOUTH | EAST) + self._tileset[TYPE_BLOCK_STATIC].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DIRT].set_walk(NWSE, 0, 0) + self._tileset[TYPE_ICE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_SOUTH].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_NORTH].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_EAST].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_WEST].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_EXIT].set_walk(NWSE, NWSE, 0) + self._tileset[TYPE_DOOR_BLUE].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DOOR_RED].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DOOR_GREEN].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DOOR_YELLOW].set_walk(NWSE, 0, 0) + self._tileset[TYPE_ICEWALL_NORTHWEST].set_walk(SOUTH | EAST, SOUTH | EAST, SOUTH | EAST) + self._tileset[TYPE_ICEWALL_NORTHEAST].set_walk(SOUTH | WEST, SOUTH | WEST, SOUTH | WEST) + self._tileset[TYPE_ICEWALL_SOUTHWEST].set_walk(NORTH | EAST, NORTH | EAST, NORTH | EAST) + self._tileset[TYPE_ICEWALL_SOUTHEAST].set_walk(NORTH | WEST, NORTH | WEST, NORTH | WEST) + self._tileset[TYPE_BLUEWALL_FAKE].set_walk(NWSE, 0, 0) + self._tileset[TYPE_BLUEWALL_REAL].set_walk(NWSE, 0, 0) + self._tileset[TYPE_THIEF].set_walk(NWSE, 0, 0) + self._tileset[TYPE_SOCKET].set_walk(NWSE, 0, 0) + self._tileset[TYPE_BUTTON_GREEN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BUTTON_RED].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SWITCHWALL_CLOSED].set_walk(0, 0, 0) + self._tileset[TYPE_SWITCHWALL_OPEN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BUTTON_BROWN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BUTTON_BLUE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_TELEPORT].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOMB].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BEARTRAP].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_HIDDENWALL_PERM].set_walk(0, 0, 0) + self._tileset[TYPE_HIDDENWALL_TEMP].set_walk(NWSE, 0, 0) + self._tileset[TYPE_GRAVEL].set_walk(NWSE, NWSE, 0) + self._tileset[TYPE_POPUPWALL].set_walk(NWSE, 0, 0) + self._tileset[TYPE_HINTBUTTON].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_CLONEMACHINE].set_walk(0, 0, 0) + self._tileset[TYPE_SLIDE_RANDOM].set_walk(NWSE, NWSE, 0) + self._tileset[TYPE_KEY_BLUE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_KEY_RED].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_KEY_GREEN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_KEY_YELLOW].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_WATER].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_FIRE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_ICE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_SLIDE].set_walk(NWSE, NWSE, NWSE) + self._tileset[0x0E].set_walk(0, 0, 0) + self._tileset[0x0F].set_walk(0, 0, 0) + self._tileset[0x10].set_walk(0, 0, 0) + self._tileset[0x11].set_walk(0, 0, 0) + for index in range(0x40, 0x64): + self._tileset[index].set_walk(NWSE, 0, 0) + for index in range(0x64, 0x70): + self._tileset[index].set_walk(0, NWSE, 0) + + def _set_floor_at(self, tile_coords, tile): + test_tile = self.current_level.get_cell(tile_coords).top.id + if not is_key(test_tile) and not is_boots(test_tile) and not is_creature(test_tile): + self.current_level.get_cell(tile_coords).top.id = tile + return + else: + self.current_level.get_cell(tile_coords).bottom.id = tile + + def _floor_at(self, tile_coords): + tile = self.current_level.get_cell(tile_coords).top.id + if not is_key(tile) and not is_boots(tile) and not is_creature(tile): + return tile + tile = self.current_level.get_cell(tile_coords).bottom.id + if not is_key(tile) and not is_boots(tile) and not is_creature(tile): + return tile + return TYPE_EMPTY + + def _is_trap_button_down(self, coords): + return (0 <= coords.x < 32 and 0 <= coords.y < 32 and + self.current_level.get_cell(coords).top.id == TYPE_BUTTON_BROWN) + + def get_tick(self): + return self._current_time + + def _set_chip_status(self, status): + self.status = (self.status & ~SF_CHIPSTATUSMASK) | status + + def _get_chip_status(self): + return self.status & SF_CHIPSTATUSMASK + + def _reset_chip_wait(self): + self.status &= ~SF_CHIPWAITMASK + + def _set_button(self, button): + self._current_input = button + + def get_chips_needed(self): + if self._chips_needed < 0: + return 0 + return self._chips_needed diff --git a/Metro/Metro_RP2350_Chips_Challenge/keyboard.py b/Metro/Metro_RP2350_Chips_Challenge/keyboard.py new file mode 100755 index 000000000..42dd6dd9b --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/keyboard.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +import sys +import supervisor + +class KeyboardBuffer: + def __init__(self, valid_sequences): + self.key_buffer = "" + self._valid_sequences = valid_sequences + + def update(self): + while supervisor.runtime.serial_bytes_available: + self.key_buffer += sys.stdin.read(1) + + def print(self): + print("buffer", end=": ") + for key in self.key_buffer: + print(hex(ord(key)), end=" ") + + def set_valid_sequences(self, valid_sequences): + self._valid_sequences = valid_sequences + + def clear(self): + self.key_buffer = "" + + def get_key(self): + """ + Check for keyboard input and return the first valid key sequence. + """ + # Check if serial data is available + self.update() + if self.key_buffer: + for sequence in self._valid_sequences: + if self.key_buffer.startswith(sequence): + key = sequence + self.key_buffer = self.key_buffer[len(sequence):] + return key + # Remove first character + self.key_buffer = self.key_buffer[1:] + + return None diff --git a/Metro/Metro_RP2350_Chips_Challenge/level.py b/Metro/Metro_RP2350_Chips_Challenge/level.py new file mode 100755 index 000000000..1317bc800 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/level.py @@ -0,0 +1,247 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +# SPDX-License-Identifier: GPL-1.0-or-later +# Based on Pocket Chip's Challenge (https://github.com/makermelissa/PocketChipsChallenge) +# +# pylint: disable=too-many-lines, wildcard-import, unused-wildcard-import + +from point import Point +from device import Device +from definitions import TYPE_EMPTY, TYPE_SWITCHWALL_OPEN, TYPE_SWITCHWALL_CLOSED + +COMPRESSED = 0 +UNCOMPRESSED = 1 + +# These are the used optional field types +FIELD_TITLE = 3 +FIELD_BEAR_TRAPS = 4 +FIELD_CLONING_MACHINES = 5 +FIELD_PASSWORD = 6 +FIELD_HINT = 7 +FIELD_MOVING_CREATURES = 10 + +class Tile: + def __init__(self): + self.id = 0 + self.state = 0 + +class Cell: + def __init__(self): + self.top = Tile() + self.bottom = Tile() + + def __repr__(self): + return f"Top: {hex(self.top.id)} Bottom: {hex(self.bottom.id)}" + +class Level: + def __init__(self, data_file): + # Initialize any variables + self._data_file = data_file + self.level_number = 0 + self.last_level = 0 + self.time_limit = 0 + self.best_time = 0 + self.chips_required = 0 + self.password = "" + self.hint = "" + self.title = "" + self.level_map = [Cell() for _ in range(1024)] + self.traps = [] + self.cloners = [] + self.creatures = [] + self.passwords = {} + + def _reset_data(self): + self.level_map = [Cell() for _ in range(1024)] + self.traps = [] + self.cloners = [] + self.creatures = [] + + def get_cell(self, coords): + if isinstance(coords, int): + coords = self.position_to_coords(coords) + return self.level_map[self.coords_to_position(coords)] + + def coords_to_position(self, coords): + return coords.y * 32 + coords.x + + def position_to_coords(self, position): + return Point(position % 32, position // 32) + + def _read_int(self, file, byte_count): + return int.from_bytes(file.read(byte_count), "little") + + def _update_cell_id(self, coords, tile_id, layer): + getattr(self.get_cell(coords), layer).id = tile_id + + def _get_map_representation(self, layer): + level_map = f"{layer} layer\n" + for y in range(32): + for x in range(32): + level_map += f"{hex(getattr(self.get_cell(Point(x, y)), layer).id)} " + level_map += "\n" + return level_map + + + def _process_map_data(self, map_data, layer): + """ + Store RLE mapdata in uncompressed form + """ + current_byte = 0 + current_position = 0 + while current_byte < len(map_data): + if map_data[current_byte] == 0xFF: + tile_id = map_data[current_byte + 2] + if 0x0E <= tile_id <= 0x11: + tile_id += 0xC2 + for _ in range(map_data[current_byte + 1]): + coords = self.position_to_coords(current_position) + self._update_cell_id(coords, tile_id, layer) + current_position += 1 + current_byte += 3 + else: + tile_id = map_data[current_byte] + if 0x0E <= tile_id <= 0x11: + tile_id += 0xC2 + coords = self.position_to_coords(current_position) + self._update_cell_id(coords, tile_id, layer) + current_position += 1 + current_byte += 1 + + def load(self, level_number): + #pylint: disable=too-many-branches + # Reset the data prior to loading + self._reset_data() + # Read the file and fill in the variables + with open(self._data_file, "rb") as file: + # Read the first 4 bytes in little endian format + if self._read_int(file, 4) not in (0x0002AAAC, 0x0102AAAC): + raise ValueError("Not a CHIP file") + self.last_level = self._read_int(file, 2) + if not 0 < level_number <= self.last_level: + raise ValueError("Invalid level number") + self.level_number = level_number + # Seek to the start of the level data for the specified level + while True: + level_bytes = self._read_int(file, 2) + if self._read_int(file, 2) == level_number: + break + # Go to next level + file.seek(level_bytes - 2, 1) + + # Read the level data + self.time_limit = self._read_int(file, 2) + self.chips_required = self._read_int(file, 2) + compression = self._read_int(file, 2) + if compression == COMPRESSED: + raise ValueError("Compressed levels not supported") + + # Process the top map data + layer_bytes = self._read_int(file, 2) + map_data = file.read(layer_bytes) + self._process_map_data(map_data, "top") + + # Process the bottom map data + layer_bytes = self._read_int(file, 2) + map_data = file.read(layer_bytes) + self._process_map_data(map_data, "bottom") + + remaining_bytes = self._read_int(file, 2) + while remaining_bytes > 0: + field_type = self._read_int(file, 1) + field_size = self._read_int(file, 1) + remaining_bytes -= (2 + field_size) + if field_type == FIELD_TITLE: + self.title = file.read(field_size).decode("utf-8").replace("\x00", "") + elif field_type == FIELD_HINT: + self.hint = file.read(field_size).decode("utf-8").replace("\x00", "") + elif field_type == FIELD_PASSWORD: + self.password = ( + "".join([chr(c ^ 0x99) for c in file.read(field_size)]).replace("\x99", "") + ) + elif field_type == FIELD_BEAR_TRAPS: + trap_count = field_size // 10 + for _ in range(trap_count): + button = Point(self._read_int(file, 2), self._read_int(file, 2)) + device = Point(self._read_int(file, 2), self._read_int(file, 2)) + self.traps.append(Device(button, device)) + file.seek(2, 1) + elif field_type == FIELD_CLONING_MACHINES: + cloner_count = field_size // 8 + for _ in range(cloner_count): + button = Point(self._read_int(file, 2), self._read_int(file, 2)) + device = Point(self._read_int(file, 2), self._read_int(file, 2)) + self.cloners.append(Device(button, device)) + elif field_type == FIELD_MOVING_CREATURES: + creature_count = field_size // 2 + for _ in range(creature_count): + self.creatures.append(Point( + self._read_int(file, 1), + self._read_int(file, 1) + )) + + # Load passwords if not already loaded + if len(self.passwords) == 0: + self._load_passwords(file) + + def _load_passwords(self, file): + file.seek(6) # Skip the file header + while True: + file.seek(2, 1) + level_number = self._read_int(file, 2) + file.seek(6, 1) + layer_bytes = self._read_int(file, 2) # Number of bytes in the top layer + file.seek(layer_bytes, 1) # Skip top layer + layer_bytes = self._read_int(file, 2) # Number of bytes in the top layer + file.seek(layer_bytes, 1) # Skip bottom layer + remaining_bytes = self._read_int(file, 2) + while remaining_bytes > 0: + field_type = self._read_int(file, 1) + field_size = self._read_int(file, 1) + remaining_bytes -= (2 + field_size) + if field_type == FIELD_PASSWORD: + password = file.read(field_size) + self.passwords[level_number] = ( + "".join([chr(c ^ 0x99) for c in password]).replace("\x99", "") + ) + file.seek(remaining_bytes, 1) + break + file.seek(field_size, 1) + if len(self.passwords) == self.last_level: + break + + def toggle_blocks(self): + for cell in self.level_map: + if cell.top.id == TYPE_SWITCHWALL_OPEN: + cell.top.id = TYPE_SWITCHWALL_CLOSED + elif cell.top.id == TYPE_SWITCHWALL_CLOSED: + cell.top.id = TYPE_SWITCHWALL_OPEN + + if cell.bottom.id == TYPE_SWITCHWALL_OPEN: + cell.bottom.id = TYPE_SWITCHWALL_CLOSED + elif cell.bottom.id == TYPE_SWITCHWALL_CLOSED: + cell.bottom.id = TYPE_SWITCHWALL_OPEN + + def pop_tile(self, coords): + tile = Tile() + cell = self.get_cell(coords) + tile.id = cell.top.id + tile.state = cell.top.state + cell.top.id = cell.bottom.id + cell.top.state = cell.bottom.state + cell.bottom.id = TYPE_EMPTY + cell.bottom.state = 0 + + return tile + + def push_tile(self, coords, tile): + cell = self.get_cell(coords) + cell.bottom.id = cell.top.id + cell.bottom.state = cell.top.state + cell.top.id = tile.id + cell.top.state = tile.state + + def __str__(self): + # print the map ids from the level + return self._get_map_representation("top") + "\n" + self._get_map_representation("bottom") diff --git a/Metro/Metro_RP2350_Chips_Challenge/point.py b/Metro/Metro_RP2350_Chips_Challenge/point.py new file mode 100755 index 000000000..30dcd2d6f --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/point.py @@ -0,0 +1,83 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +import math + +class Point: + def __init__(self, x, y): + self.x = x + self.y = y + + def __str__(self): + return f'({self.x}, {self.y})' + + def __repr__(self): + return f'({self.x}, {self.y})' + + def __add__(self, other): + return Point(self.x + other.x, self.y + other.y) + + def __sub__(self, other): + return Point(self.x - other.x, self.y - other.y) + + def __mul__(self, other): + return Point(self.x * other.x, self.y * other.y) + + def __truediv__(self, other): + return Point(self.x / other.x, self.y / other.y) + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __ne__(self, other): + return not self.__eq__(other) + + def __lt__(self, other): + return self.x < other.x and self.y < other.y + + def __le__(self, other): + return self.x <= other.x and self.y <= other.y + + def __gt__(self, other): + return self.x > other.x and self.y > other.y + + def __ge__(self, other): + return self.x >= other.x and self.y >= other.y + + def __neg__(self): + return Point(-self.x, -self.y) + + def __pos__(self): + return Point(+self.x, +self.y) + + def __abs__(self): + return Point(abs(self.x), abs(self.y)) + + def __invert__(self): + return Point(~self.x, ~self.y) + + def __round__(self, n=0): + return Point(round(self.x, n), round(self.y, n)) + + def __floor__(self): + return Point(math.floor(self.x), math.floor(self.y)) + + def __ceil__(self): + return Point(math.ceil(self.x), math.ceil(self.y)) + + def __trunc__(self): + return Point(math.trunc(self.x), math.trunc(self.y)) + + def __hash__(self): + return hash((self.x, self.y)) + + def __len__(self): + return 2 + + def __getitem__(self, index): + if index == 0: + return self.x + elif index == 1: + return self.y + else: + raise IndexError diff --git a/Metro/Metro_RP2350_Chips_Challenge/savestate.py b/Metro/Metro_RP2350_Chips_Challenge/savestate.py new file mode 100755 index 000000000..7235dc08e --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/savestate.py @@ -0,0 +1,154 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from math import floor +import json +import board +from microcontroller import nvm +from digitalio import DigitalInOut, Pull +import busio +import sdcardio +import storage + +SAVESTATE_FILE = "chips.json" + +class SaveState: + def __init__(self): + self._levels = {} + self._has_sdcard = self._mount_sd_card() + if self._has_sdcard: + print("SD Card detected") + else: + print("SD Card not detected. Level data will NOT be saved.") + self.load() + self._sdcard = None + + def _mount_sd_card(self): + self._card_detect = DigitalInOut(board.SD_CARD_DETECT) + self._card_detect.switch_to_input(pull=Pull.UP) + if self._card_detect.value: + return False + + # Attempt to unmount the SD card + try: + storage.umount("/sd") + except OSError: + pass + + spi = busio.SPI(board.SD_SCK, MOSI=board.SD_MOSI, MISO=board.SD_MISO) + + try: + sdcard = sdcardio.SDCard(spi, board.SD_CS, baudrate=20_000_000) + vfs = storage.VfsFat(sdcard) + storage.mount(vfs, "/sd") + except OSError: + return False + + return True + + def save(self): + if not self._has_sdcard: + return + with open("/sd/" + SAVESTATE_FILE, "w") as f: + json.dump({"levels": self._levels}, f) + + def load(self): + if not self._has_sdcard: + return + # Use try in case the file doesn't exist + try: + with open("/sd/" + SAVESTATE_FILE, "r") as f: + data = json.load(f) + self._levels = data["levels"] + except OSError: + pass + + def set_level_score(self, level, score, time_left): + level_key = f"level{level}" + new_high_score = False + lower_time = False + if level_key not in self._levels: + self._levels[level_key] = {} + if score > self._levels[level_key].get("score", 0): + new_high_score = True + self._levels[level_key]["score"] = score + if time_left > self._levels[level_key].get("time_left", 0): + lower_time = True + self._levels[level_key]["time_left"] = time_left + + self.save() + return new_high_score, lower_time + + def add_level_password(self, level, password): + nvm[0] = level + for byte, char in enumerate(password): + nvm[1 + byte] = ord(char) + level_key = f"level{level}" + if level_key not in self._levels: + self._levels[level_key] = {} + self._levels[level_key]["password"] = password.upper() + self.save() + + def find_unlocked_level(self, level_or_password): + if isinstance(level_or_password, int): + level_key = f"level{level_or_password}" + password = None + else: + level_key = None + password = level_or_password + + # Look for level by number + if level_key in self._levels: + return level_or_password + + for key, data in self._levels.items(): + if "password" in data and data["password"] == password: + return int(key[5:]) + + return None + + def calculate_score(self, level, time_left, deaths): + time_bonus = time_left * 10 + level_bonus = floor(level * 500 * 0.8**deaths) + level_score = time_bonus + level_bonus + total_score = self.total_score + return time_bonus, level_bonus, level_score, total_score + + def has_password(self, level, password): + level_key = f"level{level}" + if level_key in self._levels: + return self._levels[level_key]["password"] == password.upper() + return False + + def level_score(self, level): + level_key = f"level{level}" + if (level_key in self._levels and "score" in self._levels[level_key] and + "time_left" in self._levels[level_key]): + return self._levels[level_key]["score"], self._levels[level_key]["time_left"] + return 0, 0 + + def is_level_unlocked(self, level): + level_key = f"level{level}" + if level_key in self._levels and "password" in self._levels[level_key]: + return True + return False + + @property + def has_sdcard(self): + return self._has_sdcard + + @property + def total_score(self): + total_score = 0 + for data in self._levels.values(): + if "score" in data: + total_score += data["score"] + return total_score + + @property + def total_completed_levels(self): + completed_levels = 0 + for data in self._levels.values(): + if "score" in data: + completed_levels += 1 + return completed_levels diff --git a/Metro/Metro_RP2350_Chips_Challenge/settings.toml b/Metro/Metro_RP2350_Chips_Challenge/settings.toml new file mode 100755 index 000000000..86420f0ed --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/settings.toml @@ -0,0 +1 @@ +CIRCUITPY_PYSTACK_SIZE = 2400 \ No newline at end of file diff --git a/Metro/Metro_RP2350_Chips_Challenge/slip.py b/Metro/Metro_RP2350_Chips_Challenge/slip.py new file mode 100755 index 000000000..aba7e92d5 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/slip.py @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +class Slip: + def __init__(self): + self.creature = None + self.dir = None + + def __repr__(self): + return f"Creature: {self.creature} | Slip Direction: {self.dir}" diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/bell.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/bell.wav new file mode 100755 index 0000000000000000000000000000000000000000..d4d3d21aef5c0cf5560fa903460543a591364261 GIT binary patch literal 10400 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 SOQVbv^h98yk0U1wl>Y&)vWAWT literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/bummer.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/bummer.wav new file mode 100755 index 0000000000000000000000000000000000000000..bec81048bc975fa2ed22699e39d5e9b62070e639 GIT binary patch literal 2758 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 At^fc4 literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/click3.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/click3.wav new file mode 100755 index 0000000000000000000000000000000000000000..7332a468418813cc1a47ff809f5d37bdc6142228 GIT binary patch literal 466 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 Z-9y8j7h$FVCI!GqNdc0@K!Yf7{~wpo(;NT* literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/door.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/door.wav new file mode 100755 index 0000000000000000000000000000000000000000..1bc817f7ab21946a4e6b2db0f99df36d23e1b714 GIT binary patch literal 2022 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 E3wKk9zW@LL literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/oof3.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/oof3.wav new file mode 100755 index 0000000000000000000000000000000000000000..982d86e3677fbd87eb7df95a8ce830ca5761ac47 GIT binary patch literal 1562 zcmW+$+j85s7F8eG>Emg?pzr4^`fxgvPA2VfVqNT5wk69{D3TH>lA?G4NC3Qnq)18B z&ALWTV#i6^ep$bvOlJ=UGkY&=EbLheC(nNQ<;U+zrOMCc|K0NPPyZ>EO5YUm!+%Tv zu5U`;mu{}*>%YG(l}3T<($P3yt*B$*lo~uIDiX^{63?(k=v%58<%vhfvwS>X#g0W{ zEWHtAnZNBQeU=eGfV81I&f_p$tX8YV2%DH9vBiio*KGGy{!Pz`us(FBc|<37+s$%9 z2?<@Lb<+`r#&t*R@m(|Upoz1^I2tYX$GgOHX@dJqo8{QcMu+QkL?hqui(FSP2nJm29pKXe=~SuXSW`tWWSA?#D@_M+KlnTsYT2tCb90_;Vz)oi}r zA9pEsNa(O8oKdpy+0fuzx?sE_HE)@&F3#__49JM!E!y_ zi$XV9tarP&Pk;XPFvd8H)Y`L?i_5eBS6XaG0%7d=S#iVR{?ngd-lqh8rSR(`Z& zDkF3i7$i|Vz1!~h1>n)rnN@$=`0rH>puxO(whxmG=`HVf(KZcJ%5U#+)?hmTK>$Ej!A zpj&430-(OX0)!J2?@2SuaX_8In>&@Z* z{p0)N)P>L#E>2$7&d+Ogw%3ykH;SV;o2~A?LO$Ft0)%X-c~+~{s%KwC(;bq)52Dd{ zHeamwZ;$)!BErznxO%x#ziu>`jvx)77kF-v&hqK}ZoS=Xc5~_gOJnQjmj$HR<^*X7 zF~KBEr_=EypRYFC-7+Dz0~O}#y1?A9JjeBhMFNs2P2)75FBYrqVKs7bK(uzV#V|KF zZT1brDFEn0JIazE8Rz-5V7|&z8ihnJT5z4#O%bh*s3?6M73sp4>2#hK#@pOYs2_z` z7A28u)*DQ_*?1$Ws*e1CdPy?M#87PgU4a*Pu_wurszG2{R^fLXj6BDSXH!74Q5<`*?}mn9>wQU7w4&5TY zF@z-4hR8FZ=^=CIyO8LvXZl6a0JvZXP0b~e;`u-|ZDL@gc>p>d!0L$Vs!M$+!4QFg NU39h$G}MUU`~xM?`l$c_ literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/pop2.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/pop2.wav new file mode 100755 index 0000000000000000000000000000000000000000..32c65f01cf0d59a6e3d80b736e8e370cee6c888f GIT binary patch literal 510 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 literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/water2.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/water2.wav new file mode 100755 index 0000000000000000000000000000000000000000..86462465738a5bd41afbe08b893d421f20088927 GIT binary patch literal 7488 zcmYLONs}GfS(SGzSil}4*srR!4oNn$lzYlIF$;Bu)NAAM-Nu*QU7 zDdQ$sp@s8f6kKQ{C1X;>;JnqGNg=u5#`%;S9!GnI$75eM0Pki3d)@3 z+G^)>3QBdHONpg(2*KcB*drFP&ZYVl%UP}lMWgrLN$a#Elq)kv@9;z;nUqe}Q@H3X z{^8AlXz_u@F(FtX7ex-lPsJ$irewLm*6>APM}p~CCOZsNXI~>0eN;|Z1WOKv85)=o z-g>V_YMJ4|XTsIwvvZbG6_TOSN{`1VKTS^5Rk`*~r@9=rs|9z~3GC8`piIK)h(Oq^ zLs*?g0&qgjp0W}>9*bmf#M1hhvN6(WoL6wJe8720&%53`i-0KNrZRa&1I<=U+r2ox)8??Z%$U)A(8Ffp5#t+)Ad-8 z)79@^?FK5x6xX?x*Z)f2{_v;ki?14c_0;KORO?asgJHX!j%{O(3c=Jh`RX8Lfv*$DUk!w>Eb`tALg%gzpCVwdmu%U9M1NrIg(S^V9LmP`-%Xj`Yk zv=&D?z8qcKeg1rVn;#$FuQ8f#AUlRKwabVeZUjkoMAHhDl#pV1nAA~n&3U)!1Rvdc z&O<}|$IC`gF)#PxfwD*j>soTx%yW<;trP3b1mrk0=)Eyn;~ZKFwa>QP$J1(y?PM@ZuK)$697O^1po(p`D$m*uHfz+4Vh5E+E<9gfxqv(8RxfL5Xg}E4E9$4w&~yrk z6WS;q^TcoW^71~A9Wf6NXMMkykCRg!yBqA01u?2u;`(sf2~MIO1VPVE?TA|7cpe`{ z8Hq5uC$Wzt`K+Q$J~7jC>E#U-=vZI;Xetzj*f|8=>7mopIBL&bf6I?+qyP+MW^^l~ z76&iuw(DBTdsgN^ zA9{CK_BVTfxuQMLNr&~3%KbdF&zR*9a73_74VS^+d@psY>kX<={!@@PV(mY~59K%g*6Ixw6r z0dsJhVYs29g zfL_rJyyZQyQm4t;-q}F*(%7NWEzv`+HSO(W?)TWYmVj5Q!FhH60USdle$e18pAkIC zhYmz5<#@D;t*moQ{by6%mBplY1j-p%{E%_ zYAz+{fCf@vXBR=2!PwBe_IswreSPHH`1Y5VSO2(Ml3cpG{Ow!X8};=IQot1@gmDd;9qve3dE=)O z@;aVE0>zoY$$~JM3y}EcZ+?9Hu?Y}E1)4%?lbPA6>6B3NmnumAa0pMHLs%29;aZiKL$>-iiG zO{NUa{1mLB$I+#@WYaNBI@HJ8Kl0{PPb8C+Zha5D`8-3%SnzUE<# zkSwUpTC)<`X9TOLfeo8|cyn<;)^qpsuRD6XXp^lh%-#REyxqurpw|$tKYk&bbY|$q zR;3XfiCUj%w5>23mr`-Pak)4q573e+1TS9R9e?qW{OuP%|IO8Y^+Wp~D^bs1|MF8b zFMk$3O)hFxnoY0HzZ&oM`ufdCpWoTb?Dhxt{=^9}LN9^14s2I5FmY+--tej+v`iLB&bJ zK?DGH=>FgaX-h`ELDw7LopDQU07XJWJoctQXKI1U7A^=v3`C&fROX{-7SD*37)GeyQyu(8uwahR>ATG?j1T84+xDn>=xfwi5-vHHA**API)G-H zjBAF5K^{*iC7X!~;gYCWzP$TLKmS+r+3_9o54_jy?tE@|fy9Q~c=SZ>8$DkkRXOB~ ziJ5d1%TYEaX!RVxD>fA+1XQvB_eBU4G*|SpV?f_A))~ji8YJ5R>rHkkhzOvd9PJm4C6&4}$@k<}-oCcllFvv_=s-7APnF*ZJy0SIK zgeM9#Cg z+BBqR%#}3qrt7(%lNva8WiHY*-Qne~17KOV)n<6Z-+z0#`QJYsKYjVd^+xgL^wUdk zQYoWeObqdQJMDKU3ZOvS2@;SYljAtYAz!C~-`PzE5en8cET(y$*Ce#mKF*Oag}Mww z@NobEgF)9B>R-FDaKqJhug1&<9Wdbph>8<>@L(m%onu%vAbg=pXyWqtnn_~yO;>TsO}TWm|>-1gJkJjlKw;hVYTbR)|7QRV%Q@QZ3mMu zf}@gSjt)~IluoU#f$^!VUi;{LS*5Yl|kB(LEm7IG+=fJY2y?|e+OFu3JbO6 z!J?K!2supk5Z5pe3>#D!J*)?)GK`6$j)WF*W6XjD{caUel6 za7ukxAS>(GpJFfpo`c!9<#e^({ovnU%-s!J&WZQRB^wTd_a7{~ZOPd$qyexb%w;TO zV|PFu=tSU|PY#2eW-b8jC+kMyefrr?nLECHbi2>!^zLzLp6|+WS?<3)C^Yq5U%rip zpY1-p?C^RrzSsv@T+6bFJVWA+ilL+7 zs1PMl0+7A2_IDgQ*fr_M-fYldTZM<^oYr8sX8-Z8FYL9QyI*y2Hx6vlqiB>r^%?zS zPh>w#Que?mmocvcm>oCcs7MZ&$+6Ww*j%1uhz(w^=ux0Z@U1Nvr%)~ZZ92L!_g|*> z@6?TI@}=nA4o*VyJ-3K4hMa-ihx|#I_8^)(*|6QhWx|}Q0Lj&RLdzHB)Ib3JUMdii zoq$R})ErEzR#LK%%rJR;lD>^{3Qj<97`Q9w!9cx^@Wq$_SlCK>-UB(A#Smc`r!I6x z9h_R16PE=O2$yHffuu#at64?O)A)naY7{u!HG^K|fMYxqPd6NqFqWx0_yDZndKhT1 z>YiZ$P+&Ffh{FS`hmohH?{0}q1`5EtC*MhL@AVr&2Y$%h%ck;xJBHwwZ^Y^u6RV5RtE0cwl0 zz{kn=-`)P(*O=8;!S`!2qD_#+IyxcrK=FGXHNfdM5j?+t#9JHq^NGCk4* z{|hxW<=C}=ADBU?YV;>G3!KJUf_6Y>B-Jx&3eKf)8es@bHD&zN5|C}lm|`gei{Ka_ z{d8FiY5NLFtoPkJ{gFVe3)hUS(D; zt;0NBxe2Wnc7Wp%;>Zk)A&cm1M1!XiMce9dAL5$Du7f;-4wID2kic7v)a?Qhz=iO} z;qSsfK!h@keuw3nMnC-|RvH{ivf&)>&u8@MT`f+aT4Ua;Z zqF<`nT+MOxjR9c;tuW1_u`v^ab zlu%4(NFyo?$;VANU&S+27Dphkad^ofb@Us|mzrd(1KC79{5MOg@)ZoSxTYB8hvuy= zKXd{W$9OvCy`xW#UnTj5Ex5 z3|2Df2q3a$F{J79TJ1z6AHo(c6h;c@FCpOe%2H1W1Z@ z02W+;gI0b)WurD>isSW1Z6y4FV$%^N2mGqXsF?=k09Am{2nv?2a|ELERJo`>czEE1 z`nCrz1Mt%0Y0|*jkb?kIAVggk1P6vfaY+;=tTCVsm`J4RivZLs38I)PrB$`}^qvS0 zt`v*aYjEqmSO9^nqZZJozRmy?V*iMAZAD}sCM)&@WvwEtRxk^m6S5z`oeqNz4hamb zwTcGEieL^5Z%79YR*M!xOU-e$@~|OL5_VeOVAbtlOtKO+gfLZjz`vh5`>80N_V-i; z)ffb~qmZ6B`?ru--=zJPjxpLo>;$wtQjbvKl@(5mH!K*je84%dDV!5$z&%iQNKyT; zT5le$gk`IzikgNUhw;}T?Gi{FK_B(h6&bz*HJ-JSYq3|v z0~_OWzY45lQ7t|XoGU00c+WG-yWl)9ntrKz%Qx%7{5>KX3p2&;DJqk}p67fhR z4xxk{iH8HMYFM9whN^w4dWX1Ic*Oyq(u%y|XWUjJjm!TZuj+BJdmLTh9Z-#&CSmRZ v!5c6beK2Uz1vW;U0_o346~4m+s|AE`;cg$R>5M~T84x?p2}G}KpzQwvq8oyk literal 0 HcmV?d00001