// DiceModalGame.h #pragma once #include "../../lib/game.h" #include "../../display/low_level_render.h" #include "../../display/low_level_gui.h" #include "input_manager.h" #include "MonopolyBoardRenderer.h" class DiceModalGame : public Game { int dice1, dice2; const BoardTile *from_tile, *to_tile; Player* players; int players_count; bool dismissed; void draw_die(int x, int y, int size, int value) { // Die base renderer->draw_rounded_rectangle(x, y, size, size, 4, true, false); // Shadow (offset 2,2) renderer->draw_line(x + size, y + 2, x + size, y + size, true); renderer->draw_line(x + 2, y + size, x + size, y + size, true); int dot_size = size / 6; int m = size / 2; int l = size / 4; int r = 3 * size / 4; int t = size / 4; int b = 3 * size / 4; auto draw_dot = [&](int dx, int dy) { renderer->draw_filled_rectangle(x + dx - dot_size / 2, y + dy - dot_size / 2, dot_size, dot_size, true, 1); }; if (value % 2 == 1) draw_dot(m, m); // Center dot for 1, 3, 5 if (value > 1) { draw_dot(l, t); draw_dot(r, b); } if (value > 3) { draw_dot(r, t); draw_dot(l, b); } if (value == 6) { draw_dot(l, m); draw_dot(r, m); } } public: DiceModalGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager, int d1, int d2, const BoardTile* from, const BoardTile* to, Player* p, int count) : Game(width, height, renderer, gui, input_manager), dice1(d1), dice2(d2), from_tile(from), to_tile(to), players(p), players_count(count), dismissed(false) {} void init() override { dismissed = false; } Type get_type() const override { return Type::MONOPOLY_DICE; } bool update(const InputEvent& event) override { // Only B dismisses now, so A can still be used for "change action" (even if it does nothing here) if (event.type == INPUT_BUTTON_1) { dismissed = true; return true; } return false; } void draw() override { renderer->clear_buffer(); MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players, players_count, (to_tile ? -1 /* or some index */ : -1)); // Keep it simple for now or pass relevant pos // Let's pass the destination position to highlight it during the dice roll int target_pos = -1; for(int i=0; i<40; i++) if(&MONOPOLY_BOARD[i] == to_tile) target_pos = i; MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players, players_count, target_pos); // --- Inner UI (Center Area) --- int cw = width / 7; int ch = height / 7; int ix = cw + 2, iy = ch + 2; int iw = width - 2 * cw - 4, ih = height - 2 * ch - 4; // Window background (White box) renderer->draw_filled_rectangle(ix, iy, iw, ih, false, 0); // Clear central area renderer->draw_rectangle(ix, iy, iw, ih, true, 1); // Border // Header renderer->draw_filled_rectangle(ix + 2, iy + 2, iw - 4, 30, true, 1); renderer->set_text_color(false); renderer->draw_string_scaled(ix + (iw - (int)strlen("==DICE ROLL==") * 12) / 2, iy + 10, "==DICE ROLL==", 2); renderer->set_text_color(true); // Dice int dice_size = 50; int dice_y = iy + 45; draw_die(ix + iw / 2 - dice_size - 10, dice_y, dice_size, dice1); draw_die(ix + iw / 2 + 10, dice_y, dice_size, dice2); // Total char buf[32]; snprintf(buf, sizeof(buf), "TOTAL: %d", dice1 + dice2); renderer->draw_string_scaled(ix + (iw - 100) / 2, dice_y + dice_size + 10, buf, 2); // Movement info int info_y = dice_y + dice_size + 30; char move_buf[64]; if (from_tile && to_tile) { snprintf(move_buf, sizeof(move_buf), "FROM: %s", from_tile->name); renderer->draw_string_scaled(ix + 10, info_y, move_buf, 1); info_y += 12; snprintf(move_buf, sizeof(move_buf), "TO: %s", to_tile->name); renderer->draw_string_scaled(ix + 10, info_y, move_buf, 1); } // Button int btn_w = 120, btn_h = 25; int btn_x = ix + (iw - btn_w) / 2; int btn_y = iy + ih - 35; renderer->draw_filled_rectangle(btn_x, btn_y, btn_w, btn_h, true, 1); renderer->set_text_color(false); renderer->draw_string_scaled(btn_x + 5, btn_y + 5, "> CONTINUE", 2); renderer->set_text_color(true); } bool is_dismissed() const { return dismissed; } };