// ============================================================================ // MONOPOLY GAME IMPLEMENTATION (for custom console) // ============================================================================ // Refactored from console version to use Game interface and rendering/input system #include "monopoly_game.h" #ifdef __cplusplus extern "C" { #endif #include "player.h" #ifdef __cplusplus } #endif #include #include #include #include #include "DiceModalGame.h" #include "PropertyModalGame.h" #include "BoardModalGame.h" #include "MonopolyBoardRenderer.h" // --- Constructor --- MonopolyGame::MonopolyGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager) : Game(width, height, renderer, gui, input_manager) { players_count = 2; current_player_idx = 0; has_rolled = false; double_rolls = 0; just_sent_to_jail = false; } // --- Initialize game state --- void MonopolyGame::init() { // Hardcoded 2 players for minimal version init_player(&players[0], 0, "Elias", "Top Hat"); init_player(&players[1], 1, "Adolfo", "Racecar"); players_count = 2; current_player_idx = 0; has_rolled = false; double_rolls = 0; just_sent_to_jail = false; selected_action = 0; srand(time(NULL)); if (active_modal) { delete active_modal; active_modal = nullptr; } // TODO: Reset all board state, property ownership, etc. } // --- Handle input events (minimal: roll, buy, end turn) --- bool MonopolyGame::update(const InputEvent& event) { Player* p = &players[current_player_idx]; bool needs_redraw = false; // If a modal is active, delegate input and check for dismissal if (active_modal) { bool modal_redraw = active_modal->update(event); if (modal_redraw) needs_redraw = true; // Check for specific modal types to handle their results auto dice_modal = dynamic_cast(active_modal); auto prop_modal = dynamic_cast(active_modal); auto board_modal = dynamic_cast(active_modal); if (dice_modal && dice_modal->is_dismissed()) { delete active_modal; active_modal = nullptr; needs_redraw = true; } else if (prop_modal && prop_modal->is_dismissed()) { if (prop_modal->wants_to_buy()) { const BoardTile* tile = &MONOPOLY_BOARD[p->position]; p->balance -= tile->cost; p->properties_owned[p->property_count++] = p->position; } delete active_modal; active_modal = nullptr; needs_redraw = true; } else if (board_modal && board_modal->is_dismissed()) { delete active_modal; active_modal = nullptr; needs_redraw = true; } return needs_redraw; } switch (event.type) { case INPUT_BUTTON_0: // Cycle options selected_action = (selected_action + 1) % ACTION_COUNT; needs_redraw = true; break; case INPUT_BUTTON_1: // Select option switch (selected_action) { case 0: // Context Action if (!has_rolled) { // Roll Dice if (!p->is_in_jail) { int dice1 = (rand() % 6) + 1; int dice2 = (rand() % 6) + 1; int total = dice1 + dice2; int old_pos = p->position; p->position = (p->position + total) % BOARD_SIZE; if (p->position < old_pos) p->balance += 200; has_rolled = true; needs_redraw = true; // Store dice values and show dice modal last_dice1 = dice1; last_dice2 = dice2; if (active_modal) delete active_modal; active_modal = new DiceModalGame(width, height, renderer, gui, input_manager, dice1, dice2, &MONOPOLY_BOARD[old_pos], &MONOPOLY_BOARD[p->position], players, players_count); // Show property modal if landed on property/railroad/utility const BoardTile* landed = &MONOPOLY_BOARD[p->position]; if (landed->type == TILE_PROPERTY || landed->type == TILE_RAILROAD || landed->type == TILE_UTILITY) { modal_property_index = p->position; } } } else { // End Turn current_player_idx = (current_player_idx + 1) % players_count; has_rolled = false; double_rolls = 0; just_sent_to_jail = false; selected_action = 0; // Reset selection for next player needs_redraw = true; } break; case 1: // View Board if (active_modal) delete active_modal; active_modal = new BoardModalGame(width, height, renderer, gui, input_manager, players, players_count); needs_redraw = true; break; } break; default: break; } // If dice modal was just dismissed and a property modal is queued, show it if (!active_modal && modal_property_index >= 0) { // Evaluate ownership and affordability bool is_owned = false; const char* owner_name = nullptr; for (int i = 0; i < players_count; ++i) { for (int j = 0; j < players[i].property_count; ++j) { if (players[i].properties_owned[j] == modal_property_index) { is_owned = true; owner_name = players[i].name; break; } } if (is_owned) break; } bool can_afford = (p->balance >= MONOPOLY_BOARD[modal_property_index].cost); active_modal = new PropertyModalGame(width, height, renderer, gui, input_manager, &MONOPOLY_BOARD[modal_property_index], is_owned, owner_name, can_afford, players, players_count); modal_property_index = -1; needs_redraw = true; } return needs_redraw; } // --- Draw game state (minimal: player info, current tile, actions) --- void MonopolyGame::draw() { // If a modal is active, draw it and return if (active_modal) { active_modal->draw(); return; } renderer->clear_buffer(); // --- Draw Board Perimeter --- MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players, players_count); // --- Inner Dashboard (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; Player* p = &players[current_player_idx]; const BoardTile* tile = &MONOPOLY_BOARD[p->position]; // Stats Window in center char buf[128]; renderer->draw_string_scaled(ix + 5, iy + 5, "Monopoly", 2); int content_y = iy + 25; snprintf(buf, sizeof(buf), "TURN: %s", p->name); renderer->draw_string_scaled(ix + 5, content_y, buf, 1); content_y += 12; snprintf(buf, sizeof(buf), "BAL: $%d", p->balance); renderer->draw_string_scaled(ix + 5, content_y, buf, 1); content_y += 12; snprintf(buf, sizeof(buf), "POS: %s", tile->name); renderer->draw_string_scaled(ix + 5, content_y, buf, 1); content_y += 15; // Draw action menu const char* actions[ACTION_COUNT]; if (!has_rolled) { actions[0] = "Roll Dice"; } else { actions[0] = "End Turn"; } actions[1] = "View Board"; for (int i = 0; i < ACTION_COUNT; ++i) { snprintf(buf, sizeof(buf), "%s%s", (i == selected_action) ? "> " : " ", actions[i]); renderer->draw_string_scaled(ix + 5, content_y, buf, 1); content_y += 12; } }