// ============================================================================ // 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" // --- 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; // If modal is dismissed, delete and return control // Use dynamic_cast to check for modal type and dismissal auto dice_modal = dynamic_cast(active_modal); auto prop_modal = dynamic_cast(active_modal); if ((dice_modal && dice_modal->is_dismissed()) || (prop_modal && prop_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: // Roll if (!has_rolled && !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); // 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; // Queue property modal after dice modal is dismissed } // TODO: Handle doubles, jail, landing effects } break; case 1: // Buy if (has_rolled) { const BoardTile* tile = &MONOPOLY_BOARD[p->position]; if ((tile->type == TILE_PROPERTY || tile->type == TILE_RAILROAD || tile->type == TILE_UTILITY) && p->balance >= tile->cost) { bool owned = false; for (int i = 0; i < p->property_count; ++i) { if (p->properties_owned[i] == p->position) owned = true; } if (!owned) { p->balance -= tile->cost; p->properties_owned[p->property_count++] = p->position; needs_redraw = true; } } // TODO: Check for ownership by other players } break; case 2: // End Turn if (has_rolled) { current_player_idx = (current_player_idx + 1) % players_count; has_rolled = false; double_rolls = 0; just_sent_to_jail = false; 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) { active_modal = new PropertyModalGame(width, height, renderer, gui, input_manager, &MONOPOLY_BOARD[modal_property_index]); 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; } Player* p = &players[current_player_idx]; const BoardTile* tile = &MONOPOLY_BOARD[p->position]; // Title renderer->draw_string_scaled(10, 10, "Monopoly", 3); // --- Player Stats (Right Side) --- int stats_x = width - 200; int y = 40 + 15 * current_player_idx; char buf[128]; // make a window showing player stats LowLevelWindow* stats_win = gui->draw_new_window(stats_x - 10, y - 10 , 190, 120, p->name); y += 20; renderer->draw_string_scaled(stats_x, y, "Location:", 1); renderer->draw_string_scaled(stats_x, y + 10, tile->name, 2); y += 30; // Money snprintf(buf, sizeof(buf), "$%d", p->balance); renderer->draw_string_scaled(stats_x, y, "Money:", 1); renderer->draw_string_scaled(stats_x, y + 10, buf, 2); y += 30; // Properties int prop_count = 0; for (int i = 0; i < p->property_count; ++i) { int prop_idx = p->properties_owned[i]; if (prop_idx >= 0 && MONOPOLY_BOARD[prop_idx].type == TILE_PROPERTY) prop_count++; } snprintf(buf, sizeof(buf), "Properties: %d", prop_count); renderer->draw_string_scaled(stats_x, y, buf, 1); y += 10; // Monopoly count int monopoly_count = 0; // For each group, check if player owns all properties in group for (int group = 1; group <= 8; ++group) { int group_total = 0, group_owned = 0; for (int i = 0; i < BOARD_SIZE; ++i) { if (MONOPOLY_BOARD[i].type == TILE_PROPERTY && MONOPOLY_BOARD[i].group[0] == group) { group_total++; for (int j = 0; j < p->property_count; ++j) { if (p->properties_owned[j] == i) group_owned++; } } } if (group_total > 0 && group_total == group_owned) monopoly_count++; } snprintf(buf, sizeof(buf), "Monopolies: %d", monopoly_count); renderer->draw_string_scaled(stats_x, y, buf, 1); // Draw action menu (highlight selected) const char* actions[ACTION_COUNT] = {"Roll Dice", "Buy Property", "End Turn"}; for (int i = 0; i < ACTION_COUNT; ++i) { int y = height - 80 + i * 20; snprintf(buf, sizeof(buf), "%s%s", (i == selected_action) ? "> " : " ", actions[i]); renderer->draw_string_scaled(10, y, buf, 2); } // TODO: Draw board, all players, property ownership, jail, chance, etc. // TODO: Add win/lose/game over conditions // TODO: Add touch support, more UI, etc. }