Fix emulator compilation and crash, and implement Monopoly payment modal

This commit is contained in:
Adolfo Reyna
2026-02-06 23:13:32 -05:00
parent 75e17fb26b
commit 64f61759d7
10 changed files with 309 additions and 66 deletions

View File

@@ -306,8 +306,8 @@ int main()
// Initialize renderer and GUI system // Initialize renderer and GUI system
LowLevelRenderer renderer(bit_buffer, V_WIDTH, V_HEIGHT); LowLevelRenderer renderer(bit_buffer, V_WIDTH, V_HEIGHT);
renderer.set_font(&font_5x5_obj); renderer.set_font(&font_homespun_obj);
LowLevelGUI gui = LowLevelGUI(&renderer, font_BMplain_obj); LowLevelGUI gui = LowLevelGUI(&renderer, font_homespun_obj);
// Initialize touch screen using abstraction FIRST (before InputManager needs it) // Initialize touch screen using abstraction FIRST (before InputManager needs it)
touch = LowLevelTouch::create((TouchType)TOUCH_TYPE_SELECTED, V_WIDTH, V_HEIGHT, touch = LowLevelTouch::create((TouchType)TOUCH_TYPE_SELECTED, V_WIDTH, V_HEIGHT,
@@ -353,7 +353,9 @@ int main()
launcher.register_game("Monopoly", "Classic property trading game", launcher.register_game("Monopoly", "Classic property trading game",
[](uint16_t w, uint16_t h, LowLevelRenderer* r, LowLevelGUI* g, InputManager* im) -> Game* { [](uint16_t w, uint16_t h, LowLevelRenderer* r, LowLevelGUI* g, InputManager* im) -> Game* {
return new MonopolyGame(w, h, r, g, im); // For Feather TFT (480x320), reduce width to 430 to make room for sidebar buttons
uint16_t game_w = (w == 480) ? 430 : w;
return new MonopolyGame(game_w, h, r, g, im);
}); });
launcher.register_game("Demo Game", "Simple test game", launcher.register_game("Demo Game", "Simple test game",

View File

@@ -8,11 +8,11 @@ CXXFLAGS = -std=c++17 -Wall
# Paths for Homebrew on macOS (Silicon/M1/M2/M3) # Paths for Homebrew on macOS (Silicon/M1/M2/M3)
ifeq ($(OS), Darwin) ifeq ($(OS), Darwin)
SFML_DIR = $(shell brew --prefix sfml@2) SFML_DIR = $(shell brew --prefix sfml@2)
INCLUDES = -I. -I$(SFML_DIR)/include -I../display -I../fonts -I../games INCLUDES = -I. -I.. -I$(SFML_DIR)/include -I../display -I../fonts -I../games
LIBS = -L$(SFML_DIR)/lib -lsfml-graphics -lsfml-window -lsfml-system LIBS = -L$(SFML_DIR)/lib -lsfml-graphics -lsfml-window -lsfml-system
else else
# Standard Linux paths # Standard Linux paths
INCLUDES = -I. -I../display -I../fonts -I../games INCLUDES = -I. -I.. -I../display -I../fonts -I../games
LIBS = -lsfml-graphics -lsfml-window -lsfml-system LIBS = -lsfml-graphics -lsfml-window -lsfml-system
endif endif

Binary file not shown.

View File

@@ -1,6 +1,56 @@
#pragma once #ifndef INPUT_MANAGER_H
#define INPUT_MANAGER_H
#include <stdint.h>
#include "input_event.h"
// Minimal stub for emulator build // Minimal stub for emulator build
class InputManager { class InputManager {
public: public:
bool has_buttons() const { return false; } bool has_buttons() const { return false; }
bool has_touch() const { return false; }
void get_virtual_button_regions(int* a_rect, int* b_rect) const {
for (int i = 0; i < 4; i++) {
a_rect[i] = v_button_a[i];
b_rect[i] = v_button_b[i];
}
}
void set_virtual_button_regions(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) {
v_button_a[0] = ax; v_button_a[1] = ay; v_button_a[2] = aw; v_button_a[3] = ah;
v_button_b[0] = bx; v_button_b[1] = by; v_button_b[2] = bw; v_button_b[3] = bh;
v_buttons_active = true;
}
void clear_virtual_button_regions() {
v_buttons_active = false;
for (int i = 0; i < 4; i++) {
v_button_a[i] = 0;
v_button_b[i] = 0;
}
}
bool check_virtual_buttons(int16_t x, int16_t y, InputType& out_type) const {
if (!v_buttons_active) return false;
if (x >= v_button_a[0] && x <= v_button_a[0] + v_button_a[2] &&
y >= v_button_a[1] && y <= v_button_a[1] + v_button_a[3]) {
out_type = INPUT_BUTTON_0;
return true;
}
if (x >= v_button_b[0] && x <= v_button_b[0] + v_button_b[2] &&
y >= v_button_b[1] && y <= v_button_b[1] + v_button_b[3]) {
out_type = INPUT_BUTTON_1;
return true;
}
return false;
}
private:
int v_button_a[4] = {0, 0, 0, 0};
int v_button_b[4] = {0, 0, 0, 0};
bool v_buttons_active = false;
}; };
#endif

View File

@@ -64,6 +64,12 @@ int main() {
event.x = sfEvent.mouseButton.x; event.x = sfEvent.mouseButton.x;
event.y = sfEvent.mouseButton.y; event.y = sfEvent.mouseButton.y;
event.valid = true; event.valid = true;
// Check for virtual buttons
InputType virtual_type;
if (input_manager.check_virtual_buttons(event.x, event.y, virtual_type)) {
event.type = virtual_type;
}
} else if (sfEvent.type == sf::Event::KeyPressed) { } else if (sfEvent.type == sf::Event::KeyPressed) {
if (sfEvent.key.code == sf::Keyboard::Space) { if (sfEvent.key.code == sf::Keyboard::Space) {
event.type = INPUT_BUTTON_0; event.type = INPUT_BUTTON_0;

View File

@@ -104,10 +104,10 @@ public:
char move_buf[64]; char move_buf[64];
if (from_tile && to_tile) { if (from_tile && to_tile) {
snprintf(move_buf, sizeof(move_buf), "FROM: %s", from_tile->name); snprintf(move_buf, sizeof(move_buf), "FROM: %s", from_tile->name);
renderer->draw_string_scaled(ix + 10, info_y, move_buf, 1); renderer->draw_string_scaled(ix + 10, info_y, move_buf, 2);
info_y += 12; info_y += 24;
snprintf(move_buf, sizeof(move_buf), "TO: %s", to_tile->name); snprintf(move_buf, sizeof(move_buf), "TO: %s", to_tile->name);
renderer->draw_string_scaled(ix + 10, info_y, move_buf, 1); renderer->draw_string_scaled(ix + 10, info_y, move_buf, 2);
} }
// Button // Button

View File

@@ -11,23 +11,32 @@ public:
static void set_monopoly_regions(InputManager* input_manager, uint16_t width, uint16_t height) { static void set_monopoly_regions(InputManager* input_manager, uint16_t width, uint16_t height) {
if (!input_manager) return; if (!input_manager) return;
// --- BUTTON CONFIGURATION --- if (width < 480) {
// Adjust these variables to move the virtual buttons easily // Sidebar mode for 480x320 screen (Buttons at 400-480)
int btn_w = 60; int sidebar_x = width;
int btn_h = 60; int sidebar_w = 480 - width;
int margin_right = 135; // Positioned for the inner board area (W - 135 = 345) int btn_h = height / 2;
int start_y = 80; // Vertical start position input_manager->set_virtual_button_regions(
int spacing = 30; // Gap between buttons sidebar_x, 0, sidebar_w, btn_h, // Button A (Top half)
sidebar_x, btn_h, sidebar_w, btn_h // Button B (Bottom half)
int btn_x = width - margin_right; );
int btn_a_y = start_y; } else {
int btn_b_y = btn_a_y + btn_h + spacing; // Inner dashboard mode (fallback)
int btn_w = 60;
int btn_h = 60;
int margin_right = 135; // Positioned for the inner board area (W - 135 = 345)
int start_y = 80; // Vertical start position
int spacing = 30; // Gap between buttons
int btn_x = width - margin_right;
int btn_a_y = start_y;
int btn_b_y = btn_a_y + btn_h + spacing;
// Apply regions to input manager input_manager->set_virtual_button_regions(
input_manager->set_virtual_button_regions( btn_x, btn_a_y, btn_w, btn_h,
btn_x, btn_a_y, btn_w, btn_h, // Button A (Top) btn_x, btn_b_y, btn_w, btn_h
btn_x, btn_b_y, btn_w, btn_h // Button B (Bottom) );
); }
} }
/** /**
@@ -42,17 +51,20 @@ public:
// Save current color // Save current color
bool original_color = renderer->get_current_text_color(); bool original_color = renderer->get_current_text_color();
// Draw Button A (Top) // Draw Button A
renderer->draw_filled_rectangle(a[0], a[1], a[2], a[3], false, 0); // White back renderer->draw_filled_rectangle(a[0], a[1], a[2], a[3], false, 0); // White back
renderer->draw_rectangle(a[0], a[1], a[2], a[3], true, 2); // Black border renderer->draw_rectangle(a[0], a[1], a[2], a[3], true, 2); // Black border
renderer->set_text_color(true); renderer->set_text_color(true);
renderer->draw_string_scaled(a[0] + (a[2] - 12) / 2, a[1] + (a[3] - 16) / 2, "A", 2); // Use larger font scaling if buttons are big (sidebar mode)
int scale_a = (a[3] > 100) ? 4 : 2;
renderer->draw_string_scaled(a[0] + (a[2] - 6 * scale_a) / 2, a[1] + (a[3] - 8 * scale_a) / 2, "A", scale_a);
// Draw Button B (Under A) // Draw Button B
renderer->draw_filled_rectangle(b[0], b[1], b[2], b[3], false, 0); // White back renderer->draw_filled_rectangle(b[0], b[1], b[2], b[3], false, 0); // White back
renderer->draw_rectangle(b[0], b[1], b[2], b[3], true, 2); // Black border renderer->draw_rectangle(b[0], b[1], b[2], b[3], true, 2); // Black border
renderer->set_text_color(true); renderer->set_text_color(true);
renderer->draw_string_scaled(b[0] + (b[2] - 12) / 2, b[1] + (b[3] - 16) / 2, "B", 2); int scale_b = (b[3] > 100) ? 4 : 2;
renderer->draw_string_scaled(b[0] + (b[2] - 6 * scale_b) / 2, b[1] + (b[3] - 8 * scale_b) / 2, "B", scale_b);
// Restore color // Restore color
renderer->set_text_color(original_color); renderer->set_text_color(original_color);

View File

@@ -0,0 +1,159 @@
// PaymentModalGame.h
#pragma once
#include "../../lib/game.h"
#include "../../display/low_level_render.h"
#include "../../display/low_level_gui.h"
#include "input_manager.h"
#include "player.h"
#include "MonopolyBoardRenderer.h"
#include "ModalButtonHelper.h"
#include <stdlib.h>
#include <stdio.h>
class PaymentModalGame : public Game {
Player* payer;
Player* recipient; // nullptr if Bank
int amount;
int options[3];
bool option_visible[3];
int correct_answer;
int selected_choice;
bool dismissed;
const char* reason;
bool show_error;
public:
PaymentModalGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager,
Player* p, Player* r, int amt, const char* reas)
: Game(width, height, renderer, gui, input_manager), payer(p), recipient(r), amount(amt), reason(reas),
selected_choice(-1), dismissed(false), show_error(false) {
correct_answer = payer->balance - amount;
for (int i = 0; i < 3; i++) option_visible[i] = true;
// Generate two fake answers
int fake1 = correct_answer + (rand() % 4 + 1) * 10;
int fake2 = correct_answer - (rand() % 4 + 1) * 10;
if (fake2 < 0 && correct_answer > 10) fake2 = correct_answer - 5;
if (fake2 == correct_answer || fake2 == fake1) fake2 = fake1 + 10;
int rand_pos = rand() % 3;
if (rand_pos == 0) {
options[0] = correct_answer;
options[1] = fake1;
options[2] = fake2;
} else if (rand_pos == 1) {
options[0] = fake1;
options[1] = correct_answer;
options[2] = fake2;
} else {
options[0] = fake1;
options[1] = fake2;
options[2] = correct_answer;
}
}
void init() override {
dismissed = false;
selected_choice = -1;
show_error = false;
for (int i = 0; i < 3; i++) option_visible[i] = true;
ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
}
Type get_type() const override { return Type::MONOPOLY_PAYMENT; }
bool update(const InputEvent& event) override {
if (event.type == INPUT_BUTTON_0) { // Select
// Find next visible option
do {
selected_choice = (selected_choice + 1) % 3;
} while (!option_visible[selected_choice]);
show_error = false;
return true;
}
if (event.type == INPUT_BUTTON_1) { // Execute
if (selected_choice == -1) return false;
if (!option_visible[selected_choice]) return false;
if (options[selected_choice] == correct_answer) {
payer->balance -= amount;
if (recipient) recipient->balance += amount;
dismissed = true;
} else {
option_visible[selected_choice] = false;
show_error = true;
// De-select the hidden option
selected_choice = -1;
}
return true;
}
return false;
}
void draw() override {
renderer->clear_buffer();
// Draw board background if possible (simplified here)
int win_w = width - 2 * (width / 8);
int win_h = height - 2 * (height / 8);
int win_x = (width - win_w) / 2;
int win_y = (height - win_h) / 2;
renderer->draw_filled_rectangle(win_x, win_y, win_w, win_h, false, 0);
renderer->draw_rectangle(win_x, win_y, win_w, win_h, true, 2);
renderer->draw_rectangle(win_x + 3, win_y + 3, win_w - 6, win_h - 6, true, 1);
// Header
renderer->draw_filled_rectangle(win_x + 4, win_y + 4, win_w - 8, 35, true, 1);
renderer->set_text_color(false);
renderer->draw_string_scaled(win_x + (win_w - 12 * 10) / 2, win_y + 10, "PAYMENT DUE", 2);
renderer->set_text_color(true);
char buf[128];
int content_y = win_y + 50;
snprintf(buf, sizeof(buf), "Paying: $%d from $%d", amount, payer->balance);
renderer->draw_string_scaled(win_x + 20, content_y, buf, 2);
content_y += 25;
snprintf(buf, sizeof(buf), "To: %s", recipient ? recipient->name : "The Bank");
renderer->draw_string_scaled(win_x + 20, content_y, buf, 2);
content_y += 25;
snprintf(buf, sizeof(buf), "Reason: %s", reason);
renderer->draw_string_scaled(win_x + 20, content_y, buf, 1);
content_y += 30;
renderer->draw_line(win_x + 10, content_y, win_x + win_w - 10, content_y, true);
content_y += 15;
renderer->draw_string_scaled(win_x + 20, content_y, "What is your new balance?", 1);
content_y += 25;
// Options
for (int i = 0; i < 3; i++) {
if (!option_visible[i]) {
content_y += 25;
continue;
}
snprintf(buf, sizeof(buf), "%s $%d", (selected_choice == i ? ">" : " "), options[i]);
if (selected_choice == i) renderer->draw_filled_rectangle(win_x + 15, content_y - 2, 120, 22, true, 1);
if (selected_choice == i) renderer->set_text_color(false);
renderer->draw_string_scaled(win_x + 20, content_y, buf, 2);
renderer->set_text_color(true);
content_y += 25;
}
if (show_error) {
renderer->set_text_color(true);
renderer->draw_string_scaled(win_x + 20, content_y + 10, "TRY AGAIN!", 2);
}
ModalButtonHelper::draw_virtual_buttons(renderer, input_manager);
}
bool is_dismissed() const { return dismissed; }
};

View File

@@ -23,6 +23,7 @@ extern "C" {
#include "ChanceModalGame.h" #include "ChanceModalGame.h"
#include "CommunityChestModalGame.h" #include "CommunityChestModalGame.h"
#include "TurnModalGame.h" #include "TurnModalGame.h"
#include "PaymentModalGame.h"
#include "ModalButtonHelper.h" #include "ModalButtonHelper.h"
#include "sprites.h" #include "sprites.h"
#include "MonopolyBoardRenderer.h" #include "MonopolyBoardRenderer.h"
@@ -55,6 +56,7 @@ 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);
if (active_modal) { delete active_modal; active_modal = nullptr; } if (active_modal) { delete active_modal; active_modal = nullptr; }
active_modal = new TurnModalGame(width, height, renderer, gui, input_manager, &players[current_player_idx]); 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.
@@ -113,6 +115,16 @@ bool MonopolyGame::update(const InputEvent& event) {
ChanceModalGame* chance_modal = (active_modal->get_type() == Game::Type::MONOPOLY_CHANCE) ? static_cast<ChanceModalGame*>(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; 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; 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()) { if (dice_modal && dice_modal->is_dismissed()) {
delete active_modal; delete active_modal;
@@ -165,7 +177,8 @@ bool MonopolyGame::update(const InputEvent& event) {
p->balance += card->value; p->balance += card->value;
break; break;
case CHANCE_SPEND: case CHANCE_SPEND:
p->balance -= card->value; active_modal = 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;
@@ -211,12 +224,12 @@ bool MonopolyGame::update(const InputEvent& event) {
break; break;
} }
delete active_modal;
active_modal = nullptr;
needs_redraw = true; needs_redraw = true;
ModalButtonHelper::set_monopoly_regions(input_manager, width, height); ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
if (position_changed) { if (active_modal) {
active_modal->init();
} 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) {
@@ -250,7 +263,8 @@ bool MonopolyGame::update(const InputEvent& event) {
p->balance += card->value; p->balance += card->value;
break; break;
case COMMUNITY_SPEND: case COMMUNITY_SPEND:
p->balance -= card->value; active_modal = 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;
@@ -277,12 +291,12 @@ bool MonopolyGame::update(const InputEvent& event) {
break; break;
} }
delete active_modal;
active_modal = nullptr;
needs_redraw = true; needs_redraw = true;
ModalButtonHelper::set_monopoly_regions(input_manager, width, height); ModalButtonHelper::set_monopoly_regions(input_manager, width, height);
if (position_changed) { if (active_modal) {
active_modal->init();
} 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;
@@ -304,28 +318,30 @@ bool MonopolyGame::update(const InputEvent& event) {
} }
} }
} else if (prop_modal && prop_modal->is_dismissed()) { } else if (prop_modal && prop_modal->is_dismissed()) {
if (prop_modal->wants_to_buy()) { 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]; const BoardTile* tile = &MONOPOLY_BOARD[p->position];
if (p->balance >= tile->cost) { if (p->balance >= tile->cost) {
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; p->properties_owned[p->property_count++] = p->position;
} }
} else if (prop_modal->wants_to_pay_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) {
// Logic for rent: If owner has all properties of group, rent is doubled (base only)
// For now, let's just use rent[0] as requested, but we should probably eventually
// check for houses. Let's stick to rent[0] to match the modal's display.
rent = tile->rent[0]; rent = tile->rent[0];
} }
else if (tile->type == TILE_RAILROAD) { else if (tile->type == TILE_RAILROAD) {
// Utility logic for Railroads: 1:25, 2:50, 3:100, 4:200
int owner_id = prop_modal->get_owner_id();
int rr_count = 0; int rr_count = 0;
if (owner_id != -1) { if (owner_id_from_modal != -1) {
for (int i = 0; i < players[owner_id].property_count; ++i) { for (int i = 0; i < players[owner_id_from_modal].property_count; ++i) {
if (MONOPOLY_BOARD[players[owner_id].properties_owned[i]].type == TILE_RAILROAD) { if (MONOPOLY_BOARD[players[owner_id_from_modal].properties_owned[i]].type == TILE_RAILROAD) {
rr_count++; rr_count++;
} }
} }
@@ -334,18 +350,14 @@ bool MonopolyGame::update(const InputEvent& event) {
else if (rr_count == 2) rent = 50; else if (rr_count == 2) rent = 50;
else if (rr_count == 3) rent = 100; else if (rr_count == 3) rent = 100;
else if (rr_count == 4) rent = 200; else if (rr_count == 4) rent = 200;
else rent = 25; // Fallback else rent = 25;
} }
else if (tile->type == TILE_UTILITY) { else if (tile->type == TILE_UTILITY) {
// Utility: 4x dice if 1 owned, 10x if both.
// Since we don't have the dice roll here, let's use a fixed 40 for now
// or calculate it from last_dice1 + last_dice2.
int total_dice = last_dice1 + last_dice2; int total_dice = last_dice1 + last_dice2;
int owner_id = prop_modal->get_owner_id();
int utility_count = 0; int utility_count = 0;
if (owner_id != -1) { if (owner_id_from_modal != -1) {
for (int i = 0; i < players[owner_id].property_count; ++i) { for (int i = 0; i < players[owner_id_from_modal].property_count; ++i) {
if (MONOPOLY_BOARD[players[owner_id].properties_owned[i]].type == TILE_UTILITY) { if (MONOPOLY_BOARD[players[owner_id_from_modal].properties_owned[i]].type == TILE_UTILITY) {
utility_count++; utility_count++;
} }
} }
@@ -359,20 +371,17 @@ bool MonopolyGame::update(const InputEvent& event) {
rent *= rent_multiplier; rent *= rent_multiplier;
int o_id = prop_modal->get_owner_id(); if (owner_id_from_modal != -1 && (int)current_player_idx != owner_id_from_modal) {
if (o_id != -1 && (int)current_player_idx != o_id) { active_modal = new PaymentModalGame(width, height, renderer, gui, input_manager, p, &players[owner_id_from_modal], rent, "RENT");
p->balance -= rent;
players[o_id].balance += rent;
} }
} }
// Reset multipliers // Reset multipliers
rent_multiplier = 1; rent_multiplier = 1;
force_utility_10x = false; force_utility_10x = false;
delete active_modal;
active_modal = nullptr;
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();
} 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;
@@ -400,7 +409,8 @@ bool MonopolyGame::update(const InputEvent& event) {
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) {
p->balance -= 50; 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->is_in_jail = false;
p->jail_turns = 0; p->jail_turns = 0;
selected_action = -1; selected_action = -1;
@@ -423,7 +433,9 @@ roll_dice_logic:
} else { } else {
p->jail_turns++; p->jail_turns++;
if (p->jail_turns >= 3) { if (p->jail_turns >= 3) {
p->balance -= 50; p->is_in_jail = false; p->jail_turns = 0; 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 { } else {
has_rolled = true; has_rolled = true;
last_dice1 = d1; last_dice2 = d2; last_dice1 = d1; last_dice2 = d2;
@@ -468,7 +480,8 @@ roll_dice_logic:
current_community_idx = (current_community_idx + 1) % COMMUNITY_DECK_SIZE; current_community_idx = (current_community_idx + 1) % COMMUNITY_DECK_SIZE;
if (current_community_idx == 0) shuffle_community_deck(); if (current_community_idx == 0) shuffle_community_deck();
} else if (lnd->type == TILE_TAX) { } else if (lnd->type == TILE_TAX) {
p->balance -= lnd->cost; active_modal = 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 {

View File

@@ -35,7 +35,8 @@ public:
MONOPOLY_BOARD, MONOPOLY_BOARD,
MONOPOLY_CHANCE, MONOPOLY_CHANCE,
MONOPOLY_COMMUNITY_CHEST, MONOPOLY_COMMUNITY_CHEST,
MONOPOLY_TURN MONOPOLY_TURN,
MONOPOLY_PAYMENT
}; };
/** /**