// PropertyModalGame.h #pragma once #include "../../lib/game.h" #include "../../display/low_level_render.h" #include "../../display/low_level_gui.h" #include "input_manager.h" #include "monopoly_board.h" #include "player.h" #include "MonopolyBoardRenderer.h" #include "sprites.h" #include "ModalButtonHelper.h" class PropertyModalGame : public Game { const BoardTile* property; bool dismissed; bool is_owned; const char* owner_name; int owner_id; // -1 if not owned bool can_afford; int selected_choice; // 0: Buy, 1: Cancel bool buy_requested; bool rent_requested; Player* players; int players_count; int observer_idx; public: PropertyModalGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager, const BoardTile* prop, bool owned, const char* owner, int o_id, bool affordable, Player* p_list = nullptr, int p_count = 0, int obs_idx = -1) : Game(width, height, renderer, gui, input_manager), property(prop), dismissed(false), is_owned(owned), owner_name(owner), owner_id(o_id), can_afford(affordable), selected_choice(-1), buy_requested(false), rent_requested(false), players(p_list), players_count(p_count), observer_idx(obs_idx) { if (is_owned || !can_afford) selected_choice = 0; } void init() override { dismissed = false; buy_requested = false; rent_requested = false; selected_choice = -1; if (is_owned || !can_afford) selected_choice = 0; ModalButtonHelper::set_monopoly_regions(input_manager, width, height); } Type get_type() const override { return Type::MONOPOLY_PROPERTY; } bool update(const InputEvent& event) override { // If rent is owed, any button pays it (it's forced) if (is_owned && owner_id != -1) { if (event.type == INPUT_BUTTON_0 || event.type == INPUT_BUTTON_1) { rent_requested = true; dismissed = true; return true; } return false; } // Otherwise (Buy/Pass), use A to cycle and B to select if (event.type == INPUT_BUTTON_0) { // BUTTON A -> Change selection if (!is_owned && can_afford) { if (selected_choice == -1) selected_choice = 0; else selected_choice = (selected_choice + 1) % 2; return true; } } if (event.type == INPUT_BUTTON_1) { // BUTTON B -> Select action if (!is_owned && can_afford) { if (selected_choice == -1) return false; // Ignore if nothing selected if (selected_choice == 0) buy_requested = true; dismissed = true; return true; } else { // Only option was Pass dismissed = true; return true; } } return false; } void draw() override { renderer->clear_buffer(); int win_w = width - 2 * (width / 7) - 4; int win_h = height - 2 * (height / 7) - 4; int win_x = width / 7 + 2; int win_y = height / 7 + 2; char buf[128]; if (players && players_count > 0) { int property_idx = -1; for(int i=0; i<40; i++) if(&MONOPOLY_BOARD[i] == property) property_idx = i; // Keep observer_idx to show player's own properties on perimeter MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players, players_count, property_idx, observer_idx); } // Window background (White box) renderer->draw_filled_rectangle(win_x, win_y, win_w, win_h, false, 0); // Clear background renderer->draw_rectangle(win_x, win_y, win_w, win_h, true, 2); renderer->draw_rectangle(win_x + 3, win_y + 3, win_w - 6, win_h - 6, true, 1); // Header Title Bar renderer->draw_filled_rectangle(win_x + 4, win_y + 4, win_w - 8, 35, true, 1); renderer->set_text_color(false); // White text snprintf(buf, sizeof(buf), "%s", property->name); renderer->draw_string_scaled(win_x + (win_w - (int)strlen(buf) * 12) / 2, win_y + 10, buf, 2); // Subtitle (Type) const char* type_str = "PROPERTY"; if (property->type == TILE_RAILROAD) type_str = "RAILROAD"; else if (property->type == TILE_UTILITY) type_str = "UTILITY"; snprintf(buf, sizeof(buf), "%s", type_str); renderer->draw_string_scaled(win_w - (int)strlen(buf) * 6 + 20, win_y + 30, buf, 1); renderer->set_text_color(true); // Info box center int info_y = win_y + 45; // Price snprintf(buf, sizeof(buf), "PRICE: $%d", property->cost); renderer->draw_string_scaled(win_x + 20, info_y, buf, 2); info_y += 25; // Rent if (property->type == TILE_PROPERTY) { snprintf(buf, sizeof(buf), "RENT: $%d", property->rent[0]); } else if (property->type == TILE_UTILITY) { snprintf(buf, sizeof(buf), "RENT: 4x DICE"); } else if (property->type == TILE_RAILROAD) { snprintf(buf, sizeof(buf), "RENT: $25"); } renderer->draw_string_scaled(win_x + 20, info_y, buf, 2); info_y += 25; // Owner if (is_owned && owner_name) { snprintf(buf, sizeof(buf), "OWNER: %s", owner_name); } else { snprintf(buf, sizeof(buf), "OWNER: %s", is_owned ? "PLAYER" : "BANK"); } renderer->draw_string_scaled(win_x + 20, info_y, buf, 2); // Draw special utility sprite if applicable const unsigned char* sprite = nullptr; if (property->type == TILE_UTILITY) { if (strstr(property->name, "Electric")) sprite = epd_bitmap_ElectricCompany; else if (strstr(property->name, "Water")) sprite = epd_bitmap_WaterWorks; } if (sprite) { renderer->draw_bitmap(sprite, win_x + win_w - 105, win_y + win_h - 105, 100, 100, true); } // Action Buttons int btn_y = win_y + win_h - 85; int btn_w = win_w - 40; int btn_h = 35; if (is_owned && owner_id != -1) { // Option: Pay Rent (A or B) renderer->draw_filled_rectangle(win_x + 20, btn_y, btn_w, btn_h, true, 1); renderer->set_text_color(false); int rent = 0; if (property->type == TILE_PROPERTY) { rent = property->rent[0]; } else if (property->type == TILE_RAILROAD) { int rr_count = 0; if (owner_id != -1 && owner_id < players_count) { for (int i = 0; i < players[owner_id].property_count; ++i) { int prop_idx = players[owner_id].properties_owned[i]; if (MONOPOLY_BOARD[prop_idx].type == TILE_RAILROAD) { rr_count++; } } } if (rr_count == 1) rent = 25; else if (rr_count == 2) rent = 50; else if (rr_count == 3) rent = 100; else if (rr_count == 4) rent = 200; else rent = 25; } else if (property->type == TILE_UTILITY) { rent = 40; } snprintf(buf, sizeof(buf), ">PAY RENT ($%d)", rent); renderer->draw_string_scaled(win_x + (win_w - (int)strlen(buf) * 12) / 2, btn_y + 10, buf, 2); renderer->set_text_color(true); } else if (!is_owned && can_afford) { if (selected_choice == 0) renderer->draw_filled_rectangle(win_x + 20, btn_y, btn_w, btn_h, true, 1); else renderer->draw_rectangle(win_x + 20, btn_y, btn_w, btn_h, true, 1); if (selected_choice == 0) renderer->set_text_color(false); snprintf(buf, sizeof(buf), "%sBUY ($%d)", (selected_choice == 0 ? "> " : " "), property->cost); renderer->draw_string_scaled(win_x + 25, btn_y + 10, buf, 2); renderer->set_text_color(true); btn_y += 40; // Pass Button if (selected_choice == 1) renderer->draw_filled_rectangle(win_x + 20, btn_y, btn_w, btn_h, true, 1); else renderer->draw_rectangle(win_x + 20, btn_y, btn_w, btn_h, true, 1); if (selected_choice == 1) renderer->set_text_color(false); snprintf(buf, sizeof(buf), "%sPASS", (selected_choice == 1 ? "> " : " ")); renderer->draw_string_scaled(win_x + 25, btn_y + 10, buf, 2); renderer->set_text_color(true); } else { renderer->draw_filled_rectangle(win_x + 20, btn_y, btn_w, btn_h, true, 1); renderer->set_text_color(false); renderer->draw_string_scaled(win_x + (win_w - 7 * 12) / 2, btn_y + 10, ">PASS", 2); renderer->set_text_color(true); } ModalButtonHelper::draw_virtual_buttons(renderer, input_manager); } bool is_dismissed() const { return dismissed; } bool wants_to_buy() const { return buy_requested; } bool wants_to_pay_rent() const { return rent_requested; } int get_owner_id() const { return owner_id; } };