Fix build error: Rename BOARD_SIZE to MONOPOLY_BOARD_SIZE to avoid macro collision

This commit is contained in:
Adolfo Reyna
2026-02-17 22:11:21 -05:00
parent b0ca1f1a55
commit b01cd652a0
5 changed files with 1768 additions and 1465 deletions

View File

@@ -1,18 +1,18 @@
// DiceModalGame.h // DiceModalGame.h
#pragma once #pragma once
#include "../../lib/game.h"
#include "../../display/low_level_render.h"
#include "../../display/low_level_gui.h" #include "../../display/low_level_gui.h"
#include "input_manager.h" #include "../../display/low_level_render.h"
#include "MonopolyBoardRenderer.h" #include "../../lib/game.h"
#include "ModalButtonHelper.h" #include "ModalButtonHelper.h"
#include <stdlib.h> #include "MonopolyBoardRenderer.h"
#include "input_manager.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
class DiceModalGame : public Game { class DiceModalGame : public Game {
int dice1, dice2; int dice1, dice2;
const BoardTile *from_tile, *to_tile; const BoardTile *from_tile, *to_tile;
Player* players; Player *players;
int players_count; int players_count;
bool dismissed; bool dismissed;
@@ -38,10 +38,13 @@ class DiceModalGame : public Game {
int b = 3 * size / 4; int b = 3 * size / 4;
auto draw_dot = [&](int dx, int dy) { 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); 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 % 2 == 1)
draw_dot(m, m); // Center dot for 1, 3, 5
if (value > 1) { if (value > 1) {
draw_dot(l, t); draw_dot(l, t);
draw_dot(r, b); draw_dot(r, b);
@@ -57,29 +60,36 @@ class DiceModalGame : public Game {
} }
public: 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) DiceModalGame(uint16_t width, uint16_t height, LowLevelRenderer *renderer,
: Game(width, height, renderer, gui, input_manager), dice1(d1), dice2(d2), from_tile(from), to_tile(to), players(p), players_count(count), dismissed(false) { 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) {
// Find from_pos // Find from_pos
from_pos = 0; from_pos = 0;
for(int i=0; i<40; i++) { for (int i = 0; i < 40; i++) {
if(&MONOPOLY_BOARD[i] == from_tile) { if (&MONOPOLY_BOARD[i] == from_tile) {
from_pos = i; from_pos = i;
break; break;
} }
} }
correct_destination = (from_pos + dice1 + dice2) % BOARD_SIZE; correct_destination = (from_pos + dice1 + dice2) % MONOPOLY_BOARD_SIZE;
selected_choice = -1; selected_choice = -1;
show_error = false; show_error = false;
for(int i=0; i<3; i++) option_visible[i] = true; for (int i = 0; i < 3; i++)
option_visible[i] = true;
// Generate fake options // Generate fake options
int fake1 = (from_pos + (rand() % 11 + 2)) % BOARD_SIZE; int fake1 = (from_pos + (rand() % 11 + 2)) % MONOPOLY_BOARD_SIZE;
if (fake1 == correct_destination) fake1 = (fake1 + 1) % BOARD_SIZE; if (fake1 == correct_destination)
fake1 = (fake1 + 1) % MONOPOLY_BOARD_SIZE;
int fake2 = (from_pos + (rand() % 11 + 2)) % BOARD_SIZE; int fake2 = (from_pos + (rand() % 11 + 2)) % MONOPOLY_BOARD_SIZE;
while (fake2 == correct_destination || fake2 == fake1) { while (fake2 == correct_destination || fake2 == fake1) {
fake2 = (from_pos + (rand() % 11 + 2)) % BOARD_SIZE; fake2 = (from_pos + (rand() % 11 + 2)) % MONOPOLY_BOARD_SIZE;
} }
int rand_pos = rand() % 3; int rand_pos = rand() % 3;
@@ -102,24 +112,27 @@ public:
dismissed = false; dismissed = false;
selected_choice = -1; selected_choice = -1;
show_error = false; show_error = false;
for(int i=0; i<3; i++) option_visible[i] = true; for (int i = 0; i < 3; i++)
option_visible[i] = true;
ModalButtonHelper::set_monopoly_regions(input_manager, width, height); ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
} }
Type get_type() const override { return Type::MONOPOLY_DICE; } Type get_type() const override { return Type::MONOPOLY_DICE; }
bool update(const InputEvent& event) override { bool update(const InputEvent &event) override {
if (event.type == INPUT_BUTTON_0) { // Select if (event.type == INPUT_BUTTON_0) { // Select
int start_choice = selected_choice; int start_choice = selected_choice;
do { do {
selected_choice = (selected_choice + 1) % 3; selected_choice = (selected_choice + 1) % 3;
} while (!option_visible[selected_choice] && selected_choice != start_choice); } while (!option_visible[selected_choice] &&
selected_choice != start_choice);
show_error = false; show_error = false;
return true; return true;
} }
if (event.type == INPUT_BUTTON_1) { if (event.type == INPUT_BUTTON_1) {
if (selected_choice == -1 || !option_visible[selected_choice]) return false; if (selected_choice == -1 || !option_visible[selected_choice])
return false;
if (options[selected_choice] == correct_destination) { if (options[selected_choice] == correct_destination) {
dismissed = true; dismissed = true;
@@ -137,7 +150,9 @@ public:
renderer->clear_buffer(); renderer->clear_buffer();
// Draw the restricted board perimeter // Draw the restricted board perimeter
MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players, players_count, -1, -1, from_pos, (from_pos + 12) % BOARD_SIZE); MonopolyBoardRenderer::draw_board_perimeter(
renderer, width, height, players, players_count, -1, -1, from_pos,
(from_pos + 12) % MONOPOLY_BOARD_SIZE);
// --- Inner UI (Center Area) --- // --- Inner UI (Center Area) ---
int cw = width / 7; int cw = width / 7;
@@ -155,7 +170,9 @@ public:
// Header // Header
renderer->draw_filled_rectangle(ix + 4, iy + 4, iw - 8, 30, true, 1); renderer->draw_filled_rectangle(ix + 4, iy + 4, iw - 8, 30, true, 1);
renderer->set_text_color(false); renderer->set_text_color(false);
renderer->draw_string_scaled(ix + (iw - (int)strlen("DICE CHALLENGE") * 12) / 2, iy + 10, "DICE CHALLENGE", 2); renderer->draw_string_scaled(
ix + (iw - (int)strlen("DICE CHALLENGE") * 12) / 2, iy + 10,
"DICE CHALLENGE", 2);
renderer->set_text_color(true); renderer->set_text_color(true);
// Dice // Dice
@@ -176,20 +193,27 @@ public:
continue; continue;
} }
char opt_buf[64]; char opt_buf[64];
snprintf(opt_buf, sizeof(opt_buf), "%s %d: %s", (selected_choice == i ? ">" : " "), i+1, MONOPOLY_BOARD[options[i]].name); snprintf(opt_buf, sizeof(opt_buf), "%s %d: %s",
(selected_choice == i ? ">" : " "), i + 1,
MONOPOLY_BOARD[options[i]].name);
if (selected_choice == i) renderer->draw_filled_rectangle(ix + 15, opt_y - 2, iw - 30, 22, true, 1); if (selected_choice == i)
if (selected_choice == i) renderer->set_text_color(false); renderer->draw_filled_rectangle(ix + 15, opt_y - 2, iw - 30, 22, true,
1);
if (selected_choice == i)
renderer->set_text_color(false);
// Truncate name if too long // Truncate name if too long
if (strlen(opt_buf) > 30) opt_buf[30] = '\0'; if (strlen(opt_buf) > 30)
opt_buf[30] = '\0';
renderer->draw_string_scaled(ix + 20, opt_y, opt_buf, 2); renderer->draw_string_scaled(ix + 20, opt_y, opt_buf, 2);
renderer->set_text_color(true); renderer->set_text_color(true);
opt_y += 25; opt_y += 25;
} }
if (show_error) { if (show_error) {
renderer->draw_string_scaled(ix + (iw - 10 * 12) / 2, iy + ih - 30, "TRY AGAIN!", 2); renderer->draw_string_scaled(ix + (iw - 10 * 12) / 2, iy + ih - 30,
"TRY AGAIN!", 2);
} }
ModalButtonHelper::draw_virtual_buttons(renderer, input_manager); ModalButtonHelper::draw_virtual_buttons(renderer, input_manager);

View File

@@ -6,8 +6,12 @@
class MonopolyBoardRenderer { class MonopolyBoardRenderer {
public: public:
static void draw_tile(LowLevelRenderer* renderer, int x, int y, int w, int h, int index, bool is_corner, Player* players, int players_count, int orientation = 0, int currentPlayerPos = -1, int observer_idx = -1) { static void draw_tile(LowLevelRenderer *renderer, int x, int y, int w, int h,
if (index < 0 || index >= BOARD_SIZE) return; int index, bool is_corner, Player *players,
int players_count, int orientation = 0,
int currentPlayerPos = -1, int observer_idx = -1) {
if (index < 0 || index >= MONOPOLY_BOARD_SIZE)
return;
// Find owner // Find owner
int owner_id = -1; int owner_id = -1;
@@ -18,7 +22,8 @@ public:
break; break;
} }
} }
if (owner_id != -1) break; if (owner_id != -1)
break;
} }
bool isInverted = false; bool isInverted = false;
@@ -35,7 +40,7 @@ public:
renderer->draw_rectangle(x, y, w, h, true, 1); renderer->draw_rectangle(x, y, w, h, true, 1);
} }
const BoardTile& tile = MONOPOLY_BOARD[index]; const BoardTile &tile = MONOPOLY_BOARD[index];
int content_x = x, content_y = y, content_w = w, content_h = h; int content_x = x, content_y = y, content_w = w, content_h = h;
if (!is_corner && tile.type == TILE_PROPERTY) { if (!is_corner && tile.type == TILE_PROPERTY) {
@@ -44,16 +49,20 @@ public:
if (orientation == 0) { // Bottom row (Bar on top) if (orientation == 0) { // Bottom row (Bar on top)
bh = bar_size; bh = bar_size;
content_y += bar_size; content_h -= bar_size; content_y += bar_size;
content_h -= bar_size;
} else if (orientation == 1) { // Left column (Bar on right) } else if (orientation == 1) { // Left column (Bar on right)
bx = x + w - bar_size; bw = bar_size; bx = x + w - bar_size;
bw = bar_size;
content_w -= bar_size; content_w -= bar_size;
} else if (orientation == 2) { // Top row (Bar on bottom) } else if (orientation == 2) { // Top row (Bar on bottom)
by = y + h - bar_size; bh = bar_size; by = y + h - bar_size;
bh = bar_size;
content_h -= bar_size; content_h -= bar_size;
} else if (orientation == 3) { // Right column (Bar on left) } else if (orientation == 3) { // Right column (Bar on left)
bw = bar_size; bw = bar_size;
content_x += bar_size; content_w -= bar_size; content_x += bar_size;
content_w -= bar_size;
} }
if (isInverted) { if (isInverted) {
@@ -66,48 +75,61 @@ public:
} }
// Group number // Group number
char gbuf[2] = { (char)('0' + tile.group[0]), '\0' }; char gbuf[2] = {(char)('0' + tile.group[0]), '\0'};
renderer->draw_string_scaled(bx + (bw - 6) / 2, by + (bh - 8) / 2, gbuf, 1); renderer->draw_string_scaled(bx + (bw - 6) / 2, by + (bh - 8) / 2, gbuf,
1);
if (isInverted) renderer->set_text_color(false); if (isInverted)
else renderer->set_text_color(true); renderer->set_text_color(false);
else
renderer->set_text_color(true);
} }
char short_name[10] = {0}; char short_name[10] = {0};
int s_ptr = 0; int s_ptr = 0;
bool isCurrentPos = (index == currentPlayerPos && observer_idx != -1); bool isCurrentPos = (index == currentPlayerPos && observer_idx != -1);
if (isCurrentPos) short_name[s_ptr++] = '-'; if (isCurrentPos)
short_name[s_ptr++] = '-';
// Add * if owned by someone else // Add * if owned by someone else
if (owner_id != -1 && observer_idx != -1 && owner_id != observer_idx) { if (owner_id != -1 && observer_idx != -1 && owner_id != observer_idx) {
short_name[s_ptr++] = '*'; short_name[s_ptr++] = '*';
} }
const char* full_name = tile.name; const char *full_name = tile.name;
if (is_corner) { if (is_corner) {
int len = strlen(full_name); int len = strlen(full_name);
if (len > 3) len = 3; if (len > 3)
for(int i=0; i<len; i++) short_name[s_ptr++] = full_name[i]; len = 3;
for (int i = 0; i < len; i++)
short_name[s_ptr++] = full_name[i];
} else { } else {
short_name[s_ptr++] = full_name[0]; short_name[s_ptr++] = full_name[0];
const char* space = strchr(full_name, ' '); const char *space = strchr(full_name, ' ');
if (space && space[1] != '\0') short_name[s_ptr++] = space[1]; if (space && space[1] != '\0')
short_name[s_ptr++] = space[1];
} }
if (isCurrentPos) short_name[s_ptr++] = '-'; if (isCurrentPos)
short_name[s_ptr++] = '-';
short_name[s_ptr] = '\0'; short_name[s_ptr] = '\0';
for (int i = 0; short_name[i]; i++) if(short_name[i] >= 'a' && short_name[i] <= 'z') short_name[i] -= 32; for (int i = 0; short_name[i]; i++)
if (short_name[i] >= 'a' && short_name[i] <= 'z')
short_name[i] -= 32;
renderer->draw_string_scaled(content_x + (content_w - (int)strlen(short_name) * 6) / 2, content_y + (content_h - 8) / 2, short_name, 1); renderer->draw_string_scaled(
content_x + (content_w - (int)strlen(short_name) * 6) / 2,
content_y + (content_h - 8) / 2, short_name, 1);
// Draw player markers // Draw player markers
int p_count = 0; int p_count = 0;
for (int i = 0; i < players_count; ++i) { for (int i = 0; i < players_count; ++i) {
if (players[i].position == index) { if (players[i].position == index) {
char mark[2] = { (players[i].token ? players[i].token[0] : 'P'), '\0' }; char mark[2] = {(players[i].token ? players[i].token[0] : 'P'), '\0'};
renderer->draw_string_scaled(content_x + 2 + (p_count * 8), content_y + 2, mark, 1); renderer->draw_string_scaled(content_x + 2 + (p_count * 8),
content_y + 2, mark, 1);
p_count++; p_count++;
} }
} }
@@ -117,14 +139,19 @@ public:
} }
} }
static void draw_board_perimeter(LowLevelRenderer* renderer, int width, int height, Player* players, int players_count, int currentPlayerPos = -1, int observer_idx = -1, int limit_start = -1, int limit_end = -1) { static void draw_board_perimeter(LowLevelRenderer *renderer, int width,
int height, Player *players,
int players_count, int currentPlayerPos = -1,
int observer_idx = -1, int limit_start = -1,
int limit_end = -1) {
int cw = width / 7; // Corner width int cw = width / 7; // Corner width
int ch = height / 7; // Corner height int ch = height / 7; // Corner height
int rw = (width - 2 * cw) / 9; // Regular tile width int rw = (width - 2 * cw) / 9; // Regular tile width
int rh = (height - 2 * ch) / 9; // Regular tile height int rh = (height - 2 * ch) / 9; // Regular tile height
auto should_draw = [&](int index) { auto should_draw = [&](int index) {
if (limit_start == -1 || limit_end == -1) return true; if (limit_start == -1 || limit_end == -1)
return true;
if (limit_start <= limit_end) { if (limit_start <= limit_end) {
return index >= limit_start && index <= limit_end; return index >= limit_start && index <= limit_end;
} else { } else {
@@ -133,27 +160,43 @@ public:
}; };
// --- Bottom Row: 0 to 10 (Right to Left) --- // --- Bottom Row: 0 to 10 (Right to Left) ---
if (should_draw(0)) draw_tile(renderer, width - cw, height - ch, cw, ch, 0, true, players, players_count, 0, currentPlayerPos, observer_idx); // GO if (should_draw(0))
draw_tile(renderer, width - cw, height - ch, cw, ch, 0, true, players,
players_count, 0, currentPlayerPos, observer_idx); // GO
for (int i = 1; i < 10; ++i) { for (int i = 1; i < 10; ++i) {
if (should_draw(i)) draw_tile(renderer, width - cw - i * rw, height - ch, rw, ch, i, false, players, players_count, 0, currentPlayerPos, observer_idx); if (should_draw(i))
draw_tile(renderer, width - cw - i * rw, height - ch, rw, ch, i, false,
players, players_count, 0, currentPlayerPos, observer_idx);
} }
if (should_draw(10)) draw_tile(renderer, 0, height - ch, cw, ch, 10, true, players, players_count, 1, currentPlayerPos, observer_idx); // JAIL if (should_draw(10))
draw_tile(renderer, 0, height - ch, cw, ch, 10, true, players,
players_count, 1, currentPlayerPos, observer_idx); // JAIL
// --- Left Column: 11 to 19 (Bottom to Top) --- // --- Left Column: 11 to 19 (Bottom to Top) ---
for (int i = 11; i < 20; ++i) { for (int i = 11; i < 20; ++i) {
if (should_draw(i)) draw_tile(renderer, 0, height - ch - (i - 10) * rh, cw, rh, i, false, players, players_count, 1, currentPlayerPos, observer_idx); if (should_draw(i))
draw_tile(renderer, 0, height - ch - (i - 10) * rh, cw, rh, i, false,
players, players_count, 1, currentPlayerPos, observer_idx);
} }
// --- Top Row: 20 to 30 (Left to Right) --- // --- Top Row: 20 to 30 (Left to Right) ---
if (should_draw(20)) draw_tile(renderer, 0, 0, cw, ch, 20, true, players, players_count, 2, currentPlayerPos, observer_idx); // FREE PARKING if (should_draw(20))
draw_tile(renderer, 0, 0, cw, ch, 20, true, players, players_count, 2,
currentPlayerPos, observer_idx); // FREE PARKING
for (int i = 21; i < 30; ++i) { for (int i = 21; i < 30; ++i) {
if (should_draw(i)) draw_tile(renderer, cw + (i - 21) * rw, 0, rw, ch, i, false, players, players_count, 2, currentPlayerPos, observer_idx); if (should_draw(i))
draw_tile(renderer, cw + (i - 21) * rw, 0, rw, ch, i, false, players,
players_count, 2, currentPlayerPos, observer_idx);
} }
if (should_draw(30)) draw_tile(renderer, width - cw, 0, cw, ch, 30, true, players, players_count, 3, currentPlayerPos, observer_idx); // GO TO JAIL if (should_draw(30))
draw_tile(renderer, width - cw, 0, cw, ch, 30, true, players,
players_count, 3, currentPlayerPos, observer_idx); // GO TO JAIL
// --- Right Column: 31 to 39 (Top to Bottom) --- // --- Right Column: 31 to 39 (Top to Bottom) ---
for (int i = 31; i < 40; ++i) { for (int i = 31; i < 40; ++i) {
if (should_draw(i)) draw_tile(renderer, width - cw, ch + (i - 31) * rh, cw, rh, i, false, players, players_count, 3, currentPlayerPos, observer_idx); if (should_draw(i))
draw_tile(renderer, width - cw, ch + (i - 31) * rh, cw, rh, i, false,
players, players_count, 3, currentPlayerPos, observer_idx);
} }
} }
}; };

