// ============================================================================ // GAME LAUNCHER IMPLEMENTATION // ============================================================================ // Menu system for selecting and launching games #include "game_launcher.h" #include "input_manager.h" #include "display/low_level_render.h" #include "display/low_level_gui.h" #include #include GameLauncher::GameLauncher(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager) : width(width), height(height), renderer(renderer), gui(gui), input_manager(input_manager), selected_index(0), selected_game(nullptr), current_page(0) { } void GameLauncher::register_game(const char* name, const char* description, std::function factory) { GameEntry entry; entry.name = name; entry.description = description; entry.factory = factory; games.push_back(entry); printf("Registered game: %s - %s\n", name, description); } void GameLauncher::draw() { // Draw main window LowLevelWindow* window = gui->draw_new_window(10, 10, width - 20, height - 20, "Game Launcher"); renderer->set_font(&font_5x5_obj); // Draw title with page indicator int total_pages = get_total_pages(); char title[64]; snprintf(title, sizeof(title), "Select a Game: (Page %d/%d)", current_page + 1, total_pages); renderer->draw_string_scaled(30, 40, title, 2); // Get games for current page int page_start = get_page_start_index(); int page_end = get_page_end_index(); // Draw game list with GUI buttons for current page only for (int i = page_start; i < page_end && i < (int)games.size(); i++) { int item_index = i - page_start; int y = MENU_Y_START + (item_index * MENU_ITEM_HEIGHT); // Draw button (pressed/highlighted if selected) bool is_selected = (i == selected_index); gui->draw_button(window, 20, y, games[i].name, is_selected, true); // Draw description below button renderer->set_font(&font_5x5_obj); // Restore small font for description renderer->set_text_color(true); // Normal text color renderer->draw_string_scaled(50, y + 36, games[i].description, 1); } // Draw navigation buttons at bottom (only if multiple pages) if (total_pages > 1) { int button_y = height - 65; // Previous page button bool has_prev = (current_page > 0); gui->draw_button(window, 30, button_y, "< PREV", false, true); // Next page button bool has_next = (current_page + 1 < total_pages); gui->draw_button(window, 200, button_y, "NEXT >", false, true); // Draw instructions renderer->set_font(&font_5x5_obj); renderer->draw_string_scaled(30, height - 25, "Touch buttons or KEY0/KEY1", 1); } else { // Single page - just show select instruction renderer->set_font(&font_5x5_obj); renderer->draw_string_scaled(30, height - 35, "KEY0: Navigate | KEY1: Select | Touch to play", 1); } } bool GameLauncher::update(const InputEvent& event) { bool needs_refresh = false; int total_pages = get_total_pages(); switch (event.type) { case INPUT_TOUCH_DOWN: { printf("Touch at (%d,%d) in launcher\n", event.x, event.y); // Check if touch is on navigation buttons (if multiple pages) if (total_pages > 1) { // Previous button: x [30-180], y [235-275] if (event.x >= PREV_BUTTON_X && event.x < PREV_BUTTON_X + BUTTON_WIDTH && event.y >= NAV_BUTTON_Y && event.y < NAV_BUTTON_Y + BUTTON_HEIGHT) { if (current_page > 0) { current_page--; selected_index = get_page_start_index(); needs_refresh = true; printf("Navigated to previous page: %d\n", current_page); } break; } // Next button: x [200-350], y [235-275] if (event.x >= NEXT_BUTTON_X && event.x < NEXT_BUTTON_X + BUTTON_WIDTH && event.y >= NAV_BUTTON_Y && event.y < NAV_BUTTON_Y + BUTTON_HEIGHT) { if (current_page + 1 < total_pages) { current_page++; selected_index = get_page_start_index(); needs_refresh = true; printf("Navigated to next page: %d\n", current_page); } break; } } // Check if touch is on a game entry for current page int page_start = get_page_start_index(); int page_end = get_page_end_index(); for (int i = page_start; i < page_end && i < (int)games.size(); i++) { int item_index = i - page_start; int y = MENU_Y_START + (item_index * MENU_ITEM_HEIGHT); // Touch area is the entire menu item if (event.y >= y - 5 && event.y < y + MENU_ITEM_HEIGHT - 5) { // Game selected - create instance printf("Selected game: %s\n", games[i].name); selected_game = games[i].factory(width, height, renderer, gui, input_manager); if (selected_game) { selected_game->init(); return true; // Signal game selected } break; } } break; } case INPUT_BUTTON_0: { // Navigate within current page or switch pages int page_start = get_page_start_index(); int page_end = get_page_end_index(); // If multiple games on current page, navigate within page first if (page_end - page_start > 1) { // Move within current page int old_index = selected_index; selected_index++; if (selected_index >= page_end) { // Moving to next page if (current_page + 1 < total_pages) { current_page++; selected_index = get_page_start_index(); } else { // Wrap to first page current_page = 0; selected_index = 0; } } else if (selected_index < page_start) { selected_index = page_start; } } else { // Single game on page, move to next page if (current_page + 1 < total_pages) { current_page++; selected_index = get_page_start_index(); } else { // Wrap to first page current_page = 0; selected_index = 0; } } needs_refresh = true; printf("Menu selection: %d (%s), Page: %d\n", selected_index, games[selected_index].name, current_page); break; } case INPUT_BUTTON_1: { // Select current game if (selected_index >= 0 && selected_index < (int)games.size()) { printf("Selected game: %s\n", games[selected_index].name); selected_game = games[selected_index].factory(width, height, renderer, gui, input_manager); if (selected_game) { selected_game->init(); return true; // Signal game selected } } break; } default: break; } return needs_refresh; } Game* GameLauncher::get_selected_game() { return selected_game; } void GameLauncher::reset() { // Clean up current game if any if (selected_game) { delete selected_game; selected_game = nullptr; } selected_index = 0; current_page = 0; printf("Launcher reset - returning to menu\n"); } void GameLauncher::clear_games() { // Clean up currently selected game first if (selected_game) { delete selected_game; selected_game = nullptr; } // Clear the games vector games.clear(); selected_index = 0; current_page = 0; printf("Launcher: Cleared all registered games\n"); } bool GameLauncher::select_game_by_name(const char* name) { // Clean up old game first if one exists if (selected_game) { printf("Cleaning up previous game...\n"); delete selected_game; selected_game = nullptr; } // First pass: search for exact match (prefer exact matches) for (size_t i = 0; i < games.size(); i++) { if (strcmp(games[i].name, name) == 0) { printf("Found exact match: %s\n", games[i].name); // Create and initialize the game selected_game = games[i].factory(width, height, renderer, gui, input_manager); if (selected_game) { printf("Game instance created, initializing...\n"); selected_game->init(); selected_index = i; current_page = i / GAMES_PER_PAGE; return true; } else { printf("Failed to create game instance\n"); return false; } } } // Second pass: search in reverse order for partial match (newest files first) for (int i = games.size() - 1; i >= 0; i--) { if (strstr(games[i].name, name) != nullptr) { printf("Found partial match: %s (searching for: %s)\n", games[i].name, name); // Create and initialize the game selected_game = games[i].factory(width, height, renderer, gui, input_manager); if (selected_game) { printf("Game instance created, initializing...\n"); selected_game->init(); selected_index = i; current_page = i / GAMES_PER_PAGE; return true; } else { printf("Failed to create game instance\n"); return false; } } } printf("Game not found: %s\n", name); return false; } int GameLauncher::get_total_pages() const { if (games.empty()) return 1; return (games.size() + GAMES_PER_PAGE - 1) / GAMES_PER_PAGE; } int GameLauncher::get_page_start_index() const { return current_page * GAMES_PER_PAGE; } int GameLauncher::get_page_end_index() const { return (current_page + 1) * GAMES_PER_PAGE; }