class MyGame(arcade.Window): """ Main application class. """ def __init__(self): # Call the parent class and set up the window super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) arcade.set_background_color(arcade.csscolor.CORNFLOWER_BLUE) def setup(self, restart=False): """ Set up the game here. Call this function to restart the game. """ self.note = Note(*NOTE_POS) self.button = Button(*BUTTON_POS) self.clock = Clock(*CLOCK_POS) self.strikes = Strikes(*STRIKES_POS) self.init_items() self.init_person() self.init_idcard() self.state = State.START_FADE_IN self.state_time = 0 self.day = 1 self.score = 0 self.guide_visible = False if not restart: self.sound_player = None arcade.play_sound(assets.sounds['elevator_music'], volume=0.03, looping=True) self.set_fullscreen(True) self.set_icon(pyglet.image.load("res/image/icon.png")) def on_draw(self): """ Render the screen. """ arcade.start_render() if self.state in [ State.START_SCREEN, State.START_FADE_OUT, State.START_FADE_IN ]: arcade.draw_scaled_texture_rectangle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, assets.intro_image, 1, 0) if self.guide_visible: arcade.draw_scaled_texture_rectangle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, assets.guide_image, 1, 0) arcade.draw_scaled_texture_rectangle(SCREEN_WIDTH - 200, 100, assets.close_image, .5, 0) if self.state == State.START_FADE_OUT: arcade.draw_rectangle_filled( SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT, (0, 0, 0, max(int(self.state_time * 255), 0))) elif self.state == State.START_FADE_IN: arcade.draw_rectangle_filled( SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT, (0, 0, 0, max(int((1 - self.state_time) * 255), 0))) return arcade.draw_scaled_texture_rectangle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, assets.bg_image, 1, 0) self.button.draw() self.person.draw() self.id_card.draw() self.clock.draw() self.note.draw() self.strikes.draw() for item in reversed(self.items): item.draw() if self.state == State.DAY_FADE_IN: arcade.draw_rectangle_filled( SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT, (0, 0, 0, max(int((1 - self.state_time) * 255), 0))) elif self.state in [State.DAY_FADE_OUT, State.END_FADE_OUT]: arcade.draw_rectangle_filled( SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT, (0, 0, 0, max(int(self.state_time * 255), 0))) elif self.state == State.DAY_INTRO: arcade.draw_rectangle_filled(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT, arcade.color.BLACK) if self.state_time < 4: color = (min(int(self.state_time * 255), 255), ) * 3 else: color = (min(int((5 - self.state_time) * 255), 255), ) * 3 arcade.draw_text(f"Day {['one', 'two', 'three'][self.day-1]}", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, color, 48, align="center", anchor_x="center", anchor_y="center") elif self.state == State.END_SCREEN: arcade.draw_rectangle_filled(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT, arcade.color.BLACK) text = f"You correctly returned {self.score} lost items." if self.strikes.strikes == 3: text = f"You have been fired for returning items wrongly.\n\n{text}" text = f"{text}\n\n\n\nPress R to play again." color = (min(int(self.state_time * 255), 255), ) * 3 arcade.draw_text(text, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, color, 48, align="center", anchor_x="center", anchor_y="center") def on_update(self, delta): """ Game logic """ self.state_time += delta if self.state in [State.END_SCREEN, State.START_SCREEN]: return elif self.state == State.DAY_FADE_IN: if self.state_time > 1: self.transition(State.CHOOSING) return elif self.state == State.START_FADE_IN: if self.state_time > 1: self.transition(State.START_SCREEN) return elif self.state == State.START_FADE_OUT: if self.state_time > 1: self.transition(State.DAY_INTRO) elif self.state == State.END_FADE_OUT: if self.state_time > 1: self.transition(State.END_SCREEN) elif self.state == State.DAY_FADE_OUT: if self.state_time > 1: self.transition(State.DAY_INTRO) self.advance_day() return elif self.state == State.DAY_INTRO: if self.state_time > 5: self.transition(State.DAY_FADE_IN) return self.person.update(delta) self.clock.update(delta) for item in self.items: item.update(delta) if self.held_item is not None: self.held_item.move(self.mouse_x, self.mouse_y) if self.state == State.CHOICE_MADE and not self.person.is_traveling: self.transition(State.CHOOSING) if self.state == State.CHOOSING and self.strikes.strikes == 3: self.transition(State.END_FADE_OUT) if self.person.state == State.ENTER and not self.person.is_traveling: self.person.set_state(State.INTRO) elif self.person.state == State.INTRO: if not is_playing(self.sound_player): self.sound_player = self.person.play_sound("intro") self.person.set_state(State.DESCRIBE) elif self.person.state == State.DESCRIBE: if not is_playing(self.sound_player): self.sound_player = self.person.wanted_item.play_sound() self.person.set_state(State.WAITING) elif self.person.state in [State.AWAY_RIGHT, State.AWAY_WRONG]: if not is_playing(self.sound_player): if self.person.state == State.AWAY_RIGHT: sound = "right" else: sound = "wrong" self.sound_player = self.person.play_sound(sound) self.person.set_state(State.EXIT) elif self.person.state == State.EXIT and not self.person.is_traveling: if self.clock.is_completed(): self.transition(State.DAY_FADE_OUT) self.person.state = State.WAITING return self.init_person() self.init_idcard() def init_items(self): """ Create a 3x4 grid of items """ self.held_item = None self.items = [] available_items = random.sample(list(assets.items), 12) for r in range(3): for c in range(4): ox, oy = GRID_POS rangle = math.pi * 2 * random.random() rlength = GRID_ITEM_RAND_MAX_OFFSET * random.random()**.3 rx, ry = math.cos(rangle) * rlength, math.sin(rangle) * rlength self.items.append( Item(ox + rx + GRID_ITEM_SIZE * c, oy + ry + GRID_ITEM_SIZE * r, available_items.pop())) def init_person(self): """ Create a person that travels to its position """ self.person = Person(0, SCREEN_HEIGHT + IMAGE_SIZE) self.person.travel_to(500, 800, spin=False) self.person.set_state(State.ENTER) self.person.pick_item(self.items) self.note.set_item(self.person.wanted_item.name) self.note.set_person_name(self.person.name) self.note.randomize_fake() def init_idcard(self): """ Inits the id card of the current person with a 30% chance of the card being false. """ self.id_card = IdCard(self.person, True if random.randint(0, 100) < 30 else False) def transition(self, state): """ Changes state """ self.state = state self.state_time = 0 def advance_day(self): """ Move to the next day """ if self.day == 3: self.transition(State.END_SCREEN) self.day = (self.day % 3) + 1 self.note.day = self.day self.clock.time = 0 self.init_items() self.init_person() self.init_idcard() def get_strike(self): arcade.play_sound(assets.sounds['strike'], volume=0.1) self.strikes.strikes += 1 if self.strikes.strikes == 3: self.transition(State.END_FADE_OUT) def on_mouse_press(self, x, y, button, _modifiers): """ Handle mouse press """ if button != 1: # Left return if self.held_item is not None: return for item in self.items: if dist(item.x, item.y, x, y) < IMAGE_SIZE / 2 * Item.SCALE * .9: self.held_item = item break if dist(self.button.x, self.button.y, x, y) < 70 * Button.SCALE: if self.state == State.CHOOSING: new_x = self.person.x - 1.5 * IMAGE_SIZE self.person.set_state(State.AWAY_WRONG) self.person.travel_to(new_x, SCREEN_HEIGHT + IMAGE_SIZE) self.transition(State.CHOICE_MADE) if not self.note.is_fake and not self.id_card.is_false(): self.get_strike() if self.state == State.START_SCREEN: if self.guide_visible: self.guide_visible = False arcade.play_sound(assets.sounds['click']) elif 350 < y and y < 600: if 1030 < x and x < 1500: self.guide_visible = True arcade.play_sound(assets.sounds['click']) if 470 < x and x < 940: self.transition(State.START_FADE_OUT) arcade.play_sound(assets.sounds['click']) def on_mouse_release(self, x, y, button, _modifiers): """ Handle mouse release """ if button != 1: # Left return if self.held_item is not None: if self.state == State.CHOOSING \ and dist(x, y, self.person.x, self.person.y) < ITEM_PLACE_RANGE: self.transition(State.CHOICE_MADE) if self.person.wanted_item.name == self.held_item.name: new_x = self.person.x + 1.5 * IMAGE_SIZE self.person.set_state(State.AWAY_RIGHT) if self.note.is_fake or self.id_card.is_false(): self.get_strike() else: self.score += 1 else: new_x = self.person.x - 1.5 * IMAGE_SIZE self.person.set_state(State.AWAY_WRONG) self.get_strike() self.person.travel_to(new_x, SCREEN_HEIGHT + IMAGE_SIZE) self.items.remove(self.held_item) self.person.give_item(self.held_item) self.held_item.x = self.held_item.orig_x self.held_item.y = self.held_item.orig_y self.held_item = None def on_mouse_motion(self, x, y, _dx, _dy): """ Handle mouse release """ self.mouse_x = x self.mouse_y = y def on_key_press(self, key, modifiers): """Called whenever a key is pressed. """ if key == arcade.key.F: self.set_fullscreen(not self.fullscreen) width, height = self.get_size() self.set_viewport(0, width, 0, height) elif key in [arcade.key.ESCAPE, arcade.key.Q]: exit() elif key == arcade.key.R: if self.state == State.END_SCREEN: self.setup(restart=True)
class Lane: def __init__(self, tree_type="sportsman", delay=0.5, start=None, lane="left", computer=True, perfect=0.0, rollout=0.220, cmin=-0.009, cmax=0.115, surface=None, background=None): self.perfect = perfect self.rollout = rollout self.cmin = cmin self.cmax = cmax self.surface = surface self.rect = self.surface.get_rect() self.dirty_rects = [] self.dirty = False self.tree_type = tree_type if tree_type == "sportsman": self.multiplier = 3 elif tree_type == "pro": self.multiplier = 1 self.state = None self.launched_time = None self.start_time = None self.foul = threading.Event() self.launched = threading.Event() self.pre_staged = threading.Event() self.staged = threading.Event() self.flashing = threading.Event() self.y1 = threading.Event() self.y2 = threading.Event() self.y3 = threading.Event() self.g = threading.Event() self.reaction = None self.dial_in = 0.0 self.log = [] self.computer = computer self.start = start self.delay = delay self.state = 0 self.total_delay = self.delay * self.multiplier self.start_time = None self.clock_log = [] clock_rect = pygame.Rect( 0, self.rect.height - self.rect.height / 7.0, self.rect.width, self.rect.height / 7.0) clock_rect.bottom = self.rect.height self.clock = Clock(clock_rect) self.background = pygame.Surface( (self.rect.width, self.rect.height), flags=pygame.SRCALPHA) self.background.blit( background, (0, 0), area=( self.surface.get_offset(), (self.rect.width, self.rect.height))) self.surface.blit(self.background, (0, 0)) self.lane = lane.lower() light_width = (self.rect.height / 7) - (self.rect.height / 35.0) self.lights = [ Light(light_width, light_type='staging'), Light(light_width, light_type='staging'), Light(light_width, light_type='yellow'), Light(light_width, light_type='yellow'), Light(light_width, light_type='yellow'), Light(light_width, light_type='green'), Light(light_width, light_type='red') ] #if self.lane == "left": # self.offset = int(round(self.rect.width * 0.49, 0)) #else: self.offset = int(round(self.rect.height / 16.5, 0)) total_offset = self.rect.height / 20.575 counter = 0 for light in self.lights: if self.lane == "right": light.rect.left = self.offset else: light.rect.right = self.rect.right - self.offset light.rect.top = int(round(total_offset, 0)) if counter == 0: total_offset += light_width - (light_width / 11.0) elif counter == 1: total_offset += light_width / 2.25 else: total_offset += (light_width / 10.0) + light_width #total_offset += (self.rect.height / 700.0) * 1.49 counter += 1 def reset(self): self.start_time = None self.launched_time = None self.foul.clear() self.flashing.clear() self.launched.clear() self.pre_staged.clear() self.staged.clear() self.y1.clear() self.y2.clear() self.y3.clear() self.g.clear() self.clock.reset() self.clock_log = [] for light in self.lights: light.off() self.pre_stage() def pre_stage(self): self.pre_staged.set() self.state = 0 self.lights[0].on() if self.computer: self.stage() def stage(self): self.state = 1 self.lights[1].on() self.staged.set() def _start(self): threading.Thread(None, self.timer, name=self.lane + " timer()").start() def launch(self): self.start.wait() if self.computer: if self.cmin == self.cmax: computer_delay = self.cmin else: computer_delay = random.randrange( (self.total_delay * 1000) + (self.cmin * 1000), (self.total_delay * 1000 ) + (self.cmax * 1000), 1) / 1000.0 self.launched_time = self.start_time + computer_delay self.launched.set() else: self.launched.wait() self.launched_time += self.rollout self.reaction = self.launched_time + self.perfect self.reaction -= (self.total_delay + self.start_time) if not self.total_delay + self.start_time - time.time() < 0: time.sleep(self.start_time + self.total_delay + self.reaction -self.perfect - time.time()) if self.reaction < self.perfect: self.red() self.pre_staged.clear() self.lights[0].off() self.staged.clear() self.lights[1].off() self.clock.draw(self.reaction) self.log.append(self.reaction) def timer(self): launch = threading.Thread(None, self.launch, name=self.lane + " launch()").start() threading.Thread(None, self.yellow1, name=self.lane + " yellow1()").start() threading.Thread(None, self.yellow2, name=self.lane + " yellow2()").start() threading.Thread(None, self.yellow3, name=self.lane + " yellow3()").start() threading.Thread(None, self.green, name=self.lane + " green()").start() self.state = 2 def light(self, number=0): if self.foul.is_set(): return False if self.tree_type == "pro": if number == 3: number = 1 else: number = 0 while time.time() < self.start_time + (self.delay * number): if self.foul.is_set(): return False return True def yellow1(self): self.y1.wait() if not self.foul.is_set(): self.lights[2].on() time.sleep(self.delay) if not self.foul.is_set(): self.lights[2].off() def yellow2(self): if self.tree_type == "pro": self.y1.wait() else: self.y2.wait() if not self.foul.is_set(): self.lights[3].on() time.sleep(self.delay) if not self.foul.is_set(): self.lights[3].off() def yellow3(self): if self.tree_type == "pro": self.y1.wait() else: self.y3.wait() if not self.foul.is_set(): self.lights[4].on() time.sleep(self.delay) if not self.foul.is_set(): self.lights[4].off() def green(self): self.g.wait() if not self.foul.is_set(): self.lights[5].on() def red(self): self.foul.set() self.lights[6].on() self.lights[5].off() def win(self): self.flashing.set() threading.Thread(None, self.flash, name=self.lane + " flash()").start() def flash(self): try: while self.flashing.is_set(): for light in self.lights[2:5]: light.on() time.sleep(0.5) for light in self.lights[2:5]: light.off() time.sleep(0.5) for light in self.lights[2:5]: light.off() except: pass def draw(self): dirty_objects = [] for light in self.lights + [self.clock]: if light.dirty: dirty_objects.append(light) self.dirty_rects.append( light.rect.move(self.surface.get_offset())) light.dirty = False # if self.dirty: # self.dirty = self.dirty.union(light.rect) # else: # self.dirty = light.rect # if self.dirty: # self.surface.blit( # self.background, # (self.dirty.left, self.dirty.top), # area=self.dirty) self.dirty = bool(len(dirty_objects)) for light in dirty_objects: self.surface.blit(self.background, (light.rect.left, light.rect.top), area=light.rect) self.surface.blit(light.surface, (light.rect.left, light.rect.top))
class Sequency(threading.Thread): def __init__(self, midi_in, midi_out): super(Sequency, self).__init__() self._midi_out = midi_out self._midi_in = midi_in # Clock messages are ignored by default midi_in.ignore_types(timing=False) midi_in.set_callback(self._handle_input) self._lp = LaunchpadMini(midi_in, midi_out) self._controller = MidiToControl() self._boot_combo = [] self._reboot_set = False self._control_mode = CONTROL_MODE.DEFAULT sequence_states = self._load_from_state() self._clock = Clock() self._sequences = [] self._active_sequence = 0 for i in range(0, 8): self._sequences.append( Sequencer(i, self._on_trigger, sequence_states[i])) self.start() def run(self): self.done = False time.sleep(5) self._startup_animation() self._draw_active_sequence() self._draw() while not self.done: time.sleep(0.02) def kill(self): self._write_save_state_raw() self._lp.turn_all_pads_off() def _startup_animation(self): for colour in [COLOUR_RED, COLOUR_ORANGE, COLOUR_GREEN]: for brightness in [ BRIGHTNESS_LOW, BRIGHTNESS_MEDIUM, BRIGHTNESS_HIGH ]: for coords in CIRCLE_COORDS: self._lp.turn_pad_on(coords, colour, brightness) time.sleep(0.01) self._lp.turn_all_pads_off() def _get_sequence_colour(self, index): if self._sequences[index].mute: return COLOUR_RED elif index == self._active_sequence: return COLOUR_GREEN return COLOUR_ORANGE def _on_trigger(self, index, channel, note): self._midi_out.send_message([143 + channel, note, 64]) bsp_lp = threading.Timer(0.06, self._end_trigger_bsp, [index, channel, note]) bsp_lp.start() colour = self._get_sequence_colour(index) self._lp.turn_pad_on(('T', index), colour, BRIGHTNESS_HIGH) t_lp = threading.Timer(0.1, self._end_trigger_lp, [index]) t_lp.start() def _end_trigger_lp(self, index): colour = self._get_sequence_colour(index) self._lp.turn_pad_on(('T', index), colour, BRIGHTNESS_LOW) def _end_trigger_bsp(self, index, channel, note): self._midi_out.send_message([127 + channel, note, 64]) def _handle_input(self, event, data=None): message, deltatime = event if message[0] is TIMING_CLOCK: self._clock.clock_pulse() for seq in self._sequences: seq.clock_pulse() elif message[0] is SONG_START: self._clock.reset() for seq in self._sequences: seq.reset() elif message[0] is SONG_STOP or message[0] is SONG_CONTINUE: pass else: command = self._controller.map_midi_to_command( message, self._control_mode) self._handle_command(command) self._draw() def _handle_command(self, command): if not command: return command_type, args = command if command_type is COMMAND.NONE: return elif command_type is COMMAND.CHANGE_CONTROL_MODE: self._change_control_mode(args[0]) elif command_type is COMMAND.CHANGE_SEQUENCE: self._change_active_sequence(args[0]) elif command_type is COMMAND.TOGGLE_MUTE: self._toggle_mute() elif command_type is COMMAND.SET_MUTE: self._set_mute(args[0], args[1]) elif command_type is COMMAND.CHANGE_MODE: self._change_sequence_mode(args[0]) elif command_type is COMMAND.MANUAL_INPUT: self._input_manual_step(args) elif command_type is COMMAND.CHANGE_LENGTH_INC: self._increment_sequence_length(args[0]) elif command_type is COMMAND.CHANGE_LENGTH_DEC: self._decrement_sequence_length(args[0]) elif command_type is COMMAND.CHANGE_FILL_INC: self._increment_fill(args[0]) elif command_type is COMMAND.CHANGE_FILL_DEC: self._decrement_fill(args[0]) elif command_type is COMMAND.CHANGE_OFFSET_INC: self._increment_sequence_offset(args[0]) elif command_type is COMMAND.CHANGE_OFFSET_DEC: self._decrement_sequence_offset(args[0]) elif command_type is COMMAND.CHANGE_CHANNEL_INC: self._increment_sequence_channel(args[0]) elif command_type is COMMAND.CHANGE_CHANNEL_DEC: self._decrement_sequence_channel(args[0]) elif command_type is COMMAND.CHANGE_NOTE_REL: self._change_sequence_note(args[0], args[1]) elif command_type is COMMAND.BOOT_COMBO: self._handle_boot_combo(args) else: print('Unkown command', command_type, args) self._write_save_state() def _change_active_sequence(self, index): self._active_sequence = index self._draw_active_sequence() def _change_control_mode(self, mode): self._control_mode = mode self._lp.turn_all_pads_off() self._draw_active_sequence() self._draw() def _toggle_mute(self): self._sequences[self._active_sequence].toggle_mute() self._draw_active_sequence() def _set_mute(self, index, mute): self._sequences[index].set_mute(mute) self._draw_active_sequence() def _change_sequence_mode(self, mode): active_sequence = self._sequences[self._active_sequence] active_sequence.change_mode(mode) self._draw_active_sequence() def _increment_sequence_length(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.increment_length() self._draw_active_sequence() def _decrement_sequence_length(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.decrement_length() self._draw_active_sequence() def _increment_fill(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.increment_fill() self._draw_active_sequence() def _decrement_fill(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.decrement_fill() self._draw_active_sequence() def _increment_sequence_offset(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.increment_offset() self._draw_active_sequence() def _decrement_sequence_offset(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.decrement_offset() self._draw_active_sequence() def _increment_sequence_channel(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.increment_channel() self._draw_active_sequence() def _decrement_sequence_channel(self, index): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.decrement_channel() self._draw_active_sequence() def _change_sequence_note(self, index, delta): self._active_sequence = index active_sequence = self._sequences[self._active_sequence] active_sequence.change_note(delta) self._draw_active_sequence() def _handle_boot_combo(self, key_event): if self._reboot_set: return key, on = key_event if on: self._boot_combo.append(key) if len(self._boot_combo) == 4: self._reboot_set = True for coords in self._boot_combo: self._lp.turn_pad_on(coords, COLOUR_GREEN, BRIGHTNESS_HIGH) os.system('sudo sh /home/pi/measure_pi/swap_config.sh') else: self._boot_combo.remove(key) self._lp.turn_pad_off(key) def _input_manual_step(self, coords): if coords in CIRCLE_COORDS: step = CIRCLE_COORDS.index(coords) active_sequence = self._sequences[self._active_sequence] active_sequence.manual_input(step) def _draw_active_sequence(self): for i, sequence in enumerate(self._sequences): colour = COLOUR_ORANGE if sequence.mute: colour = COLOUR_RED if i == self._active_sequence: colour = COLOUR_GREEN self._lp.turn_pad_on(('T', i), colour) active_sequence = self._sequences[self._active_sequence] if active_sequence.mute: self._lp.turn_pad_on((8, 0), COLOUR_RED, BRIGHTNESS_HIGH) else: self._lp.turn_pad_off((8, 0)) if active_sequence._mode is EUCLIDIAN: self._lp.turn_pad_on((8, 1), COLOUR_GREEN, BRIGHTNESS_HIGH) else: self._lp.turn_pad_off((8, 1)) if active_sequence._mode is REV_EUCLIDIAN: self._lp.turn_pad_on((8, 2), COLOUR_GREEN, BRIGHTNESS_HIGH) else: self._lp.turn_pad_off((8, 2)) if active_sequence._mode is MANUAL: self._lp.turn_pad_on((8, 3), COLOUR_GREEN, BRIGHTNESS_HIGH) else: self._lp.turn_pad_off((8, 3)) def _draw(self): clock_state = self._clock.draw() for i, message in enumerate(clock_state): colour, brightness = message self._lp.turn_pad_on((8, 7 - i), colour, brightness) if self._control_mode is CONTROL_MODE.DEFAULT: self._draw_sequence() elif self._control_mode is CONTROL_MODE.SETTINGS: self._draw_settings() def _draw_sequence(self): active_sequence = self._sequences[self._active_sequence] sequence_state = active_sequence.draw() for i, message in enumerate(sequence_state): colour, brightness = message self._lp.turn_pad_on(CIRCLE_COORDS[i], colour, brightness) def _draw_settings(self): active_sequence = self._sequences[self._active_sequence] settings_state = active_sequence.draw_settings() for i, message in enumerate(settings_state): colour, brightness = message self._lp.turn_pad_on(SETTINGS_COORDS[i], colour, brightness) def _load_from_state(self): try: f = open('state.txt', 'r') lines = f.readlines() sequence_states = [] parsing_sequences = False for line in lines: if parsing_sequences: sequence_states.append(line) if line == 'seqs\n': parsing_sequences = True f.close() # If somehow we're missing states fill up to 8 sequence_states.extend([None] * (8 - len(sequence_states))) return sequence_states except: print('Invalid state file, resetting defaults') return [None] * 8 @debounce(1) def _write_save_state(self): self._write_save_state_raw() def _write_save_state_raw(self): state = 'seqs' for seq in self._sequences: state += '\n' state += seq.get_save_state() f = open('state.txt', 'w') f.write(state) f.close()