View File

@@ -1,10 +1,10 @@
#include "chance.h"
#include "community_chest.h"
#include "monopoly_board.h"
#include "player.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "monopoly_board.h"
#include "player.h"
#include "chance.h"
#include "community_chest.h"
// Forward Declarations // Forward Declarations
void handle_roll(Player *p, bool *has_rolled, int *double_rolls); void handle_roll(Player *p, bool *has_rolled, int *double_rolls);
@@ -13,9 +13,10 @@ void handle_trade(Player *p);
void handle_build(Player *p); void handle_build(Player *p);
void process_landing(Player *p); void process_landing(Player *p);
void handle_property_landing(Player *p, const BoardTile *tile); void handle_property_landing(Player *p, const BoardTile *tile);
void handle_chance(Player* p); void handle_chance(Player *p);
void find_properties_on_group_from_position(int position, int positions_found[4], int *count); void find_properties_on_group_from_position(int position,
void handle_community_chest(Player* p); int positions_found[4], int *count);
void handle_community_chest(Player *p);
void handle_jail_options(Player *p); void handle_jail_options(Player *p);
bool attempt_jail_escape(Player *p); bool attempt_jail_escape(Player *p);
@@ -26,8 +27,7 @@ int players_count = 2;
int current_player_idx = 0; int current_player_idx = 0;
bool just_sent_to_jail = false; // Flag to end turn when sent to jail bool just_sent_to_jail = false; // Flag to end turn when sent to jail
int main() int main() {
{
srand(time(NULL)); srand(time(NULL));
// Initialize hardcoded players // Initialize hardcoded players
@@ -44,18 +44,16 @@ int main()
bool has_rolled = false; // Turn state tracker bool has_rolled = false; // Turn state tracker
int double_rolls = 0; int double_rolls = 0;
current_player_idx = 0; current_player_idx = 0;
while (running) while (running) {
{
Player *p = &players[current_player_idx]; Player *p = &players[current_player_idx];
printf("\n╔═════════════════════════════════════════╗\n"); printf("\n╔═════════════════════════════════════════╗\n");
printf("║ %s's Turn (%s)\n", p->name, p->token); printf("║ %s's Turn (%s)\n", p->name, p->token);
printf("║ 💰 Balance: $%d | 📍 %s\n", p->balance, MONOPOLY_BOARD[p->position].name); printf("║ 💰 Balance: $%d | 📍 %s\n", p->balance,
MONOPOLY_BOARD[p->position].name);
printf("╚═════════════════════════════════════════╝\n\n"); printf("╚═════════════════════════════════════════╝\n\n");
// Handle jail status at start of turn // Handle jail status at start of turn
if (p->is_in_jail) if (p->is_in_jail) {
{ if (just_sent_to_jail) {
if (just_sent_to_jail)
{
// Player was just sent to jail this turn, end their turn // Player was just sent to jail this turn, end their turn
printf("\n🚨 You have been sent to Jail! Your turn ends.\n"); printf("\n🚨 You have been sent to Jail! Your turn ends.\n");
current_player_idx = (current_player_idx + 1) % players_count; current_player_idx = (current_player_idx + 1) % players_count;
@@ -68,13 +66,10 @@ int main()
printf(" Turns in jail: %d/3\n", p->jail_turns); printf(" Turns in jail: %d/3\n", p->jail_turns);
handle_jail_options(p); handle_jail_options(p);
if (!p->is_in_jail) if (!p->is_in_jail) {
{
// Player escaped jail, now they can roll // Player escaped jail, now they can roll
printf("\n📋 %s escaped jail!\n\n", p->name); printf("\n📋 %s escaped jail!\n\n", p->name);
} } else {
else
{
// Player remains in jail, end turn // Player remains in jail, end turn
printf("\n📋 %s remains in jail.\n", p->name); printf("\n📋 %s remains in jail.\n", p->name);
current_player_idx = (current_player_idx + 1) % players_count; current_player_idx = (current_player_idx + 1) % players_count;
@@ -98,8 +93,7 @@ int main()
int choice; int choice;
scanf("%d", &choice); scanf("%d", &choice);
switch (choice) switch (choice) {
{
case 1: case 1:
handle_roll(p, &has_rolled, &double_rolls); handle_roll(p, &has_rolled, &double_rolls);
break; break;
@@ -113,15 +107,12 @@ int main()
handle_trade(p); handle_trade(p);
break; break;
case 5: case 5:
if (has_rolled) if (has_rolled) {
{
current_player_idx = (current_player_idx + 1) % players_count; current_player_idx = (current_player_idx + 1) % players_count;
has_rolled = false; // Reset for next player has_rolled = false; // Reset for next player
just_sent_to_jail = false; // Reset jail flag just_sent_to_jail = false; // Reset jail flag
printf("✓ Turn ended.\n"); printf("✓ Turn ended.\n");
} } else {
else
{
printf("❌ You must roll before ending your turn!\n"); printf("❌ You must roll before ending your turn!\n");
} }
break; break;
@@ -136,36 +127,33 @@ int main()
return 0; return 0;
} }
void find_properties_on_group_from_position(int position, int positions_found[4], int *count) void find_properties_on_group_from_position(int position,
{ int positions_found[4],
int *count) {
const BoardTile *tile = &MONOPOLY_BOARD[position]; const BoardTile *tile = &MONOPOLY_BOARD[position];
if (tile->type == TILE_PROPERTY || tile->type == TILE_RAILROAD || tile->type == TILE_UTILITY) if (tile->type == TILE_PROPERTY || tile->type == TILE_RAILROAD ||
{ tile->type == TILE_UTILITY) {
int group_id = tile->group[0]; int group_id = tile->group[0];
*count = 0; *count = 0;
for (int i = 0; i < BOARD_SIZE; i++) for (int i = 0; i < MONOPOLY_BOARD_SIZE; i++) {
{
if (i == position) if (i == position)
continue; continue;
const BoardTile *t = &MONOPOLY_BOARD[i]; const BoardTile *t = &MONOPOLY_BOARD[i];
if (t->group[0] == group_id) if (t->group[0] == group_id) {
{
positions_found[(*count)++] = i; positions_found[(*count)++] = i;
} }
} }
} }
} }
bool handle_if_owned(Player *p, const BoardTile *tile){ bool handle_if_owned(Player *p, const BoardTile *tile) {
if (tile->type == TILE_PROPERTY || tile->type == TILE_RAILROAD || tile->type == TILE_UTILITY){ if (tile->type == TILE_PROPERTY || tile->type == TILE_RAILROAD ||
tile->type == TILE_UTILITY) {
bool is_owned = false; bool is_owned = false;
int i = 0; int i = 0;
for (i = 0; i < MAX_PLAYERS; i++) for (i = 0; i < MAX_PLAYERS; i++) {
{ for (int j = 0; j < players[i].property_count; j++) {
for (int j = 0; j < players[i].property_count; j++) if (players[i].properties_owned[j] == p->position) {
{
if (players[i].properties_owned[j] == p->position)
{
is_owned = true; is_owned = true;
printf("🏠 This property is owned by %s.\n", players[i].name); printf("🏠 This property is owned by %s.\n", players[i].name);
break; break;
@@ -174,10 +162,8 @@ bool handle_if_owned(Player *p, const BoardTile *tile){
if (is_owned) if (is_owned)
break; break;
} }
if(is_owned) if (is_owned) {
{ if (players[i].id == p->id) {
if(players[i].id == p->id)
{
printf("✓ You own this property.\n"); printf("✓ You own this property.\n");
return true; return true;
} }
@@ -191,17 +177,14 @@ bool handle_if_owned(Player *p, const BoardTile *tile){
return false; return false;
} }
void handle_roll(Player *p, bool *has_rolled, int *double_rolls) void handle_roll(Player *p, bool *has_rolled, int *double_rolls) {
{ if (*has_rolled) {
if (*has_rolled)
{
printf("❌ You have already moved this turn!\n"); printf("❌ You have already moved this turn!\n");
return; return;
} }
// Check if player is in jail and trying to escape // Check if player is in jail and trying to escape
if (p->is_in_jail) if (p->is_in_jail) {
{
printf("❌ You are in jail! Use the jail menu to escape first.\n"); printf("❌ You are in jail! Use the jail menu to escape first.\n");
return; return;
} }
@@ -210,13 +193,11 @@ void handle_roll(Player *p, bool *has_rolled, int *double_rolls)
int dice2 = (rand() % 6) + 1; int dice2 = (rand() % 6) + 1;
printf("\n🎲 Rolled: [%d] + [%d] = %d\n", dice1, dice2, dice1 + dice2); printf("\n🎲 Rolled: [%d] + [%d] = %d\n", dice1, dice2, dice1 + dice2);
int total = dice1 + dice2; int total = dice1 + dice2;
p->position = (p->position + total) % BOARD_SIZE; p->position = (p->position + total) % MONOPOLY_BOARD_SIZE;
if(dice1 == dice2) if (dice1 == dice2) {
{
(*double_rolls)++; (*double_rolls)++;
if(*double_rolls >= 3) if (*double_rolls >= 3) {
{
printf("🚨 Three doubles in a row! Sent directly to JAIL!\n"); printf("🚨 Three doubles in a row! Sent directly to JAIL!\n");
p->position = 10; // Jail position p->position = 10; // Jail position
p->jail_turns = 0; p->jail_turns = 0;
@@ -225,34 +206,28 @@ void handle_roll(Player *p, bool *has_rolled, int *double_rolls)
*has_rolled = true; *has_rolled = true;
just_sent_to_jail = true; just_sent_to_jail = true;
return; return;
} } else {
else
{
printf("✨ Doubles! You get another turn!\n"); printf("✨ Doubles! You get another turn!\n");
} }
} } else {
else
{
*double_rolls = 0; // Reset double rolls count *double_rolls = 0; // Reset double rolls count
} }
*has_rolled = true; *has_rolled = true;
// Check for passing GO // Check for passing GO
if (p->position < (p->position - total)) if (p->position < (p->position - total)) { // Simplistic wrap-around check
{ // Simplistic wrap-around check
p->balance += 200; p->balance += 200;
printf("Passed GO! Collected $200.\n"); printf("Passed GO! Collected $200.\n");
} }
printf("➜ Moved %d spaces to: %s\n\n", total, MONOPOLY_BOARD[p->position].name); printf("➜ Moved %d spaces to: %s\n\n", total,
MONOPOLY_BOARD[p->position].name);
process_landing(p); process_landing(p);
} }
void handle_buy(Player *p, bool has_rolled) void handle_buy(Player *p, bool has_rolled) {
{ if (!has_rolled) {
if (!has_rolled)
{
printf("❌ You can't buy anything until you roll and land on a tile!\n"); printf("❌ You can't buy anything until you roll and land on a tile!\n");
return; return;
} }
@@ -260,48 +235,42 @@ void handle_buy(Player *p, bool has_rolled)
const BoardTile *tile = &MONOPOLY_BOARD[p->position]; const BoardTile *tile = &MONOPOLY_BOARD[p->position];
// Check if it's even a purchasable type // Check if it's even a purchasable type
if (tile->type != TILE_PROPERTY && tile->type != TILE_RAILROAD && tile->type != TILE_UTILITY) if (tile->type != TILE_PROPERTY && tile->type != TILE_RAILROAD &&
{ tile->type != TILE_UTILITY) {
printf("❌ This location (%s) cannot be purchased.\n", tile->name); printf("❌ This location (%s) cannot be purchased.\n", tile->name);
return; return;
} }
// Check if someone already owns it (basic check) // Check if someone already owns it (basic check)
// In a full game, we'd iterate through all players' properties_owned arrays // In a full game, we'd iterate through all players' properties_owned arrays
for (int i = 0; i < MAX_PLAYERS; i++) for (int i = 0; i < MAX_PLAYERS; i++) {
{ for (int j = 0; j < players[i].property_count; j++) {
for (int j = 0; j < players[i].property_count; j++) if (players[i].properties_owned[j] == p->position) {
{
if (players[i].properties_owned[j] == p->position)
{
printf("❌ This property is already owned by %s.\n", players[i].name); printf("❌ This property is already owned by %s.\n", players[i].name);
return; return;
} }
} }
} }
if (p->balance >= tile->cost) if (p->balance >= tile->cost) {
{
p->balance -= tile->cost; p->balance -= tile->cost;
p->properties_owned[p->property_count++] = p->position; p->properties_owned[p->property_count++] = p->position;
printf("✓ Bought %s for $%d! (Balance: $%d)\n", tile->name, tile->cost, p->balance); printf("✓ Bought %s for $%d! (Balance: $%d)\n", tile->name, tile->cost,
} p->balance);
else } else {
{ printf("❌ Insufficient funds! Cost: $%d | Your Balance: $%d\n", tile->cost,
printf("❌ Insufficient funds! Cost: $%d | Your Balance: $%d\n", tile->cost, p->balance); p->balance);
} }
} }
void process_landing(Player *p) void process_landing(Player *p) {
{
const BoardTile *tile = &MONOPOLY_BOARD[p->position]; const BoardTile *tile = &MONOPOLY_BOARD[p->position];
printf("\n─────────────────────────────────────────\n"); printf("\n─────────────────────────────────────────\n");
printf("📍 Landed on: %s\n", tile->name); printf("📍 Landed on: %s\n", tile->name);
printf("─────────────────────────────────────────\n"); printf("─────────────────────────────────────────\n");
switch (tile->type) switch (tile->type) {
{
case TILE_PROPERTY: case TILE_PROPERTY:
case TILE_RAILROAD: case TILE_RAILROAD:
case TILE_UTILITY: case TILE_UTILITY:
@@ -330,23 +299,19 @@ void process_landing(Player *p)
printf("📌 You're at: %s\n", tile->name); printf("📌 You're at: %s\n", tile->name);
break; break;
default: default:
break; break;
} }
} }
void handle_property_landing(Player *p, const BoardTile *tile) void handle_property_landing(Player *p, const BoardTile *tile) {
{
bool is_owned = handle_if_owned(p, tile); bool is_owned = handle_if_owned(p, tile);
if (is_owned) if (is_owned) {
{
return; return;
} }
printf("\n💰 Purchase Price: $%d\n", tile->cost); printf("\n💰 Purchase Price: $%d\n", tile->cost);
if (tile->type == TILE_PROPERTY) if (tile->type == TILE_PROPERTY) {
{
// rent data // rent data
printf("\n📋 Rent Schedule:\n"); printf("\n📋 Rent Schedule:\n");
printf(" Vacant.....................$%d\n", tile->rent[0]); printf(" Vacant.....................$%d\n", tile->rent[0]);
@@ -359,25 +324,21 @@ void handle_property_landing(Player *p, const BoardTile *tile)
} }
// show if the other properties in the group are owned // show if the other properties in the group are owned
printf("\n🏘️ Property Group: %d | Position %d/%d in group\n", printf("\n🏘️ Property Group: %d | Position %d/%d in group\n", tile->group[0],
tile->group[0], tile->group[1], tile->group[2]); tile->group[1], tile->group[2]);
int group_positions[4]; int group_positions[4];
int group_count = 0; int group_count = 0;
find_properties_on_group_from_position(p->position, group_positions, &group_count); find_properties_on_group_from_position(p->position, group_positions,
if (group_count > 0) &group_count);
{ if (group_count > 0) {
printf("\n Related properties:\n"); printf("\n Related properties:\n");
for (int i = 0; i < group_count; i++) for (int i = 0; i < group_count; i++) {
{
const BoardTile *gtile = &MONOPOLY_BOARD[group_positions[i]]; const BoardTile *gtile = &MONOPOLY_BOARD[group_positions[i]];
// Check if owned by any player // Check if owned by any player
bool is_owned_in_group = false; bool is_owned_in_group = false;
for (int j = 0; j < MAX_PLAYERS; j++) for (int j = 0; j < MAX_PLAYERS; j++) {
{ for (int k = 0; k < players[j].property_count; k++) {
for (int k = 0; k < players[j].property_count; k++) if (players[j].properties_owned[k] == group_positions[i]) {
{
if (players[j].properties_owned[k] == group_positions[i])
{
is_owned_in_group = true; is_owned_in_group = true;
printf(" 🔒 %s (Owned by %s)\n", gtile->name, players[j].name); printf(" 🔒 %s (Owned by %s)\n", gtile->name, players[j].name);
break; break;
@@ -386,21 +347,18 @@ void handle_property_landing(Player *p, const BoardTile *tile)
if (is_owned_in_group) if (is_owned_in_group)
break; break;
} }
if (!is_owned_in_group) if (!is_owned_in_group) {
{
printf(" 🔓 %s - $%d (available)\n", gtile->name, gtile->cost); printf(" 🔓 %s - $%d (available)\n", gtile->name, gtile->cost);
} }
} }
} }
} }
void handle_trade(Player *p) void handle_trade(Player *p) {
{
printf("⚙️ Trade functionality is not yet implemented.\n"); printf("⚙️ Trade functionality is not yet implemented.\n");
} }
void handle_jail_options(Player *p) void handle_jail_options(Player *p) {
{
bool escaped = false; bool escaped = false;
printf("\n╔─ Jail Options ──────────────────────────────╗\n"); printf("\n╔─ Jail Options ──────────────────────────────╗\n");
@@ -414,39 +372,32 @@ void handle_jail_options(Player *p)
int choice; int choice;
scanf("%d", &choice); scanf("%d", &choice);
switch(choice) switch (choice) {
{
case 1: case 1:
// Try to roll doubles // Try to roll doubles
escaped = attempt_jail_escape(p); escaped = attempt_jail_escape(p);
break; break;
case 2: case 2:
// Pay bail // Pay bail
if (p->balance >= 50) if (p->balance >= 50) {
{
p->balance -= 50; p->balance -= 50;
p->is_in_jail = false; p->is_in_jail = false;
p->jail_turns = 0; p->jail_turns = 0;
escaped = true; escaped = true;
printf("\n✓ Paid $50 bail! You are now free.\n"); printf("\n✓ Paid $50 bail! You are now free.\n");
} } else {
else
{
printf("\n❌ Insufficient funds! You need $50.\n"); printf("\n❌ Insufficient funds! You need $50.\n");
} }
break; break;
case 3: case 3:
if (p->jail_free_cards > 0) if (p->jail_free_cards > 0) {
{
p->jail_free_cards--; p->jail_free_cards--;
p->is_in_jail = false; p->is_in_jail = false;
p->jail_turns = 0; p->jail_turns = 0;
escaped = true; escaped = true;
printf("\n✓ Used a Get Out of Jail Free card! You are now free.\n"); printf("\n✓ Used a Get Out of Jail Free card! You are now free.\n");
printf(" Cards remaining: %d\n", p->jail_free_cards); printf(" Cards remaining: %d\n", p->jail_free_cards);
} } else {
else
{
printf("\n❌ You don't have any Get Out of Jail Free cards!\n"); printf("\n❌ You don't have any Get Out of Jail Free cards!\n");
} }
break; break;
@@ -455,11 +406,9 @@ void handle_jail_options(Player *p)
break; break;
} }
if (!escaped) if (!escaped) {
{
p->jail_turns++; p->jail_turns++;
if (p->jail_turns >= 3) if (p->jail_turns >= 3) {
{
// Force payment after 3 turns // Force payment after 3 turns
printf("\n⏰ You've been in jail for 3 turns. You must pay $50 bail!\n"); printf("\n⏰ You've been in jail for 3 turns. You must pay $50 bail!\n");
p->balance -= 50; p->balance -= 50;
@@ -470,26 +419,21 @@ void handle_jail_options(Player *p)
} }
} }
bool attempt_jail_escape(Player *p) bool attempt_jail_escape(Player *p) {
{
int dice1 = (rand() % 6) + 1; int dice1 = (rand() % 6) + 1;
int dice2 = (rand() % 6) + 1; int dice2 = (rand() % 6) + 1;
printf("\n🎲 Rolling to escape...\n"); printf("\n🎲 Rolling to escape...\n");
printf(" Rolled: [%d] + [%d]\n", dice1, dice2); printf(" Rolled: [%d] + [%d]\n", dice1, dice2);
if (dice1 == dice2) if (dice1 == dice2) {
{
printf("\n✨ DOUBLES! You escaped jail!\n"); printf("\n✨ DOUBLES! You escaped jail!\n");
p->is_in_jail = false; p->is_in_jail = false;
p->jail_turns = 0; p->jail_turns = 0;
return true; return true;
} } else {
else
{
printf("\n❌ No doubles. You remain in jail.\n"); printf("\n❌ No doubles. You remain in jail.\n");
p->jail_turns++; p->jail_turns++;
if (p->jail_turns >= 3) if (p->jail_turns >= 3) {
{
printf("\n⏰ You've been in jail for 3 turns. You must pay $50 bail!\n"); printf("\n⏰ You've been in jail for 3 turns. You must pay $50 bail!\n");
p->balance -= 50; p->balance -= 50;
p->is_in_jail = false; p->is_in_jail = false;
@@ -500,15 +444,14 @@ bool attempt_jail_escape(Player *p)
} }
} }
void handle_build(Player *p) void handle_build(Player *p) {
{
printf("⚙️ Build functionality is not yet implemented.\n"); printf("⚙️ Build functionality is not yet implemented.\n");
} }
void handle_chance(Player* p) { void handle_chance(Player *p) {
// In a real game, you'd pull from a shuffled deck of indices // In a real game, you'd pull from a shuffled deck of indices
int card_idx = rand() % CHANCE_DECK_SIZE; int card_idx = rand() % CHANCE_DECK_SIZE;
const ChanceCard* card = &CHANCE_DECK[card_idx]; const ChanceCard *card = &CHANCE_DECK[card_idx];
printf("\n✨ %s\n", card->description); printf("\n✨ %s\n", card->description);
@@ -519,11 +462,11 @@ void handle_chance(Player* p) {
// Handle special "Nearest" logic // Handle special "Nearest" logic
if (target == TARGET_NEAREST_UTILITY) { if (target == TARGET_NEAREST_UTILITY) {
while (MONOPOLY_BOARD[p->position].type != TILE_UTILITY) { while (MONOPOLY_BOARD[p->position].type != TILE_UTILITY) {
p->position = (p->position + 1) % BOARD_SIZE; p->position = (p->position + 1) % MONOPOLY_BOARD_SIZE;
} }
} else if (target == TARGET_NEAREST_RAILROAD) { } else if (target == TARGET_NEAREST_RAILROAD) {
while (MONOPOLY_BOARD[p->position].type != TILE_RAILROAD) { while (MONOPOLY_BOARD[p->position].type != TILE_RAILROAD) {
p->position = (p->position + 1) % BOARD_SIZE; p->position = (p->position + 1) % MONOPOLY_BOARD_SIZE;
} }
} else { } else {
// Check for passing GO during standard advance // Check for passing GO during standard advance
@@ -547,7 +490,8 @@ void handle_chance(Player* p) {
break; break;
case CHANCE_BACK: case CHANCE_BACK:
p->position = (p->position - card->value + BOARD_SIZE) % BOARD_SIZE; p->position =
(p->position - card->value + MONOPOLY_BOARD_SIZE) % MONOPOLY_BOARD_SIZE;
printf("⬅️ Moved back to: %s\n", MONOPOLY_BOARD[p->position].name); printf("⬅️ Moved back to: %s\n", MONOPOLY_BOARD[p->position].name);
process_landing(p); process_landing(p);
break; break;
@@ -571,7 +515,8 @@ void handle_chance(Player* p) {
case CHANCE_JAIL_FREE: case CHANCE_JAIL_FREE:
p->jail_free_cards++; p->jail_free_cards++;
printf("🔑 You received a 'Get Out of Jail Free' card! (Total: %d)\n", p->jail_free_cards); printf("🔑 You received a 'Get Out of Jail Free' card! (Total: %d)\n",
p->jail_free_cards);
break; break;
case CHANCE_REPAIRS: case CHANCE_REPAIRS:
@@ -581,9 +526,9 @@ void handle_chance(Player* p) {
} }
} }
void handle_community_chest(Player* p) { void handle_community_chest(Player *p) {
int card_idx = rand() % COMMUNITY_DECK_SIZE; int card_idx = rand() % COMMUNITY_DECK_SIZE;
const CommunityCard* card = &COMMUNITY_DECK[card_idx]; const CommunityCard *card = &COMMUNITY_DECK[card_idx];
printf("\n📦 %s\n", card->description); printf("\n📦 %s\n", card->description);

View File

@@ -18,59 +18,219 @@ typedef enum {
} TileType; } TileType;
typedef struct { typedef struct {
const char* name; const char *name;
TileType type; TileType type;
bool is_corner; bool is_corner;
int cost; // 0 if not applicable int cost; // 0 if not applicable
const char* color; // Hex string, NULL if not property const char *color; // Hex string, NULL if not property
int rent[6]; // Base, 1H, 2H, 3H, 4H, Hotel int rent[6]; // Base, 1H, 2H, 3H, 4H, Hotel
int group[3]; // Group ID, Position in group, Total in group int group[3]; // Group ID, Position in group, Total in group
int house_cost; // Cost to build int house_cost; // Cost to build
} BoardTile; } BoardTile;
#define BOARD_SIZE 40 #define MONOPOLY_BOARD_SIZE 40
static const BoardTile MONOPOLY_BOARD[BOARD_SIZE] = { static const BoardTile MONOPOLY_BOARD[MONOPOLY_BOARD_SIZE] = {
{"Go", TILE_GO, true, 0, NULL, {0}, {0}, 0}, {"Go", TILE_GO, true, 0, NULL, {0}, {0}, 0},
{"Mediterranean Avenue", TILE_PROPERTY, false, 60, "#955438", {2, 10, 30, 90, 160, 250}, {1, 1, 2}, 50}, {"Mediterranean Avenue",
TILE_PROPERTY,
false,
60,
"#955438",
{2, 10, 30, 90, 160, 250},
{1, 1, 2},
50},
{"Community Chest", TILE_COMMUNITY_CHEST, false, 0, NULL, {0}, {0}, 0}, {"Community Chest", TILE_COMMUNITY_CHEST, false, 0, NULL, {0}, {0}, 0},
{"Baltic Avenue", TILE_PROPERTY, false, 60, "#955438", {4, 20, 60, 180, 320, 450}, {1, 2, 2}, 50}, {"Baltic Avenue",
TILE_PROPERTY,
false,
60,
"#955438",
{4, 20, 60, 180, 320, 450},
{1, 2, 2},
50},
{"Income Tax", TILE_TAX, false, 200, NULL, {0}, {0}, 0}, {"Income Tax", TILE_TAX, false, 200, NULL, {0}, {0}, 0},
{"Reading Railroad", TILE_RAILROAD, false, 200, NULL, {0}, {9, 1, 4}, 0}, {"Reading Railroad", TILE_RAILROAD, false, 200, NULL, {0}, {9, 1, 4}, 0},
{"Rhode Island Avenue", TILE_PROPERTY, false, 100, "#aae0fa", {6, 30, 90, 270, 400, 550}, {2, 1, 3}, 50}, {"Rhode Island Avenue",
TILE_PROPERTY,
false,
100,
"#aae0fa",
{6, 30, 90, 270, 400, 550},
{2, 1, 3},
50},
{"Chance", TILE_CHANCE, false, 0, NULL, {0}, {0}, 0}, {"Chance", TILE_CHANCE, false, 0, NULL, {0}, {0}, 0},
{"Vermont Avenue", TILE_PROPERTY, false, 100, "#aae0fa", {6, 30, 90, 270, 400, 550}, {2, 2, 3}, 50}, {"Vermont Avenue",
{"Connecticut Avenue", TILE_PROPERTY, false, 120, "#aae0fa", {8, 40, 100, 300, 450, 600}, {2, 3, 3}, 50}, TILE_PROPERTY,
false,
100,
"#aae0fa",
{6, 30, 90, 270, 400, 550},
{2, 2, 3},
50},
{"Connecticut Avenue",
TILE_PROPERTY,
false,
120,
"#aae0fa",
{8, 40, 100, 300, 450, 600},
{2, 3, 3},
50},
{"Jail", TILE_JAIL, true, 0, NULL, {0}, {0}, 0}, {"Jail", TILE_JAIL, true, 0, NULL, {0}, {0}, 0},
{"St. Charles Place", TILE_PROPERTY, false, 140, "#d93a96", {10, 50, 150, 450, 625, 750}, {3, 1, 3}, 100}, {"St. Charles Place",
TILE_PROPERTY,
false,
140,
"#d93a96",
{10, 50, 150, 450, 625, 750},
{3, 1, 3},
100},
{"Electric Company", TILE_UTILITY, false, 150, NULL, {0}, {10, 1, 2}, 0}, {"Electric Company", TILE_UTILITY, false, 150, NULL, {0}, {10, 1, 2}, 0},
{"States Avenue", TILE_PROPERTY, false, 140, "#d93a96", {10, 50, 150, 450, 625, 750}, {3, 2, 3}, 100}, {"States Avenue",
{"Virginia Avenue", TILE_PROPERTY, false, 160, "#d93a96", {12, 60, 180, 500, 700, 900}, {3, 3, 3}, 100}, TILE_PROPERTY,
{"Pennsylvania Railroad", TILE_RAILROAD, false, 200, NULL, {0}, {9, 2, 4}, 0}, false,
{"St. James Place", TILE_PROPERTY, false, 180, "#f7941d", {14, 70, 200, 550, 750, 950}, {4, 1, 3}, 100}, 140,
"#d93a96",
{10, 50, 150, 450, 625, 750},
{3, 2, 3},
100},
{"Virginia Avenue",
TILE_PROPERTY,
false,
160,
"#d93a96",
{12, 60, 180, 500, 700, 900},
{3, 3, 3},
100},
{"Pennsylvania Railroad",
TILE_RAILROAD,
false,
200,
NULL,
{0},
{9, 2, 4},
0},
{"St. James Place",
TILE_PROPERTY,
false,
180,
"#f7941d",
{14, 70, 200, 550, 750, 950},
{4, 1, 3},
100},
{"Community Chest", TILE_COMMUNITY_CHEST, false, 0, NULL, {0}, {0}, 0}, {"Community Chest", TILE_COMMUNITY_CHEST, false, 0, NULL, {0}, {0}, 0},
{"Tennessee Avenue", TILE_PROPERTY, false, 180, "#f7941d", {14, 70, 200, 550, 750, 950}, {4, 2, 3}, 100}, {"Tennessee Avenue",
{"New York Avenue", TILE_PROPERTY, false, 200, "#f7941d", {16, 80, 220, 600, 800, 1000}, {4, 3, 3}, 100}, TILE_PROPERTY,
false,
180,
"#f7941d",
{14, 70, 200, 550, 750, 950},
{4, 2, 3},
100},
{"New York Avenue",
TILE_PROPERTY,
false,
200,
"#f7941d",
{16, 80, 220, 600, 800, 1000},
{4, 3, 3},
100},
{"Free Parking", TILE_FREE_PARKING, true, 0, NULL, {0}, {0}, 0}, {"Free Parking", TILE_FREE_PARKING, true, 0, NULL, {0}, {0}, 0},
{"Kentucky Avenue", TILE_PROPERTY, false, 220, "#ed1b24", {18, 90, 250, 700, 875, 1050}, {5, 1, 3}, 150}, {"Kentucky Avenue",
TILE_PROPERTY,
false,
220,
"#ed1b24",
{18, 90, 250, 700, 875, 1050},
{5, 1, 3},
150},
{"Chance", TILE_CHANCE, false, 0, NULL, {0}, {0}, 0}, {"Chance", TILE_CHANCE, false, 0, NULL, {0}, {0}, 0},
{"Indiana Avenue", TILE_PROPERTY, false, 220, "#ed1b24", {18, 90, 250, 700, 875, 1050}, {5, 2, 3}, 150}, {"Indiana Avenue",
{"Illinois Avenue", TILE_PROPERTY, false, 240, "#ed1b24", {20, 100, 300, 750, 925, 1100}, {5, 3, 3}, 150}, TILE_PROPERTY,
false,
220,
"#ed1b24",
{18, 90, 250, 700, 875, 1050},
{5, 2, 3},
150},
{"Illinois Avenue",
TILE_PROPERTY,
false,
240,
"#ed1b24",
{20, 100, 300, 750, 925, 1100},
{5, 3, 3},
150},
{"B. & O. Railroad", TILE_RAILROAD, false, 200, NULL, {0}, {9, 3, 4}, 0}, {"B. & O. Railroad", TILE_RAILROAD, false, 200, NULL, {0}, {9, 3, 4}, 0},
{"Atlantic Avenue", TILE_PROPERTY, false, 260, "#fef200", {22, 110, 330, 800, 975, 1150}, {6, 1, 3}, 150}, {"Atlantic Avenue",
{"Ventnor Avenue", TILE_PROPERTY, false, 260, "#fef200", {22, 110, 330, 800, 975, 1150}, {6, 2, 3}, 150}, TILE_PROPERTY,
false,
260,
"#fef200",
{22, 110, 330, 800, 975, 1150},
{6, 1, 3},
150},
{"Ventnor Avenue",
TILE_PROPERTY,
false,
260,
"#fef200",
{22, 110, 330, 800, 975, 1150},
{6, 2, 3},
150},
{"Water Works", TILE_UTILITY, false, 150, NULL, {0}, {10, 2, 2}, 0}, {"Water Works", TILE_UTILITY, false, 150, NULL, {0}, {10, 2, 2}, 0},
{"Marvin Gardens", TILE_PROPERTY, false, 280, "#fef200", {24, 120, 360, 850, 1025, 1200}, {6, 3, 3}, 150}, {"Marvin Gardens",
TILE_PROPERTY,
false,
280,
"#fef200",
{24, 120, 360, 850, 1025, 1200},
{6, 3, 3},
150},
{"Go To Jail", TILE_GO_TO_JAIL, true, 0, NULL, {0}, {0}, 0}, {"Go To Jail", TILE_GO_TO_JAIL, true, 0, NULL, {0}, {0}, 0},
{"Pacific Avenue", TILE_PROPERTY, false, 300, "#1fb25a", {26, 130, 390, 900, 1100, 1275}, {7, 1, 3}, 200}, {"Pacific Avenue",
{"North Carolina Avenue", TILE_PROPERTY, false, 300, "#1fb25a", {26, 130, 390, 900, 1100, 1275}, {7, 2, 3}, 200}, TILE_PROPERTY,
false,
300,
"#1fb25a",
{26, 130, 390, 900, 1100, 1275},
{7, 1, 3},
200},
{"North Carolina Avenue",
TILE_PROPERTY,
false,
300,
"#1fb25a",
{26, 130, 390, 900, 1100, 1275},
{7, 2, 3},
200},
{"Community Chest", TILE_COMMUNITY_CHEST, false, 0, NULL, {0}, {0}, 0}, {"Community Chest", TILE_COMMUNITY_CHEST, false, 0, NULL, {0}, {0}, 0},
{"Pennsylvania Avenue", TILE_PROPERTY, false, 320, "#1fb25a", {28, 150, 450, 1000, 1200, 1400}, {7, 3, 3}, 200}, {"Pennsylvania Avenue",
TILE_PROPERTY,
false,
320,
"#1fb25a",
{28, 150, 450, 1000, 1200, 1400},
{7, 3, 3},
200},
{"Short Line", TILE_RAILROAD, false, 200, NULL, {0}, {9, 4, 4}, 0}, {"Short Line", TILE_RAILROAD, false, 200, NULL, {0}, {9, 4, 4}, 0},
{"Chance", TILE_CHANCE, false, 0, NULL, {0}, {0}, 0}, {"Chance", TILE_CHANCE, false, 0, NULL, {0}, {0}, 0},
{"Park Place", TILE_PROPERTY, false, 350, "#0072bb", {35, 175, 500, 1100, 1300, 1500}, {8, 1, 2}, 200}, {"Park Place",
TILE_PROPERTY,
false,
350,
"#0072bb",
{35, 175, 500, 1100, 1300, 1500},
{8, 1, 2},
200},
{"Luxury Tax", TILE_TAX, false, 100, NULL, {0}, {0}, 0}, {"Luxury Tax", TILE_TAX, false, 100, NULL, {0}, {0}, 0},
{"Boardwalk", TILE_PROPERTY, false, 400, "#0072bb", {50, 200, 600, 1400, 1700, 2000}, {8, 2, 2}, 200} {"Boardwalk",
}; TILE_PROPERTY,
false,
400,
"#0072bb",
{50, 200, 600, 1400, 1700, 2000},
{8, 2, 2},
200}};
#endif #endif

View File

@@ -1,7 +1,8 @@
// ============================================================================ // ============================================================================
// MONOPOLY GAME IMPLEMENTATION (for custom console) // MONOPOLY GAME IMPLEMENTATION (for custom console)
// ============================================================================ // ============================================================================
// Refactored from console version to use Game interface and rendering/input system // Refactored from console version to use Game interface and rendering/input
// system
#include "monopoly_game.h" #include "monopoly_game.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -12,25 +13,25 @@ extern "C" {
} }
#endif #endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "DiceModalGame.h"
#include "PropertyModalGame.h"
#include "BoardModalGame.h" #include "BoardModalGame.h"
#include "ChanceModalGame.h" #include "ChanceModalGame.h"
#include "CommunityChestModalGame.h" #include "CommunityChestModalGame.h"
#include "TurnModalGame.h" #include "DiceModalGame.h"
#include "PaymentModalGame.h"
#include "ModalButtonHelper.h" #include "ModalButtonHelper.h"
#include "sprites.h"
#include "MonopolyBoardRenderer.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 --- // --- Constructor ---
MonopolyGame::MonopolyGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager) MonopolyGame::MonopolyGame(uint16_t width, uint16_t height,
LowLevelRenderer *renderer, LowLevelGUI *gui,
InputManager *input_manager)
: Game(width, height, renderer, gui, input_manager) { : Game(width, height, renderer, gui, input_manager) {
players_count = 2; players_count = 2;
current_player_idx = 0; current_player_idx = 0;
@@ -56,9 +57,13 @@ void MonopolyGame::init() {
srand(time(NULL)); srand(time(NULL));
shuffle_chance_deck(); shuffle_chance_deck();
shuffle_community_deck(); shuffle_community_deck();
//renderer->set_font(&font_tama_mini02_obj); // renderer->set_font(&font_tama_mini02_obj);
if (active_modal) { delete active_modal; active_modal = nullptr; } if (active_modal) {
active_modal = new TurnModalGame(width, height, renderer, gui, input_manager, &players[current_player_idx]); 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. // TODO: Reset all board state, property ownership, etc.
} }
@@ -89,15 +94,16 @@ void MonopolyGame::shuffle_community_deck() {
} }
// --- Handle input events (minimal: roll, buy, end turn) --- // --- Handle input events (minimal: roll, buy, end turn) ---
bool MonopolyGame::update(const InputEvent& event) { bool MonopolyGame::update(const InputEvent &event) {
Player* p = &players[current_player_idx]; Player *p = &players[current_player_idx];
bool needs_redraw = false; bool needs_redraw = false;
// Calculate available actions // Calculate available actions
int menu_count = 0; int menu_count = 0;
if (!has_rolled) { if (!has_rolled) {
menu_count++; // Roll Dice menu_count++; // Roll Dice
if (p->is_in_jail) menu_count++; // Pay $50 if (p->is_in_jail)
menu_count++; // Pay $50
} else { } else {
menu_count++; // End Turn menu_count++; // End Turn
} }
@@ -106,16 +112,39 @@ bool MonopolyGame::update(const InputEvent& event) {
// If a modal is active, delegate input and check for dismissal // If a modal is active, delegate input and check for dismissal
if (active_modal) { if (active_modal) {
bool modal_redraw = active_modal->update(event); bool modal_redraw = active_modal->update(event);
if (modal_redraw) needs_redraw = true; if (modal_redraw)
needs_redraw = true;
// Check for specific modal types to handle their results using custom get_type() // Check for specific modal types to handle their results using custom
DiceModalGame* dice_modal = (active_modal->get_type() == Game::Type::MONOPOLY_DICE) ? static_cast<DiceModalGame*>(active_modal) : nullptr; // get_type()
PropertyModalGame* prop_modal = (active_modal->get_type() == Game::Type::MONOPOLY_PROPERTY) ? static_cast<PropertyModalGame*>(active_modal) : nullptr; DiceModalGame *dice_modal =
BoardModalGame* board_modal = (active_modal->get_type() == Game::Type::MONOPOLY_BOARD) ? static_cast<BoardModalGame*>(active_modal) : nullptr; (active_modal->get_type() == Game::Type::MONOPOLY_DICE)
ChanceModalGame* chance_modal = (active_modal->get_type() == Game::Type::MONOPOLY_CHANCE) ? static_cast<ChanceModalGame*>(active_modal) : nullptr; ? static_cast<DiceModalGame *>(active_modal)
CommunityChestModalGame* community_modal = (active_modal->get_type() == Game::Type::MONOPOLY_COMMUNITY_CHEST) ? static_cast<CommunityChestModalGame*>(active_modal) : nullptr; : nullptr;
TurnModalGame* turn_modal = (active_modal->get_type() == Game::Type::MONOPOLY_TURN) ? static_cast<TurnModalGame*>(active_modal) : nullptr; PropertyModalGame *prop_modal =
PaymentModalGame* pay_modal = (active_modal->get_type() == Game::Type::MONOPOLY_PAYMENT) ? static_cast<PaymentModalGame*>(active_modal) : nullptr; (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()) { if (pay_modal && pay_modal->is_dismissed()) {
delete active_modal; delete active_modal;
@@ -135,7 +164,7 @@ bool MonopolyGame::update(const InputEvent& event) {
// Immediately check if we need to show a property modal // Immediately check if we need to show a property modal
if (modal_property_index >= 0) { if (modal_property_index >= 0) {
bool is_owned = false; bool is_owned = false;
const char* owner_name = nullptr; const char *owner_name = nullptr;
int owner_id = -1; int owner_id = -1;
for (int i = 0; i < players_count; ++i) { for (int i = 0; i < players_count; ++i) {
for (int j = 0; j < players[i].property_count; ++j) { for (int j = 0; j < players[i].property_count; ++j) {
@@ -146,23 +175,36 @@ bool MonopolyGame::update(const InputEvent& event) {
break; break;
} }
} }
if (is_owned) break; if (is_owned)
break;
} }
bool can_afford = (p->balance >= MONOPOLY_BOARD[modal_property_index].cost); bool can_afford =
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); (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; modal_property_index = -1;
} else if (last_drawn_chance_idx >= 0) { } 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); 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 // We'll apply the effect when ChanceModal is dismissed
} else if (last_drawn_community_idx >= 0) { } 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); 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 // We'll apply the effect when CommunityChestModal is dismissed
} }
if (active_modal) active_modal->init(); if (active_modal)
else selected_action = -1; active_modal->init();
else
selected_action = -1;
return needs_redraw; return needs_redraw;
} else if (chance_modal && chance_modal->is_dismissed()) { } else if (chance_modal && chance_modal->is_dismissed()) {
const ChanceCard* card = &CHANCE_DECK[last_drawn_chance_idx]; const ChanceCard *card = &CHANCE_DECK[last_drawn_chance_idx];
last_drawn_chance_idx = -1; last_drawn_chance_idx = -1;
delete active_modal; delete active_modal;
active_modal = nullptr; active_modal = nullptr;
@@ -177,31 +219,36 @@ bool MonopolyGame::update(const InputEvent& event) {
p->balance += card->value; p->balance += card->value;
break; break;
case CHANCE_SPEND: case CHANCE_SPEND:
active_modal = new PaymentModalGame(width, height, renderer, gui, input_manager, p, nullptr, card->value, "CHANCE CARD"); active_modal =
if (active_modal) active_modal->init(); new PaymentModalGame(width, height, renderer, gui, input_manager, p,
nullptr, card->value, "CHANCE CARD");
if (active_modal)
active_modal->init();
break; break;
case CHANCE_ADVANCE: { case CHANCE_ADVANCE: {
int target = card->value; int target = card->value;
if (target == TARGET_NEAREST_UTILITY) { if (target == TARGET_NEAREST_UTILITY) {
target = (p->position + 1) % BOARD_SIZE; target = (p->position + 1) % MONOPOLY_BOARD_SIZE;
while (MONOPOLY_BOARD[target].type != TILE_UTILITY) { while (MONOPOLY_BOARD[target].type != TILE_UTILITY) {
target = (target + 1) % BOARD_SIZE; target = (target + 1) % MONOPOLY_BOARD_SIZE;
} }
force_utility_10x = true; force_utility_10x = true;
} else if (target == TARGET_NEAREST_RAILROAD) { } else if (target == TARGET_NEAREST_RAILROAD) {
target = (p->position + 1) % BOARD_SIZE; target = (p->position + 1) % MONOPOLY_BOARD_SIZE;
while (MONOPOLY_BOARD[target].type != TILE_RAILROAD) { while (MONOPOLY_BOARD[target].type != TILE_RAILROAD) {
target = (target + 1) % BOARD_SIZE; target = (target + 1) % MONOPOLY_BOARD_SIZE;
} }
rent_multiplier = 2; rent_multiplier = 2;
} }
p->position = target; p->position = target;
if (p->position < old_pos) p->balance += 200; if (p->position < old_pos)
p->balance += 200;
position_changed = true; position_changed = true;
break; break;
} }
case CHANCE_BACK: case CHANCE_BACK:
p->position = (p->position - card->value + BOARD_SIZE) % BOARD_SIZE; p->position = (p->position - card->value + MONOPOLY_BOARD_SIZE) %
MONOPOLY_BOARD_SIZE;
position_changed = true; position_changed = true;
break; break;
case CHANCE_JAIL: case CHANCE_JAIL:
@@ -231,10 +278,11 @@ bool MonopolyGame::update(const InputEvent& event) {
active_modal->init(); active_modal->init();
} else if (position_changed) { } else if (position_changed) {
// If we moved, check if we landed on a property // If we moved, check if we landed on a property
const BoardTile* landed = &MONOPOLY_BOARD[p->position]; const BoardTile *landed = &MONOPOLY_BOARD[p->position];
if (landed->type == TILE_PROPERTY || landed->type == TILE_RAILROAD || landed->type == TILE_UTILITY) { if (landed->type == TILE_PROPERTY || landed->type == TILE_RAILROAD ||
landed->type == TILE_UTILITY) {
bool is_owned = false; bool is_owned = false;
const char* owner_name = nullptr; const char *owner_name = nullptr;
int owner_id = -1; int owner_id = -1;
for (int i = 0; i < players_count; ++i) { for (int i = 0; i < players_count; ++i) {
for (int j = 0; j < players[i].property_count; ++j) { for (int j = 0; j < players[i].property_count; ++j) {
@@ -247,12 +295,16 @@ bool MonopolyGame::update(const InputEvent& event) {
} }
} }
bool can_afford = (p->balance >= landed->cost); 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); active_modal = new PropertyModalGame(
if (active_modal) active_modal->init(); 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()) { } else if (community_modal && community_modal->is_dismissed()) {
const CommunityCard* card = &COMMUNITY_DECK[last_drawn_community_idx]; const CommunityCard *card = &COMMUNITY_DECK[last_drawn_community_idx];
last_drawn_community_idx = -1; last_drawn_community_idx = -1;
delete active_modal; delete active_modal;
@@ -266,12 +318,16 @@ bool MonopolyGame::update(const InputEvent& event) {
p->balance += card->value; p->balance += card->value;
break; break;
case COMMUNITY_SPEND: case COMMUNITY_SPEND:
active_modal = new PaymentModalGame(width, height, renderer, gui, input_manager, p, nullptr, card->value, "COMMUNITY CHEST"); active_modal =
if (active_modal) active_modal->init(); new PaymentModalGame(width, height, renderer, gui, input_manager, p,
nullptr, card->value, "COMMUNITY CHEST");
if (active_modal)
active_modal->init();
break; break;
case COMMUNITY_ADVANCE: case COMMUNITY_ADVANCE:
p->position = card->value; p->position = card->value;
if (p->position < old_pos) p->balance += 200; if (p->position < old_pos)
p->balance += 200;
position_changed = true; position_changed = true;
break; break;
case COMMUNITY_JAIL: case COMMUNITY_JAIL:
@@ -300,10 +356,11 @@ bool MonopolyGame::update(const InputEvent& event) {
if (active_modal) { if (active_modal) {
active_modal->init(); active_modal->init();
} else if (position_changed) { } else if (position_changed) {
const BoardTile* landed = &MONOPOLY_BOARD[p->position]; const BoardTile *landed = &MONOPOLY_BOARD[p->position];
if (landed->type == TILE_PROPERTY || landed->type == TILE_RAILROAD || landed->type == TILE_UTILITY) { if (landed->type == TILE_PROPERTY || landed->type == TILE_RAILROAD ||
landed->type == TILE_UTILITY) {
bool is_owned = false; bool is_owned = false;
const char* owner_name = nullptr; const char *owner_name = nullptr;
int owner_id = -1; int owner_id = -1;
for (int i = 0; i < players_count; ++i) { for (int i = 0; i < players_count; ++i) {
for (int j = 0; j < players[i].property_count; ++j) { for (int j = 0; j < players[i].property_count; ++j) {
@@ -316,8 +373,12 @@ bool MonopolyGame::update(const InputEvent& event) {
} }
} }
bool can_afford = (p->balance >= landed->cost); 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); active_modal = new PropertyModalGame(
if (active_modal) active_modal->init(); 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()) { } else if (prop_modal && prop_modal->is_dismissed()) {
@@ -329,38 +390,49 @@ bool MonopolyGame::update(const InputEvent& event) {
active_modal = nullptr; active_modal = nullptr;
if (wants_buy) { if (wants_buy) {
const BoardTile* tile = &MONOPOLY_BOARD[p->position]; const BoardTile *tile = &MONOPOLY_BOARD[p->position];
if (p->balance >= tile->cost) { if (p->balance >= tile->cost) {
active_modal = new PaymentModalGame(width, height, renderer, gui, input_manager, p, nullptr, tile->cost, "BUY PROPERTY"); active_modal =
new PaymentModalGame(width, height, renderer, gui, input_manager,
p, nullptr, tile->cost, "BUY PROPERTY");
p->properties_owned[p->property_count++] = p->position; p->properties_owned[p->property_count++] = p->position;
} }
} else if (wants_rent) { } else if (wants_rent) {
const BoardTile* tile = &MONOPOLY_BOARD[p->position]; const BoardTile *tile = &MONOPOLY_BOARD[p->position];
int rent = 0; int rent = 0;
if (tile->type == TILE_PROPERTY) { if (tile->type == TILE_PROPERTY) {
rent = tile->rent[0]; rent = tile->rent[0];
} } else if (tile->type == TILE_RAILROAD) {
else if (tile->type == TILE_RAILROAD) {
int rr_count = 0; int rr_count = 0;
if (owner_id_from_modal != -1) { if (owner_id_from_modal != -1) {
for (int i = 0; i < players[owner_id_from_modal].property_count; ++i) { for (int i = 0; i < players[owner_id_from_modal].property_count;
if (MONOPOLY_BOARD[players[owner_id_from_modal].properties_owned[i]].type == TILE_RAILROAD) { ++i) {
if (MONOPOLY_BOARD[players[owner_id_from_modal]
.properties_owned[i]]
.type == TILE_RAILROAD) {
rr_count++; rr_count++;
} }
} }
} }
if (rr_count == 1) rent = 25; if (rr_count == 1)
else if (rr_count == 2) rent = 50; rent = 25;
else if (rr_count == 3) rent = 100; else if (rr_count == 2)
else if (rr_count == 4) rent = 200; rent = 50;
else rent = 25; else if (rr_count == 3)
} rent = 100;
else if (tile->type == TILE_UTILITY) { else if (rr_count == 4)
rent = 200;
else
rent = 25;
} else if (tile->type == TILE_UTILITY) {
int total_dice = last_dice1 + last_dice2; int total_dice = last_dice1 + last_dice2;
int utility_count = 0; int utility_count = 0;
if (owner_id_from_modal != -1) { if (owner_id_from_modal != -1) {
for (int i = 0; i < players[owner_id_from_modal].property_count; ++i) { for (int i = 0; i < players[owner_id_from_modal].property_count;
if (MONOPOLY_BOARD[players[owner_id_from_modal].properties_owned[i]].type == TILE_UTILITY) { ++i) {
if (MONOPOLY_BOARD[players[owner_id_from_modal]
.properties_owned[i]]
.type == TILE_UTILITY) {
utility_count++; utility_count++;
} }
} }
@@ -374,8 +446,11 @@ bool MonopolyGame::update(const InputEvent& event) {
rent *= rent_multiplier; rent *= rent_multiplier;
if (owner_id_from_modal != -1 && (int)current_player_idx != owner_id_from_modal) { if (owner_id_from_modal != -1 &&
active_modal = new PaymentModalGame(width, height, renderer, gui, input_manager, p, &players[owner_id_from_modal], rent, "RENT"); (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 // Reset multipliers
@@ -384,7 +459,8 @@ bool MonopolyGame::update(const InputEvent& event) {
needs_redraw = true; needs_redraw = true;
ModalButtonHelper::set_monopoly_regions(input_manager, width, height); ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
if (active_modal) active_modal->init(); if (active_modal)
active_modal->init();
} else if (board_modal && board_modal->is_dismissed()) { } else if (board_modal && board_modal->is_dismissed()) {
delete active_modal; delete active_modal;
active_modal = nullptr; active_modal = nullptr;
@@ -409,40 +485,56 @@ bool MonopolyGame::update(const InputEvent& event) {
needs_redraw = true; needs_redraw = true;
break; break;
case INPUT_BUTTON_1: case INPUT_BUTTON_1:
if (selected_action == -1) return false; if (selected_action == -1)
return false;
if (p->is_in_jail && !has_rolled && selected_action == 1) { 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"); active_modal =
if (active_modal) active_modal->init(); 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->is_in_jail = false;
p->jail_turns = 0; p->jail_turns = 0;
selected_action = -1; selected_action = -1;
needs_redraw = true; needs_redraw = true;
return true; return true;
} }
if (active_modal) delete active_modal; if (active_modal)
delete active_modal;
if (selected_action == (menu_count - 1)) { if (selected_action == (menu_count - 1)) {
active_modal = new BoardModalGame(width, height, renderer, gui, input_manager, players, players_count, current_player_idx); active_modal =
new BoardModalGame(width, height, renderer, gui, input_manager,
players, players_count, current_player_idx);
needs_redraw = true; needs_redraw = true;
} else if (!has_rolled) { } else if (!has_rolled) {
roll_dice_logic: roll_dice_logic:
int d1 = (rand() % 6) + 1; int d1 = (rand() % 6) + 1;
int d2 = (rand() % 6) + 1; int d2 = (rand() % 6) + 1;
bool is_db = (d1 == d2); bool is_db = (d1 == d2);
int old_pos = p->position; int old_pos = p->position;
if (p->is_in_jail) { if (p->is_in_jail) {
if (is_db) { if (is_db) {
p->is_in_jail = false; p->jail_turns = 0; p->is_in_jail = false;
p->jail_turns = 0;
} else { } else {
p->jail_turns++; p->jail_turns++;
if (p->jail_turns >= 3) { if (p->jail_turns >= 3) {
active_modal = new PaymentModalGame(width, height, renderer, gui, input_manager, p, nullptr, 50, "JAIL BAIL (FORCED)"); active_modal = new PaymentModalGame(width, height, renderer, gui,
if (active_modal) active_modal->init(); input_manager, p, nullptr, 50,
p->is_in_jail = false; p->jail_turns = 0; "JAIL BAIL (FORCED)");
if (active_modal)
active_modal->init();
p->is_in_jail = false;
p->jail_turns = 0;
} else { } else {
has_rolled = true; has_rolled = true;
last_dice1 = d1; last_dice2 = d2; last_dice1 = d1;
active_modal = new DiceModalGame(width, height, renderer, gui, input_manager, d1, d2, &MONOPOLY_BOARD[old_pos], &MONOPOLY_BOARD[old_pos], players, players_count); 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; needs_redraw = true;
return true; return true;
} }
@@ -450,10 +542,17 @@ roll_dice_logic:
} else if (is_db) { } else if (is_db) {
double_rolls++; double_rolls++;
if (double_rolls >= 3) { if (double_rolls >= 3) {
p->position = 10; p->is_in_jail = true; p->jail_turns = 0; p->position = 10;
has_rolled = true; double_rolls = 0; p->is_in_jail = true;
last_dice1 = d1; last_dice2 = d2; p->jail_turns = 0;
active_modal = new DiceModalGame(width, height, renderer, gui, input_manager, d1, d2, &MONOPOLY_BOARD[old_pos], &MONOPOLY_BOARD[10], players, players_count); 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; needs_redraw = true;
return true; return true;
} }
@@ -462,39 +561,60 @@ roll_dice_logic:
} }
int total = d1 + d2; int total = d1 + d2;
p->position = (p->position + total) % BOARD_SIZE; p->position = (p->position + total) % MONOPOLY_BOARD_SIZE;
if (p->position < old_pos) p->balance += 200; if (p->position < old_pos)
p->balance += 200;
has_rolled = !is_db; has_rolled = !is_db;
last_dice1 = d1; last_dice2 = d2; last_dice1 = d1;
active_modal = new DiceModalGame(width, height, renderer, gui, input_manager, d1, d2, &MONOPOLY_BOARD[old_pos], &MONOPOLY_BOARD[p->position], players, players_count); 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]; const BoardTile *lnd = &MONOPOLY_BOARD[p->position];
if (lnd->type == TILE_GO_TO_JAIL) { if (lnd->type == TILE_GO_TO_JAIL) {
p->position = 10; p->is_in_jail = true; p->jail_turns = 0; p->position = 10;
has_rolled = true; double_rolls = 0; p->is_in_jail = true;
} else if (lnd->type == TILE_PROPERTY || lnd->type == TILE_RAILROAD || lnd->type == TILE_UTILITY) { 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; modal_property_index = p->position;
} else if (lnd->type == TILE_CHANCE) { } else if (lnd->type == TILE_CHANCE) {
last_drawn_chance_idx = chance_deck[current_chance_idx]; last_drawn_chance_idx = chance_deck[current_chance_idx];
current_chance_idx = (current_chance_idx + 1) % CHANCE_DECK_SIZE; current_chance_idx = (current_chance_idx + 1) % CHANCE_DECK_SIZE;
if (current_chance_idx == 0) shuffle_chance_deck(); if (current_chance_idx == 0)
shuffle_chance_deck();
} else if (lnd->type == TILE_COMMUNITY_CHEST) { } else if (lnd->type == TILE_COMMUNITY_CHEST) {
last_drawn_community_idx = community_deck[current_community_idx]; last_drawn_community_idx = community_deck[current_community_idx];
current_community_idx = (current_community_idx + 1) % COMMUNITY_DECK_SIZE; current_community_idx =
if (current_community_idx == 0) shuffle_community_deck(); (current_community_idx + 1) % COMMUNITY_DECK_SIZE;
if (current_community_idx == 0)
shuffle_community_deck();
} else if (lnd->type == TILE_TAX) { } else if (lnd->type == TILE_TAX) {
active_modal = new PaymentModalGame(width, height, renderer, gui, input_manager, p, nullptr, lnd->cost, "TAXES"); active_modal =
if (active_modal) active_modal->init(); new PaymentModalGame(width, height, renderer, gui, input_manager, p,
nullptr, lnd->cost, "TAXES");
if (active_modal)
active_modal->init();
} }
needs_redraw = true; needs_redraw = true;
} else { } else {
current_player_idx = (current_player_idx + 1) % players_count; current_player_idx = (current_player_idx + 1) % players_count;
has_rolled = false; double_rolls = 0; just_sent_to_jail = false; selected_action = -1; has_rolled = false;
active_modal = new TurnModalGame(width, height, renderer, gui, input_manager, &players[current_player_idx]); 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; needs_redraw = true;
} }
break; break;
default: break; default:
break;
} }
return needs_redraw; return needs_redraw;
} }
@@ -509,11 +629,12 @@ void MonopolyGame::draw() {
renderer->clear_buffer(); renderer->clear_buffer();
Player* p = &players[current_player_idx]; Player *p = &players[current_player_idx];
const BoardTile* tile = &MONOPOLY_BOARD[p->position]; const BoardTile *tile = &MONOPOLY_BOARD[p->position];
// --- Draw Board Perimeter --- // --- Draw Board Perimeter ---
MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players, players_count, p->position); MonopolyBoardRenderer::draw_board_perimeter(renderer, width, height, players,
players_count, p->position);
// --- Inner Dashboard (Center Area) --- // --- Inner Dashboard (Center Area) ---
int cw = width / 7; int cw = width / 7;
@@ -531,10 +652,12 @@ void MonopolyGame::draw() {
renderer->draw_filled_rectangle(ix + 4, iy + 4, iw - 8, 35, true, 1); renderer->draw_filled_rectangle(ix + 4, iy + 4, iw - 8, 35, true, 1);
renderer->set_text_color(false); // White text renderer->set_text_color(false); // White text
snprintf(buf, sizeof(buf), "%s'S TURN", p->name); 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->draw_string_scaled(ix + (iw - (int)strlen(buf) * 12) / 2, iy + 12,
buf, 2);
renderer->set_text_color(true); renderer->set_text_color(true);
renderer->draw_string_scaled(ix + (iw - 8 * 18) / 2, iy + ih - 35, "Monopoly", 3); renderer->draw_string_scaled(ix + (iw - 8 * 18) / 2, iy + ih - 35, "Monopoly",
3);
int content_y = iy + 50; int content_y = iy + 50;
@@ -547,14 +670,20 @@ void MonopolyGame::draw() {
content_y += 20; content_y += 20;
// Draw special tile sprite // Draw special tile sprite
const unsigned char* sprite = nullptr; const unsigned char *sprite = nullptr;
if (tile->type == TILE_COMMUNITY_CHEST) sprite = epd_bitmap_CommunityChest; if (tile->type == TILE_COMMUNITY_CHEST)
else if (tile->type == TILE_CHANCE) sprite = epd_bitmap_Chance; sprite = epd_bitmap_CommunityChest;
else if (tile->type == TILE_FREE_PARKING) sprite = epd_bitmap_FreeParking; else if (tile->type == TILE_CHANCE)
else if (tile->type == TILE_GO_TO_JAIL) sprite = epd_bitmap_GoToJail; 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) { else if (tile->type == TILE_UTILITY) {
if (strstr(tile->name, "Electric")) sprite = epd_bitmap_ElectricCompany; if (strstr(tile->name, "Electric"))
else if (strstr(tile->name, "Water")) sprite = epd_bitmap_WaterWorks; sprite = epd_bitmap_ElectricCompany;
else if (strstr(tile->name, "Water"))
sprite = epd_bitmap_WaterWorks;
} }
if (sprite) { if (sprite) {
@@ -566,18 +695,20 @@ void MonopolyGame::draw() {
renderer->draw_line(ix + 10, content_y, ix + iw - 10, content_y, true); renderer->draw_line(ix + 10, content_y, ix + iw - 10, content_y, true);
content_y += 15; content_y += 15;
// Draw action menu // Draw action menu
const char* actions[3]; const char *actions[3];
int menu_count = 0; int menu_count = 0;
if (!has_rolled) { if (!has_rolled) {
actions[menu_count++] = "Roll Dice"; actions[menu_count++] = "Roll Dice";
if (p->is_in_jail) actions[menu_count++] = "Pay $50"; if (p->is_in_jail)
actions[menu_count++] = "Pay $50";
} else { } else {
actions[menu_count++] = "End Turn"; actions[menu_count++] = "End Turn";
} }
actions[menu_count++] = "View Board"; actions[menu_count++] = "View Board";
for (int i = 0; i < menu_count; ++i) { for (int i = 0; i < menu_count; ++i) {
snprintf(buf, sizeof(buf), "%s%s", (i == selected_action) ? "> " : " ", actions[i]); snprintf(buf, sizeof(buf), "%s%s", (i == selected_action) ? "> " : " ",
actions[i]);
renderer->draw_string_scaled(ix + 15, content_y, buf, 2); renderer->draw_string_scaled(ix + 15, content_y, buf, 2);
content_y += 25; content_y += 25;
} }