718 lines
24 KiB
C++
718 lines
24 KiB
C++
// ============================================================================
|
|
// 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 "BoardModalGame.h"
|
|
#include "ChanceModalGame.h"
|
|
#include "CommunityChestModalGame.h"
|
|
#include "DiceModalGame.h"
|
|
#include "ModalButtonHelper.h"
|
|
#include "MonopolyBoardRenderer.h"
|
|
#include "PaymentModalGame.h"
|
|
#include "PropertyModalGame.h"
|
|
#include "TurnModalGame.h"
|
|
#include "sprites.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.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() {
|
|
// Initialize regions for touch buttons
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
|
|
// 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 = -1;
|
|
srand(time(NULL));
|
|
shuffle_chance_deck();
|
|
shuffle_community_deck();
|
|
// renderer->set_font(&font_tama_mini02_obj);
|
|
if (active_modal) {
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
}
|
|
active_modal = new TurnModalGame(width, height, renderer, gui, input_manager,
|
|
&players[current_player_idx]);
|
|
// TODO: Reset all board state, property ownership, etc.
|
|
}
|
|
|
|
void MonopolyGame::shuffle_chance_deck() {
|
|
for (int i = 0; i < CHANCE_DECK_SIZE; i++) {
|
|
chance_deck[i] = i;
|
|
}
|
|
for (int i = CHANCE_DECK_SIZE - 1; i > 0; i--) {
|
|
int j = rand() % (i + 1);
|
|
int temp = chance_deck[i];
|
|
chance_deck[i] = chance_deck[j];
|
|
chance_deck[j] = temp;
|
|
}
|
|
current_chance_idx = 0;
|
|
}
|
|
|
|
void MonopolyGame::shuffle_community_deck() {
|
|
for (int i = 0; i < COMMUNITY_DECK_SIZE; i++) {
|
|
community_deck[i] = i;
|
|
}
|
|
for (int i = COMMUNITY_DECK_SIZE - 1; i > 0; i--) {
|
|
int j = rand() % (i + 1);
|
|
int temp = community_deck[i];
|
|
community_deck[i] = community_deck[j];
|
|
community_deck[j] = temp;
|
|
}
|
|
current_community_idx = 0;
|
|
}
|
|
|
|
// --- Handle input events (minimal: roll, buy, end turn) ---
|
|
bool MonopolyGame::update(const InputEvent &event) {
|
|
Player *p = &players[current_player_idx];
|
|
bool needs_redraw = false;
|
|
|
|
// Calculate available actions
|
|
int menu_count = 0;
|
|
if (!has_rolled) {
|
|
menu_count++; // Roll Dice
|
|
if (p->is_in_jail)
|
|
menu_count++; // Pay $50
|
|
} else {
|
|
menu_count++; // End Turn
|
|
}
|
|
menu_count++; // View Board
|
|
|
|
// 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 using custom
|
|
// get_type()
|
|
DiceModalGame *dice_modal =
|
|
(active_modal->get_type() == Game::Type::MONOPOLY_DICE)
|
|
? static_cast<DiceModalGame *>(active_modal)
|
|
: nullptr;
|
|
PropertyModalGame *prop_modal =
|
|
(active_modal->get_type() == Game::Type::MONOPOLY_PROPERTY)
|
|
? static_cast<PropertyModalGame *>(active_modal)
|
|
: nullptr;
|
|
BoardModalGame *board_modal =
|
|
(active_modal->get_type() == Game::Type::MONOPOLY_BOARD)
|
|
? static_cast<BoardModalGame *>(active_modal)
|
|
: nullptr;
|
|
ChanceModalGame *chance_modal =
|
|
(active_modal->get_type() == Game::Type::MONOPOLY_CHANCE)
|
|
? static_cast<ChanceModalGame *>(active_modal)
|
|
: nullptr;
|
|
CommunityChestModalGame *community_modal =
|
|
(active_modal->get_type() == Game::Type::MONOPOLY_COMMUNITY_CHEST)
|
|
? static_cast<CommunityChestModalGame *>(active_modal)
|
|
: nullptr;
|
|
TurnModalGame *turn_modal =
|
|
(active_modal->get_type() == Game::Type::MONOPOLY_TURN)
|
|
? static_cast<TurnModalGame *>(active_modal)
|
|
: nullptr;
|
|
PaymentModalGame *pay_modal =
|
|
(active_modal->get_type() == Game::Type::MONOPOLY_PAYMENT)
|
|
? static_cast<PaymentModalGame *>(active_modal)
|
|
: nullptr;
|
|
|
|
if (pay_modal && pay_modal->is_dismissed()) {
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
selected_action = -1;
|
|
needs_redraw = true;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
return needs_redraw;
|
|
}
|
|
|
|
if (dice_modal && dice_modal->is_dismissed()) {
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
needs_redraw = true;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
|
|
// Immediately check if we need to show a property modal
|
|
if (modal_property_index >= 0) {
|
|
bool is_owned = false;
|
|
const char *owner_name = nullptr;
|
|
int owner_id = -1;
|
|
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;
|
|
owner_id = i;
|
|
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,
|
|
owner_id, can_afford, players, players_count, current_player_idx);
|
|
modal_property_index = -1;
|
|
} else if (last_drawn_chance_idx >= 0) {
|
|
active_modal =
|
|
new ChanceModalGame(width, height, renderer, gui, input_manager,
|
|
&CHANCE_DECK[last_drawn_chance_idx], players,
|
|
players_count, p->position);
|
|
// We'll apply the effect when ChanceModal is dismissed
|
|
} else if (last_drawn_community_idx >= 0) {
|
|
active_modal = new CommunityChestModalGame(
|
|
width, height, renderer, gui, input_manager,
|
|
&COMMUNITY_DECK[last_drawn_community_idx], players, players_count,
|
|
p->position);
|
|
// We'll apply the effect when CommunityChestModal is dismissed
|
|
}
|
|
if (active_modal)
|
|
active_modal->init();
|
|
else
|
|
selected_action = -1;
|
|
return needs_redraw;
|
|
} else if (chance_modal && chance_modal->is_dismissed()) {
|
|
const ChanceCard *card = &CHANCE_DECK[last_drawn_chance_idx];
|
|
last_drawn_chance_idx = -1;
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
|
|
// Apply card effects
|
|
bool position_changed = false;
|
|
int old_pos = p->position;
|
|
|
|
switch (card->type) {
|
|
case CHANCE_EARN:
|
|
p->balance += card->value;
|
|
break;
|
|
case CHANCE_SPEND:
|
|
active_modal =
|
|
new PaymentModalGame(width, height, renderer, gui, input_manager, p,
|
|
nullptr, card->value, "CHANCE CARD");
|
|
if (active_modal)
|
|
active_modal->init();
|
|
break;
|
|
case CHANCE_ADVANCE: {
|
|
int target = card->value;
|
|
if (target == TARGET_NEAREST_UTILITY) {
|
|
target = (p->position + 1) % MONOPOLY_BOARD_SIZE;
|
|
while (MONOPOLY_BOARD[target].type != TILE_UTILITY) {
|
|
target = (target + 1) % MONOPOLY_BOARD_SIZE;
|
|
}
|
|
force_utility_10x = true;
|
|
} else if (target == TARGET_NEAREST_RAILROAD) {
|
|
target = (p->position + 1) % MONOPOLY_BOARD_SIZE;
|
|
while (MONOPOLY_BOARD[target].type != TILE_RAILROAD) {
|
|
target = (target + 1) % MONOPOLY_BOARD_SIZE;
|
|
}
|
|
rent_multiplier = 2;
|
|
}
|
|
p->position = target;
|
|
if (p->position < old_pos)
|
|
p->balance += 200;
|
|
position_changed = true;
|
|
break;
|
|
}
|
|
case CHANCE_BACK:
|
|
p->position = (p->position - card->value + MONOPOLY_BOARD_SIZE) %
|
|
MONOPOLY_BOARD_SIZE;
|
|
position_changed = true;
|
|
break;
|
|
case CHANCE_JAIL:
|
|
p->position = 10; // Jail
|
|
p->is_in_jail = true;
|
|
break;
|
|
case CHANCE_JAIL_FREE:
|
|
p->jail_free_cards++;
|
|
break;
|
|
case CHANCE_SPEND_EACH_PLAYER:
|
|
for (int i = 0; i < players_count; i++) {
|
|
if (i != (int)current_player_idx) {
|
|
p->balance -= card->value;
|
|
players[i].balance += card->value;
|
|
}
|
|
}
|
|
break;
|
|
case CHANCE_REPAIRS:
|
|
// For now, simplify or implement if houses are tracked
|
|
break;
|
|
}
|
|
|
|
needs_redraw = true;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
|
|
if (active_modal) {
|
|
active_modal->init();
|
|
} else if (position_changed) {
|
|
// If we moved, check if we landed on a property
|
|
const BoardTile *landed = &MONOPOLY_BOARD[p->position];
|
|
if (landed->type == TILE_PROPERTY || landed->type == TILE_RAILROAD ||
|
|
landed->type == TILE_UTILITY) {
|
|
bool is_owned = false;
|
|
const char *owner_name = nullptr;
|
|
int owner_id = -1;
|
|
for (int i = 0; i < players_count; ++i) {
|
|
for (int j = 0; j < players[i].property_count; ++j) {
|
|
if (players[i].properties_owned[j] == p->position) {
|
|
is_owned = true;
|
|
owner_name = players[i].name;
|
|
owner_id = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
bool can_afford = (p->balance >= landed->cost);
|
|
active_modal = new PropertyModalGame(
|
|
width, height, renderer, gui, input_manager, landed, is_owned,
|
|
owner_name, owner_id, can_afford, players, players_count,
|
|
current_player_idx);
|
|
if (active_modal)
|
|
active_modal->init();
|
|
}
|
|
}
|
|
} else if (community_modal && community_modal->is_dismissed()) {
|
|
const CommunityCard *card = &COMMUNITY_DECK[last_drawn_community_idx];
|
|
last_drawn_community_idx = -1;
|
|
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
|
|
bool position_changed = false;
|
|
int old_pos = p->position;
|
|
|
|
switch (card->type) {
|
|
case COMMUNITY_EARN:
|
|
p->balance += card->value;
|
|
break;
|
|
case COMMUNITY_SPEND:
|
|
active_modal =
|
|
new PaymentModalGame(width, height, renderer, gui, input_manager, p,
|
|
nullptr, card->value, "COMMUNITY CHEST");
|
|
if (active_modal)
|
|
active_modal->init();
|
|
break;
|
|
case COMMUNITY_ADVANCE:
|
|
p->position = card->value;
|
|
if (p->position < old_pos)
|
|
p->balance += 200;
|
|
position_changed = true;
|
|
break;
|
|
case COMMUNITY_JAIL:
|
|
p->position = 10;
|
|
p->is_in_jail = true;
|
|
break;
|
|
case COMMUNITY_JAIL_FREE:
|
|
p->jail_free_cards++;
|
|
break;
|
|
case COMMUNITY_EARN_EACH_PLAYER:
|
|
for (int i = 0; i < players_count; i++) {
|
|
if (i != (int)current_player_idx) {
|
|
p->balance += card->value;
|
|
players[i].balance -= card->value;
|
|
}
|
|
}
|
|
break;
|
|
case COMMUNITY_REPAIRS:
|
|
// p->balance -= (houses * card->value) + (hotels * card->value2);
|
|
break;
|
|
}
|
|
|
|
needs_redraw = true;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
|
|
if (active_modal) {
|
|
active_modal->init();
|
|
} else if (position_changed) {
|
|
const BoardTile *landed = &MONOPOLY_BOARD[p->position];
|
|
if (landed->type == TILE_PROPERTY || landed->type == TILE_RAILROAD ||
|
|
landed->type == TILE_UTILITY) {
|
|
bool is_owned = false;
|
|
const char *owner_name = nullptr;
|
|
int owner_id = -1;
|
|
for (int i = 0; i < players_count; ++i) {
|
|
for (int j = 0; j < players[i].property_count; ++j) {
|
|
if (players[i].properties_owned[j] == p->position) {
|
|
is_owned = true;
|
|
owner_name = players[i].name;
|
|
owner_id = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
bool can_afford = (p->balance >= landed->cost);
|
|
active_modal = new PropertyModalGame(
|
|
width, height, renderer, gui, input_manager, landed, is_owned,
|
|
owner_name, owner_id, can_afford, players, players_count,
|
|
current_player_idx);
|
|
if (active_modal)
|
|
active_modal->init();
|
|
}
|
|
}
|
|
} else if (prop_modal && prop_modal->is_dismissed()) {
|
|
bool wants_buy = prop_modal->wants_to_buy();
|
|
bool wants_rent = prop_modal->wants_to_pay_rent();
|
|
int owner_id_from_modal = prop_modal->get_owner_id();
|
|
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
|
|
if (wants_buy) {
|
|
const BoardTile *tile = &MONOPOLY_BOARD[p->position];
|
|
if (p->balance >= tile->cost) {
|
|
active_modal =
|
|
new PaymentModalGame(width, height, renderer, gui, input_manager,
|
|
p, nullptr, tile->cost, "BUY PROPERTY");
|
|
p->properties_owned[p->property_count++] = p->position;
|
|
}
|
|
} else if (wants_rent) {
|
|
const BoardTile *tile = &MONOPOLY_BOARD[p->position];
|
|
int rent = 0;
|
|
if (tile->type == TILE_PROPERTY) {
|
|
rent = tile->rent[0];
|
|
} else if (tile->type == TILE_RAILROAD) {
|
|
int rr_count = 0;
|
|
if (owner_id_from_modal != -1) {
|
|
for (int i = 0; i < players[owner_id_from_modal].property_count;
|
|
++i) {
|
|
if (MONOPOLY_BOARD[players[owner_id_from_modal]
|
|
.properties_owned[i]]
|
|
.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 (tile->type == TILE_UTILITY) {
|
|
int total_dice = last_dice1 + last_dice2;
|
|
int utility_count = 0;
|
|
if (owner_id_from_modal != -1) {
|
|
for (int i = 0; i < players[owner_id_from_modal].property_count;
|
|
++i) {
|
|
if (MONOPOLY_BOARD[players[owner_id_from_modal]
|
|
.properties_owned[i]]
|
|
.type == TILE_UTILITY) {
|
|
utility_count++;
|
|
}
|
|
}
|
|
}
|
|
if (force_utility_10x) {
|
|
rent = total_dice * 10;
|
|
} else {
|
|
rent = (utility_count == 2) ? (total_dice * 10) : (total_dice * 4);
|
|
}
|
|
}
|
|
|
|
rent *= rent_multiplier;
|
|
|
|
if (owner_id_from_modal != -1 &&
|
|
(int)current_player_idx != owner_id_from_modal) {
|
|
active_modal = new PaymentModalGame(
|
|
width, height, renderer, gui, input_manager, p,
|
|
&players[owner_id_from_modal], rent, "RENT");
|
|
}
|
|
}
|
|
// Reset multipliers
|
|
rent_multiplier = 1;
|
|
force_utility_10x = false;
|
|
|
|
needs_redraw = true;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
if (active_modal)
|
|
active_modal->init();
|
|
} else if (board_modal && board_modal->is_dismissed()) {
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
needs_redraw = true;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
} else if (turn_modal && turn_modal->is_dismissed()) {
|
|
delete active_modal;
|
|
active_modal = nullptr;
|
|
needs_redraw = true;
|
|
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
|
|
}
|
|
|
|
if (active_modal == nullptr && needs_redraw) {
|
|
selected_action = -1;
|
|
}
|
|
return needs_redraw;
|
|
}
|
|
|
|
switch (event.type) {
|
|
case INPUT_BUTTON_0:
|
|
selected_action = (selected_action + 1) % menu_count;
|
|
needs_redraw = true;
|
|
break;
|
|
case INPUT_BUTTON_1:
|
|
if (selected_action == -1)
|
|
return false;
|
|
|
|
if (p->is_in_jail && !has_rolled && selected_action == 1) {
|
|
active_modal =
|
|
new PaymentModalGame(width, height, renderer, gui, input_manager, p,
|
|
nullptr, 50, "JAIL BAIL");
|
|
if (active_modal)
|
|
active_modal->init();
|
|
p->is_in_jail = false;
|
|
p->jail_turns = 0;
|
|
selected_action = -1;
|
|
needs_redraw = true;
|
|
return true;
|
|
}
|
|
if (active_modal)
|
|
delete active_modal;
|
|
if (selected_action == (menu_count - 1)) {
|
|
active_modal =
|
|
new BoardModalGame(width, height, renderer, gui, input_manager,
|
|
players, players_count, current_player_idx);
|
|
needs_redraw = true;
|
|
} else if (!has_rolled) {
|
|
roll_dice_logic:
|
|
int d1 = (rand() % 6) + 1;
|
|
int d2 = (rand() % 6) + 1;
|
|
bool is_db = (d1 == d2);
|
|
int old_pos = p->position;
|
|
if (p->is_in_jail) {
|
|
if (is_db) {
|
|
p->is_in_jail = false;
|
|
p->jail_turns = 0;
|
|
} else {
|
|
p->jail_turns++;
|
|
if (p->jail_turns >= 3) {
|
|
active_modal = new PaymentModalGame(width, height, renderer, gui,
|
|
input_manager, p, nullptr, 50,
|
|
"JAIL BAIL (FORCED)");
|
|
if (active_modal)
|
|
active_modal->init();
|
|
p->is_in_jail = false;
|
|
p->jail_turns = 0;
|
|
} else {
|
|
has_rolled = true;
|
|
last_dice1 = d1;
|
|
last_dice2 = d2;
|
|
active_modal = new DiceModalGame(
|
|
width, height, renderer, gui, input_manager, d1, d2,
|
|
&MONOPOLY_BOARD[old_pos], &MONOPOLY_BOARD[old_pos], players,
|
|
players_count);
|
|
needs_redraw = true;
|
|
return true;
|
|
}
|
|
}
|
|
} else if (is_db) {
|
|
double_rolls++;
|
|
if (double_rolls >= 3) {
|
|
p->position = 10;
|
|
p->is_in_jail = true;
|
|
p->jail_turns = 0;
|
|
has_rolled = true;
|
|
double_rolls = 0;
|
|
last_dice1 = d1;
|
|
last_dice2 = d2;
|
|
active_modal =
|
|
new DiceModalGame(width, height, renderer, gui, input_manager, d1,
|
|
d2, &MONOPOLY_BOARD[old_pos],
|
|
&MONOPOLY_BOARD[10], players, players_count);
|
|
needs_redraw = true;
|
|
return true;
|
|
}
|
|
} else {
|
|
double_rolls = 0;
|
|
}
|
|
|
|
int total = d1 + d2;
|
|
p->position = (p->position + total) % MONOPOLY_BOARD_SIZE;
|
|
if (p->position < old_pos)
|
|
p->balance += 200;
|
|
has_rolled = !is_db;
|
|
last_dice1 = d1;
|
|
last_dice2 = d2;
|
|
active_modal = new DiceModalGame(
|
|
width, height, renderer, gui, input_manager, d1, d2,
|
|
&MONOPOLY_BOARD[old_pos], &MONOPOLY_BOARD[p->position], players,
|
|
players_count);
|
|
|
|
const BoardTile *lnd = &MONOPOLY_BOARD[p->position];
|
|
if (lnd->type == TILE_GO_TO_JAIL) {
|
|
p->position = 10;
|
|
p->is_in_jail = true;
|
|
p->jail_turns = 0;
|
|
has_rolled = true;
|
|
double_rolls = 0;
|
|
} else if (lnd->type == TILE_PROPERTY || lnd->type == TILE_RAILROAD ||
|
|
lnd->type == TILE_UTILITY) {
|
|
modal_property_index = p->position;
|
|
} else if (lnd->type == TILE_CHANCE) {
|
|
last_drawn_chance_idx = chance_deck[current_chance_idx];
|
|
current_chance_idx = (current_chance_idx + 1) % CHANCE_DECK_SIZE;
|
|
if (current_chance_idx == 0)
|
|
shuffle_chance_deck();
|
|
} else if (lnd->type == TILE_COMMUNITY_CHEST) {
|
|
last_drawn_community_idx = community_deck[current_community_idx];
|
|
current_community_idx =
|
|
(current_community_idx + 1) % COMMUNITY_DECK_SIZE;
|
|
if (current_community_idx == 0)
|
|
shuffle_community_deck();
|
|
} else if (lnd->type == TILE_TAX) {
|
|
active_modal =
|
|
new PaymentModalGame(width, height, renderer, gui, input_manager, p,
|
|
nullptr, lnd->cost, "TAXES");
|
|
if (active_modal)
|
|
active_modal->init();
|
|
}
|
|
needs_redraw = true;
|
|
} else {
|
|
current_player_idx = (current_player_idx + 1) % players_count;
|
|
has_rolled = false;
|
|
double_rolls = 0;
|
|
just_sent_to_jail = false;
|
|
selected_action = -1;
|
|
active_modal =
|
|
new TurnModalGame(width, height, renderer, gui, input_manager,
|
|
&players[current_player_idx]);
|
|
needs_redraw = true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
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();
|
|
|
|
Player *p = &players[current_player_idx];
|
|
const BoardTile *tile = &MONOPOLY_BOARD[p->position];
|
|
|
|
// --- Draw Board Perimeter ---
|
|
MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players,
|
|
players_count, p->position);
|
|
|
|
// --- 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;
|
|
|
|
// --- Inner Dashboard UI ---
|
|
// Window Border
|
|
renderer->draw_rectangle(ix, iy, iw, ih, true, 2);
|
|
renderer->draw_rectangle(ix + 3, iy + 3, iw - 6, ih - 6, true, 1);
|
|
|
|
// Header Title Bar (Player Name)
|
|
char buf[128];
|
|
renderer->draw_filled_rectangle(ix + 4, iy + 4, iw - 8, 35, true, 1);
|
|
renderer->set_text_color(false); // White text
|
|
snprintf(buf, sizeof(buf), "%s'S TURN", p->name);
|
|
renderer->draw_string_scaled(ix + (iw - (int)strlen(buf) * 12) / 2, iy + 12,
|
|
buf, 2);
|
|
renderer->set_text_color(true);
|
|
|
|
renderer->draw_string_scaled(ix + (iw - 8 * 18) / 2, iy + ih - 35, "Monopoly",
|
|
3);
|
|
|
|
int content_y = iy + 50;
|
|
|
|
snprintf(buf, sizeof(buf), "BALANCE: $%d", p->balance);
|
|
renderer->draw_string_scaled(ix + 10, content_y, buf, 2);
|
|
content_y += 25;
|
|
|
|
snprintf(buf, sizeof(buf), "TILE: %s", tile->name);
|
|
renderer->draw_string_scaled(ix + 10, content_y, buf, 1);
|
|
content_y += 20;
|
|
|
|
// Draw special tile sprite
|
|
const unsigned char *sprite = nullptr;
|
|
if (tile->type == TILE_COMMUNITY_CHEST)
|
|
sprite = epd_bitmap_CommunityChest;
|
|
else if (tile->type == TILE_CHANCE)
|
|
sprite = epd_bitmap_Chance;
|
|
else if (tile->type == TILE_FREE_PARKING)
|
|
sprite = epd_bitmap_FreeParking;
|
|
else if (tile->type == TILE_GO_TO_JAIL)
|
|
sprite = epd_bitmap_GoToJail;
|
|
else if (tile->type == TILE_UTILITY) {
|
|
if (strstr(tile->name, "Electric"))
|
|
sprite = epd_bitmap_ElectricCompany;
|
|
else if (strstr(tile->name, "Water"))
|
|
sprite = epd_bitmap_WaterWorks;
|
|
}
|
|
|
|
if (sprite) {
|
|
// Draw at bottom right of dashboard
|
|
renderer->draw_bitmap(sprite, ix + iw - 105, iy + ih - 105, 100, 100, true);
|
|
}
|
|
|
|
// Separator line
|
|
renderer->draw_line(ix + 10, content_y, ix + iw - 10, content_y, true);
|
|
content_y += 15;
|
|
// Draw action menu
|
|
const char *actions[3];
|
|
int menu_count = 0;
|
|
if (!has_rolled) {
|
|
actions[menu_count++] = "Roll Dice";
|
|
if (p->is_in_jail)
|
|
actions[menu_count++] = "Pay $50";
|
|
} else {
|
|
actions[menu_count++] = "End Turn";
|
|
}
|
|
actions[menu_count++] = "View Board";
|
|
|
|
for (int i = 0; i < menu_count; ++i) {
|
|
snprintf(buf, sizeof(buf), "%s%s", (i == selected_action) ? "> " : " ",
|
|
actions[i]);
|
|
renderer->draw_string_scaled(ix + 15, content_y, buf, 2);
|
|
content_y += 25;
|
|
}
|
|
|
|
ModalButtonHelper::draw_virtual_buttons(renderer, input_manager);
|
|
}
|