diff --git a/rpi/config.py b/rpi/config.py index 548b2ab..86a8a3f 100644 --- a/rpi/config.py +++ b/rpi/config.py @@ -23,3 +23,7 @@ MEDIUM_TEXT_WIDTH = 5 PROGRAM2_TEXT_ITERATIONS = 5 PROGRAM2_TRIGGER_CHANCE = 25 PROGRAM2_VEHICLE_COUNT = 25 + +DVD_TOP_TEXT_CYCLES = 3 +DVD_TRIGGER_CHANCE = 15 +DVD_ITERATIONS = 200 diff --git a/rpi/main.py b/rpi/main.py index 0144c43..2137ecd 100644 --- a/rpi/main.py +++ b/rpi/main.py @@ -79,6 +79,9 @@ bottom_text_state = 0 scroll_node_global_id = 0 scroll_node_active = False +top_text_node_global_id = 0 +top_text_cycle_count = 0 + program2_active = False bottom_text_iteration_count = 0 program2_vehicles_spawned = 0 @@ -89,6 +92,22 @@ program2_spacing_counter = 0 program2_draw_col = 0 program2_current_vehicle = None +dvd_pending = False +dvd_active = False +dvd_x = 0 +dvd_y = 0 +dvd_dx = 1 +dvd_dy = 1 +dvd_iteration = 0 +dvd_move_counter = 0 + +DVD_TEXT = "PTI" +DVD_TEXT_W = 17 # 3 chars * 5px + 2 gaps +DVD_TEXT_H = 7 +DVD_MAX_X = config.DISPLAY_MAX_X - DVD_TEXT_W + 1 # 31 +DVD_MAX_Y = config.DISPLAY_MAX_Y - DVD_TEXT_H + 1 # 9 +DVD_COLOR = (0, 0, 50) + VEHICLES = [ [[0,0,0,0,0,0,0,0],[0,0,1,1,1,1,1,0],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]], [[0,0,1,1,0,0,0,0],[0,1,1,1,0,0,0,0],[1,1,1,1,1,1,1,1],[0,1,0,0,0,0,1,0]], @@ -292,9 +311,27 @@ def handle_multi_color_disappear_timers(): def handle_program1(): global main_animation_started, scroll_node_active, scroll_node_global_id global bottom_text_state, bottom_text_iteration_count, program2_active + global top_text_node_global_id, top_text_cycle_count + global dvd_pending, dvd_active s = server.state + # --- DVD active: handled entirely in loop() --- + if dvd_active: + return + + # --- DVD pending: wait for bottom area to clear --- + if dvd_pending: + if scroll_node_active and not _is_node_existing(scroll_node_global_id): + scroll_node_active = False + if not scroll_node_active and not program2_active: + dvd_pending = False + dvd_active = True + reset_dvd() + low_level.fill_pixels(0, 0, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0) + return + + # --- Top text management --- if not s['program_top_text_enabled']: for node in multi_color_text_nodes: if node['disappear_time'] != 0: @@ -303,12 +340,39 @@ def handle_program1(): elif not main_animation_started: if not _is_node_existing(0) and not _is_node_existing(1): main_animation_started = True - _add_multi_color_node( + node = _add_multi_color_node( "Witamy w PTI", [(40, 40, 40, 0), (0, 0, 50, 9)], - 0, 0, 3, True, True, -1, True + 0, 0, 3, True, True, -1, False ) + if node: + top_text_node_global_id = node['global_id'] + elif not _is_node_existing(top_text_node_global_id): + # Top text cycle ended + top_text_cycle_count += 1 + force_dvd = s.get('force_dvd', False) + if force_dvd: + with server._lock: + server.state['force_dvd'] = False + + if force_dvd or (top_text_cycle_count >= config.DVD_TOP_TEXT_CYCLES + and random.randint(0, 99) < config.DVD_TRIGGER_CHANCE): + top_text_cycle_count = 0 + dvd_pending = True + main_animation_started = False + return + + # Re-add top text from right edge + node = _add_multi_color_node( + "Witamy w PTI", + [(40, 40, 40, 0), (0, 0, 50, 9)], + config.DISPLAY_MAX_X, 0, 3, True, True, -1, False + ) + if node: + top_text_node_global_id = node['global_id'] + + # --- Bottom text management --- if not s['program_bottom_text_enabled']: if scroll_node_active: for node in text_nodes: @@ -354,6 +418,49 @@ def handle_program1(): bottom_text_state = (bottom_text_state + 1) % 4 +def reset_dvd(): + global dvd_x, dvd_y, dvd_dx, dvd_dy, dvd_iteration, dvd_move_counter + dvd_x = random.randint(0, DVD_MAX_X) + dvd_y = random.randint(0, DVD_MAX_Y) + dvd_dx = random.choice([-1, 1]) + dvd_dy = random.choice([-1, 1]) + dvd_iteration = 0 + dvd_move_counter = 0 + + +def handle_dvd(): + global dvd_x, dvd_y, dvd_dx, dvd_dy, dvd_iteration, dvd_move_counter + global dvd_active, main_animation_started + + if dvd_iteration >= config.DVD_ITERATIONS: + dvd_active = False + main_animation_started = False + return + + dvd_iteration += 1 + + dvd_move_counter += 1 + if dvd_move_counter >= 2: + dvd_move_counter = 0 + + new_x = dvd_x + dvd_dx + new_y = dvd_y + dvd_dy + + if new_x < 0 or new_x > DVD_MAX_X: + dvd_dx = -dvd_dx + new_x = dvd_x + dvd_dx + if new_y < 0 or new_y > DVD_MAX_Y: + dvd_dy = -dvd_dy + new_y = dvd_y + dvd_dy + + dvd_x = new_x + dvd_y = new_y + + cursor = {'x': dvd_x, 'y': dvd_y} + for ch in DVD_TEXT: + _draw_char(ch, config.SMALL_TEXT_HEIGHT, config.SMALL_TEXT_WIDTH, *DVD_COLOR, cursor) + + def draw_vehicle(index, pos_x, pos_y): vr, vg, vb = config.VEHICLE_COLOR for row in range(4): @@ -431,9 +538,21 @@ def loop(): s = server.state + if dvd_active: + low_level.fill_pixels(0, 0, config.DISPLAY_MAX_X, config.DISPLAY_MAX_Y, 0, 0, 0) + handle_dvd() + strip.show() + _send_frame() + return + low_level.fill_pixels(0, 0, config.DISPLAY_MAX_X, 7, 0, 0, 0) handle_program1() + if dvd_active: + strip.show() + _send_frame() + return + if s['program_top_text_enabled']: scroll_all_multi_color_texts(split_scroll_mode=True) handle_multi_color_disappear_timers() diff --git a/rpi/server.py b/rpi/server.py index e51aae2..2fc12e3 100644 --- a/rpi/server.py +++ b/rpi/server.py @@ -19,6 +19,7 @@ state = { 'program_bottom_text_enabled': True, 'program_vehicles_enabled': True, 'force_vehicles': False, + 'force_dvd': False, } _lock = threading.Lock() @@ -71,6 +72,9 @@ INDEX_HTML = """ .btn-vehicles { background: #2a4a7f; color: #eee; } .btn-vehicles:hover { background: #3a5a9f; } .btn-vehicles:active { background: #1a3a6f; } + .btn-dvd { background: #6b2a7f; color: #eee; } + .btn-dvd:hover { background: #8b3a9f; } + .btn-dvd:active { background: #5b1a6f; }
@@ -100,6 +104,7 @@ INDEX_HTML = """ +