interpreting monopoly as multi scree game
This commit is contained in:
@@ -1,155 +0,0 @@
|
|||||||
Multigame Migration Plan
|
|
||||||
Overview
|
|
||||||
Refactor the existing monolithic tic-tac-toe implementation into a modular game architecture that allows multiple games to run on the RP2350 platform while preserving the interrupt-driven, dual-core reactive architecture.
|
|
||||||
|
|
||||||
Goals
|
|
||||||
Abstract game logic from hardware/display management
|
|
||||||
Create reusable input processing system
|
|
||||||
Enable multiple games to coexist in the codebase
|
|
||||||
Maintain the efficient reactive architecture (event-driven, dual-core)
|
|
||||||
Keep hardware-specific code isolated in basic1.cpp
|
|
||||||
Architecture Components
|
|
||||||
1. Input Event System
|
|
||||||
Files: lib/input_event.h
|
|
||||||
|
|
||||||
Defines shared input event structures used by both InputManager and Game classes:
|
|
||||||
|
|
||||||
InputType enum (NONE, TOUCH_DOWN, TOUCH_MOVE, TOUCH_UP, BUTTON_0, BUTTON_1, GESTURE)
|
|
||||||
InputEvent struct with coordinates, gesture codes, button IDs, pressure, validity flag
|
|
||||||
2. Input Manager
|
|
||||||
Files: lib/input_manager.h, lib/input_manager.cpp
|
|
||||||
|
|
||||||
Handles all input processing and debouncing:
|
|
||||||
|
|
||||||
Constructor: InputManager(LowLevelTouch* touch, GameConfig* config)
|
|
||||||
Methods: process_touch_input(uint32_t* last_time), process_button_input()
|
|
||||||
Returns InputEvent objects to be passed to games
|
|
||||||
Manages touch debouncing and gesture recognition
|
|
||||||
Does NOT handle button GPIO setup (stays in basic1.cpp)
|
|
||||||
3. Abstract Game Base Class
|
|
||||||
Files: lib/game.h
|
|
||||||
|
|
||||||
Defines the interface all games must implement:
|
|
||||||
|
|
||||||
Constructor: Game(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui)
|
|
||||||
Protected members: width, height, renderer, gui
|
|
||||||
Pure virtual methods:
|
|
||||||
virtual void init() = 0 - Initialize game state
|
|
||||||
virtual bool update(const InputEvent& event) = 0 - Process input, return true if redraw needed
|
|
||||||
virtual void draw() = 0 - Render game to buffer
|
|
||||||
Virtual destructor: virtual ~Game() {}
|
|
||||||
4. Tic-Tac-Toe Game Implementation
|
|
||||||
Files: games/tic_tac_toe.h, games/tic_tac_toe.cpp
|
|
||||||
|
|
||||||
Concrete implementation of the Game interface:
|
|
||||||
|
|
||||||
Private GameState struct with board, current player, winner, statistics
|
|
||||||
Private method: check_winner()
|
|
||||||
Private constants: BOARD_SIZE, CELL_SIZE, BOARD_Y, LINE_WIDTH
|
|
||||||
Overrides: init(), update(const InputEvent& event), draw()
|
|
||||||
Encapsulates all tic-tac-toe logic extracted from basic1.cpp lines 162-770
|
|
||||||
5. Main Loop Refactor
|
|
||||||
File: basic1.cpp
|
|
||||||
|
|
||||||
Simplified main program focusing on hardware management:
|
|
||||||
|
|
||||||
Keep: Display initialization, dual-core setup, interrupt handlers, GPIO configuration
|
|
||||||
Remove: Game-specific logic (moves to TicTacToeGame)
|
|
||||||
Add: InputManager instantiation, Game* pointer instantiation
|
|
||||||
Modify main loop:
|
|
||||||
Migration Steps
|
|
||||||
Step 1: Create Input Event Header
|
|
||||||
Extract input structures from basic1.cpp (lines 134-156) to new file lib/input_event.h.
|
|
||||||
|
|
||||||
Validation:
|
|
||||||
|
|
||||||
Compile successfully
|
|
||||||
No duplicate definitions
|
|
||||||
Both basic1.cpp and new files include this header
|
|
||||||
Step 2: Create Input Manager
|
|
||||||
Move input processing functions (lines 313-442) to new InputManager class.
|
|
||||||
|
|
||||||
Validation:
|
|
||||||
|
|
||||||
Constructor properly stores touch pointer and config
|
|
||||||
process_touch_input() returns valid InputEvent on touch
|
|
||||||
process_button_input() returns valid InputEvent on button press
|
|
||||||
Debouncing still works correctly
|
|
||||||
Compile and run - verify touch/button detection unchanged
|
|
||||||
Step 3: Create Abstract Game Class
|
|
||||||
Create lib/game.h with base class definition.
|
|
||||||
|
|
||||||
Validation:
|
|
||||||
|
|
||||||
Header compiles successfully
|
|
||||||
Pure virtual methods defined correctly
|
|
||||||
Protected members accessible to derived classes
|
|
||||||
Step 4: Extract Tic-Tac-Toe Game
|
|
||||||
Create TicTacToeGame class inheriting from Game.
|
|
||||||
|
|
||||||
Validation:
|
|
||||||
|
|
||||||
Move GameState struct (lines 162-176) - verify all members present
|
|
||||||
Move check_winner() (lines 447-495) - verify logic identical
|
|
||||||
Move game_init() to init() override (lines 505-522)
|
|
||||||
Move game_update() to update() override (lines 536-668)
|
|
||||||
Move game_draw() to draw() override (lines 671-770)
|
|
||||||
Move constants: BOARD_SIZE, CELL_SIZE, BOARD_Y
|
|
||||||
Compile successfully
|
|
||||||
Step 5: Refactor Main Loop
|
|
||||||
Update basic1.cpp to use new architecture.
|
|
||||||
|
|
||||||
Validation:
|
|
||||||
|
|
||||||
Remove old GameState state variable
|
|
||||||
Remove old game functions
|
|
||||||
Instantiate InputManager after hardware init
|
|
||||||
Instantiate TicTacToeGame as Game*
|
|
||||||
Update main loop to use polymorphic calls
|
|
||||||
Compile successfully
|
|
||||||
Run and verify: Touch input works, buttons work, game plays correctly
|
|
||||||
Verify dual-core refresh still works (Core 1 handles display)
|
|
||||||
Test full game: place pieces, win conditions, restart
|
|
||||||
Step 6: Update Build System
|
|
||||||
Modify CMakeLists.txt to include new source files.
|
|
||||||
|
|
||||||
Validation:
|
|
||||||
|
|
||||||
Add lib/input_manager.cpp
|
|
||||||
Add games/tic_tac_toe.cpp
|
|
||||||
Clean build succeeds
|
|
||||||
Binary size reasonable (no major bloat)
|
|
||||||
Step 7: Final Testing
|
|
||||||
Comprehensive system test.
|
|
||||||
|
|
||||||
Validation:
|
|
||||||
|
|
||||||
Touch detection works (tap cells)
|
|
||||||
Button navigation works (KEY0/KEY1)
|
|
||||||
Game logic correct (wins, ties, restart)
|
|
||||||
Display refreshes properly (no artifacts)
|
|
||||||
Statistics persist across games
|
|
||||||
Debug output shows correct events
|
|
||||||
System remains responsive during e-ink refresh
|
|
||||||
Future Extensions
|
|
||||||
Adding New Games
|
|
||||||
To add a new game (e.g., Snake, Pong):
|
|
||||||
|
|
||||||
Create games/snake.h and games/snake.cpp
|
|
||||||
Inherit from Game base class
|
|
||||||
Implement init(), update(), draw()
|
|
||||||
Define game-specific state as private members
|
|
||||||
Add to CMakeLists.txt
|
|
||||||
Change game selection in basic1.cpp: Game* current_game = new SnakeGame(...)
|
|
||||||
Game Launcher (Future)
|
|
||||||
Create GameLauncher class to display menu
|
|
||||||
Allow runtime game switching
|
|
||||||
Handle cleanup: delete current_game; current_game = new SnakeGame(...)
|
|
||||||
Store game selection preference in flash
|
|
||||||
Key Design Principles
|
|
||||||
Hardware Isolation: All GPIO, interrupts, hardware config stay in basic1.cpp
|
|
||||||
State Encapsulation: Each game owns its state completely
|
|
||||||
Polymorphism: Use Game* pointer for runtime flexibility
|
|
||||||
Event-Driven: Games respond to InputEvent objects only
|
|
||||||
Reactive Rendering: Only redraw when update() returns true
|
|
||||||
Dual-Core Efficiency: Core 0 handles logic, Core 1 handles display refresh
|
|
||||||
@@ -505,10 +505,10 @@ int main()
|
|||||||
game_start_time = 0;
|
game_start_time = 0;
|
||||||
// Force full clear for clean transition to game
|
// Force full clear for clean transition to game
|
||||||
display->clear(false);
|
display->clear(false);
|
||||||
if (display->get_type() == DISPLAY_TYPE_EPAPER) {
|
// if (display->get_type() == DISPLAY_TYPE_EPAPER) {
|
||||||
LowLevelDisplayEPaper* epaper = static_cast<LowLevelDisplayEPaper*>(display);
|
// LowLevelDisplayEPaper* epaper = static_cast<LowLevelDisplayEPaper*>(display);
|
||||||
epaper->full_refresh();
|
// epaper->full_refresh();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
needs_refresh = true;
|
needs_refresh = true;
|
||||||
}
|
}
|
||||||
|
|||||||
32
games/monopoly/DiceModalGame.h
Normal file
32
games/monopoly/DiceModalGame.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// DiceModalGame.h
|
||||||
|
#pragma once
|
||||||
|
#include "../../lib/game.h"
|
||||||
|
#include "../../display/low_level_render.h"
|
||||||
|
#include "../../display/low_level_gui.h"
|
||||||
|
#include "input_manager.h"
|
||||||
|
|
||||||
|
class DiceModalGame : public Game {
|
||||||
|
int dice1, dice2;
|
||||||
|
bool dismissed;
|
||||||
|
public:
|
||||||
|
DiceModalGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager, int d1, int d2)
|
||||||
|
: Game(width, height, renderer, gui, input_manager), dice1(d1), dice2(d2), dismissed(false) {}
|
||||||
|
void init() override { dismissed = false; }
|
||||||
|
bool update(const InputEvent& event) override {
|
||||||
|
if (event.type == INPUT_BUTTON_0 || event.type == INPUT_BUTTON_1) {
|
||||||
|
dismissed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void draw() override {
|
||||||
|
int win_w = 220, win_h = 120;
|
||||||
|
int win_x = (width - win_w) / 2, win_y = (height - win_h) / 2;
|
||||||
|
char buf[64];
|
||||||
|
gui->draw_new_window(win_x, win_y, win_w, win_h, "Dice Roll");
|
||||||
|
snprintf(buf, sizeof(buf), "You rolled: %d + %d", dice1, dice2);
|
||||||
|
renderer->draw_string_scaled(win_x + 30, win_y + 40, buf, 2);
|
||||||
|
renderer->draw_string_scaled(10, height - 20, "Press any button...", 2);
|
||||||
|
}
|
||||||
|
bool is_dismissed() const { return dismissed; }
|
||||||
|
};
|
||||||
0
games/monopoly/PropertyModalGame.cpp
Normal file
0
games/monopoly/PropertyModalGame.cpp
Normal file
47
games/monopoly/PropertyModalGame.h
Normal file
47
games/monopoly/PropertyModalGame.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// PropertyModalGame.h
|
||||||
|
#pragma once
|
||||||
|
#include "../../lib/game.h"
|
||||||
|
#include "../../display/low_level_render.h"
|
||||||
|
#include "../../display/low_level_gui.h"
|
||||||
|
#include "input_manager.h"
|
||||||
|
#include "monopoly_board.h"
|
||||||
|
|
||||||
|
class PropertyModalGame : public Game {
|
||||||
|
const BoardTile* property;
|
||||||
|
bool dismissed;
|
||||||
|
public:
|
||||||
|
PropertyModalGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager, const BoardTile* prop)
|
||||||
|
: Game(width, height, renderer, gui, input_manager), property(prop), dismissed(false) {}
|
||||||
|
void init() override { dismissed = false; }
|
||||||
|
bool update(const InputEvent& event) override {
|
||||||
|
if (event.type == INPUT_BUTTON_0 || event.type == INPUT_BUTTON_1) {
|
||||||
|
dismissed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void draw() override {
|
||||||
|
int win_w = 320, win_h = 180;
|
||||||
|
int win_x = (width - win_w) / 2, win_y = (height - win_h) / 2;
|
||||||
|
char buf[128];
|
||||||
|
snprintf(buf, sizeof(buf), "Property: %s", property->name);
|
||||||
|
gui->draw_new_window(win_x, win_y, win_w, win_h, buf);
|
||||||
|
int py = win_y + 30;
|
||||||
|
char pbuf[128];
|
||||||
|
if (property->type == TILE_PROPERTY) {
|
||||||
|
snprintf(pbuf, sizeof(pbuf), "Cost: $%d", property->cost);
|
||||||
|
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
||||||
|
py += 25;
|
||||||
|
snprintf(pbuf, sizeof(pbuf), "Rent: $%d", property->rent[0]);
|
||||||
|
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
||||||
|
py += 25;
|
||||||
|
snprintf(pbuf, sizeof(pbuf), "House Cost: $%d", property->house_cost);
|
||||||
|
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
||||||
|
} else if (property->type == TILE_RAILROAD || property->type == TILE_UTILITY) {
|
||||||
|
snprintf(pbuf, sizeof(pbuf), "Cost: $%d", property->cost);
|
||||||
|
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
||||||
|
}
|
||||||
|
renderer->draw_string_scaled(10, height - 20, "Press any button...", 2);
|
||||||
|
}
|
||||||
|
bool is_dismissed() const { return dismissed; }
|
||||||
|
};
|
||||||
@@ -11,8 +11,14 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "DiceModalGame.h"
|
||||||
|
#include "PropertyModalGame.h"
|
||||||
|
|
||||||
|
|
||||||
// --- Constructor ---
|
// --- Constructor ---
|
||||||
@@ -36,6 +42,8 @@ void MonopolyGame::init() {
|
|||||||
double_rolls = 0;
|
double_rolls = 0;
|
||||||
just_sent_to_jail = false;
|
just_sent_to_jail = false;
|
||||||
selected_action = 0;
|
selected_action = 0;
|
||||||
|
srand(time(NULL));
|
||||||
|
if (active_modal) { delete active_modal; active_modal = nullptr; }
|
||||||
// TODO: Reset all board state, property ownership, etc.
|
// TODO: Reset all board state, property ownership, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,11 +52,17 @@ 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;
|
||||||
|
|
||||||
// If modal is open, any button closes it
|
// If a modal is active, delegate input and check for dismissal
|
||||||
if (show_property_modal) {
|
if (active_modal) {
|
||||||
if (event.type == INPUT_BUTTON_0 || event.type == INPUT_BUTTON_1) {
|
bool modal_redraw = active_modal->update(event);
|
||||||
show_property_modal = false;
|
if (modal_redraw) needs_redraw = true;
|
||||||
modal_property_index = -1;
|
// If modal is dismissed, delete and return control
|
||||||
|
// Use dynamic_cast to check for modal type and dismissal
|
||||||
|
auto dice_modal = dynamic_cast<DiceModalGame*>(active_modal);
|
||||||
|
auto prop_modal = dynamic_cast<PropertyModalGame*>(active_modal);
|
||||||
|
if ((dice_modal && dice_modal->is_dismissed()) || (prop_modal && prop_modal->is_dismissed())) {
|
||||||
|
delete active_modal;
|
||||||
|
active_modal = nullptr;
|
||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
}
|
}
|
||||||
return needs_redraw;
|
return needs_redraw;
|
||||||
@@ -71,11 +85,16 @@ bool MonopolyGame::update(const InputEvent& event) {
|
|||||||
if (p->position < old_pos) p->balance += 200;
|
if (p->position < old_pos) p->balance += 200;
|
||||||
has_rolled = true;
|
has_rolled = true;
|
||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
|
// Store dice values and show dice modal
|
||||||
|
last_dice1 = dice1;
|
||||||
|
last_dice2 = dice2;
|
||||||
|
if (active_modal) delete active_modal;
|
||||||
|
active_modal = new DiceModalGame(width, height, renderer, gui, input_manager, dice1, dice2);
|
||||||
// Show property modal if landed on property/railroad/utility
|
// Show property modal if landed on property/railroad/utility
|
||||||
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) {
|
||||||
show_property_modal = true;
|
|
||||||
modal_property_index = p->position;
|
modal_property_index = p->position;
|
||||||
|
// Queue property modal after dice modal is dismissed
|
||||||
}
|
}
|
||||||
// TODO: Handle doubles, jail, landing effects
|
// TODO: Handle doubles, jail, landing effects
|
||||||
}
|
}
|
||||||
@@ -111,27 +130,42 @@ bool MonopolyGame::update(const InputEvent& event) {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// If dice modal was just dismissed and a property modal is queued, show it
|
||||||
|
if (!active_modal && modal_property_index >= 0) {
|
||||||
|
active_modal = new PropertyModalGame(width, height, renderer, gui, input_manager, &MONOPOLY_BOARD[modal_property_index]);
|
||||||
|
modal_property_index = -1;
|
||||||
|
needs_redraw = true;
|
||||||
|
}
|
||||||
return needs_redraw;
|
return needs_redraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Draw game state (minimal: player info, current tile, actions) ---
|
// --- Draw game state (minimal: player info, current tile, actions) ---
|
||||||
void MonopolyGame::draw() {
|
void MonopolyGame::draw() {
|
||||||
|
// If a modal is active, draw it and return
|
||||||
|
if (active_modal) {
|
||||||
|
active_modal->draw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
Player* p = &players[current_player_idx];
|
Player* p = &players[current_player_idx];
|
||||||
const BoardTile* tile = &MONOPOLY_BOARD[p->position];
|
const BoardTile* tile = &MONOPOLY_BOARD[p->position];
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
renderer->draw_string_scaled(10, 10, "Monopoly (Minimal)", 2);
|
renderer->draw_string_scaled(10, 10, "Monopoly", 3);
|
||||||
|
|
||||||
// --- Player Stats (Right Side) ---
|
// --- Player Stats (Right Side) ---
|
||||||
int stats_x = width - 180;
|
int stats_x = width - 200;
|
||||||
int y = 20;
|
int y = 40 + 15 * current_player_idx;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
// Name (Big)
|
// make a window showing player stats
|
||||||
renderer->draw_string_scaled(stats_x, y, p->name, 2);
|
LowLevelWindow* stats_win = gui->draw_new_window(stats_x - 10, y - 10 , 190, 120, p->name);
|
||||||
y += 40;
|
y += 20;
|
||||||
|
renderer->draw_string_scaled(stats_x, y, "Location:", 1);
|
||||||
|
renderer->draw_string_scaled(stats_x, y + 10, tile->name, 2);
|
||||||
|
y += 30;
|
||||||
// Money
|
// Money
|
||||||
snprintf(buf, sizeof(buf), "$%d", p->balance);
|
snprintf(buf, sizeof(buf), "$%d", p->balance);
|
||||||
renderer->draw_string_scaled(stats_x, y, buf, 2);
|
renderer->draw_string_scaled(stats_x, y, "Money:", 1);
|
||||||
|
renderer->draw_string_scaled(stats_x, y + 10, buf, 2);
|
||||||
y += 30;
|
y += 30;
|
||||||
// Properties
|
// Properties
|
||||||
int prop_count = 0;
|
int prop_count = 0;
|
||||||
@@ -140,8 +174,8 @@ void MonopolyGame::draw() {
|
|||||||
if (prop_idx >= 0 && MONOPOLY_BOARD[prop_idx].type == TILE_PROPERTY) prop_count++;
|
if (prop_idx >= 0 && MONOPOLY_BOARD[prop_idx].type == TILE_PROPERTY) prop_count++;
|
||||||
}
|
}
|
||||||
snprintf(buf, sizeof(buf), "Properties: %d", prop_count);
|
snprintf(buf, sizeof(buf), "Properties: %d", prop_count);
|
||||||
renderer->draw_string_scaled(stats_x, y, buf, 2);
|
renderer->draw_string_scaled(stats_x, y, buf, 1);
|
||||||
y += 30;
|
y += 10;
|
||||||
// Monopoly count
|
// Monopoly count
|
||||||
int monopoly_count = 0;
|
int monopoly_count = 0;
|
||||||
// For each group, check if player owns all properties in group
|
// For each group, check if player owns all properties in group
|
||||||
@@ -158,49 +192,7 @@ void MonopolyGame::draw() {
|
|||||||
if (group_total > 0 && group_total == group_owned) monopoly_count++;
|
if (group_total > 0 && group_total == group_owned) monopoly_count++;
|
||||||
}
|
}
|
||||||
snprintf(buf, sizeof(buf), "Monopolies: %d", monopoly_count);
|
snprintf(buf, sizeof(buf), "Monopolies: %d", monopoly_count);
|
||||||
renderer->draw_string_scaled(stats_x, y, buf, 2);
|
renderer->draw_string_scaled(stats_x, y, buf, 1);
|
||||||
|
|
||||||
// --- Main Info (Left Side) ---
|
|
||||||
snprintf(buf, sizeof(buf), "Player: %s ($%d)", p->name, p->balance);
|
|
||||||
renderer->draw_string_scaled(10, 30, buf, 2);
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "Location: %s", tile->name);
|
|
||||||
renderer->draw_string_scaled(10, 50, buf, 2);
|
|
||||||
|
|
||||||
// Show property modal window if needed
|
|
||||||
if (show_property_modal && modal_property_index >= 0) {
|
|
||||||
const BoardTile* mprop = &MONOPOLY_BOARD[modal_property_index];
|
|
||||||
int win_w = 320, win_h = 180;
|
|
||||||
int win_x = (width - win_w) / 2, win_y = (height - win_h) / 2;
|
|
||||||
LowLevelWindow* win = gui->draw_new_window(win_x, win_y, win_w, win_h, "Property Info");
|
|
||||||
// gui->current_font = renderer->get_current_font();
|
|
||||||
int py = win_y + 30;
|
|
||||||
char pbuf[128];
|
|
||||||
if (mprop->type == TILE_PROPERTY) {
|
|
||||||
snprintf(pbuf, sizeof(pbuf), "%s", mprop->name);
|
|
||||||
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
|
||||||
py += 30;
|
|
||||||
snprintf(pbuf, sizeof(pbuf), "Color: %s", mprop->color ? mprop->color : "-");
|
|
||||||
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
|
||||||
py += 25;
|
|
||||||
snprintf(pbuf, sizeof(pbuf), "Cost: $%d", mprop->cost);
|
|
||||||
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
|
||||||
py += 25;
|
|
||||||
snprintf(pbuf, sizeof(pbuf), "Rent: $%d", mprop->rent[0]);
|
|
||||||
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
|
||||||
py += 25;
|
|
||||||
snprintf(pbuf, sizeof(pbuf), "House Cost: $%d", mprop->house_cost);
|
|
||||||
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
|
||||||
} else if (mprop->type == TILE_RAILROAD || mprop->type == TILE_UTILITY) {
|
|
||||||
snprintf(pbuf, sizeof(pbuf), "%s", mprop->name);
|
|
||||||
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
|
||||||
py += 30;
|
|
||||||
snprintf(pbuf, sizeof(pbuf), "Cost: $%d", mprop->cost);
|
|
||||||
renderer->draw_string_scaled(win_x + 20, py, pbuf, 2);
|
|
||||||
}
|
|
||||||
renderer->draw_string_scaled(win_x + 20, win_y + win_h - 40, "Press any button...", 2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw action menu (highlight selected)
|
// Draw action menu (highlight selected)
|
||||||
const char* actions[ACTION_COUNT] = {"Roll Dice", "Buy Property", "End Turn"};
|
const char* actions[ACTION_COUNT] = {"Roll Dice", "Buy Property", "End Turn"};
|
||||||
@@ -210,8 +202,6 @@ void MonopolyGame::draw() {
|
|||||||
renderer->draw_string_scaled(10, y, buf, 2);
|
renderer->draw_string_scaled(10, y, buf, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderer->draw_string_scaled(10, height - 20, "BTN0: Next Option BTN1: Select", 2);
|
|
||||||
|
|
||||||
// TODO: Draw board, all players, property ownership, jail, chance, etc.
|
// TODO: Draw board, all players, property ownership, jail, chance, etc.
|
||||||
// TODO: Add win/lose/game over conditions
|
// TODO: Add win/lose/game over conditions
|
||||||
// TODO: Add touch support, more UI, etc.
|
// TODO: Add touch support, more UI, etc.
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public:
|
|||||||
bool update(const InputEvent& event) override;
|
bool update(const InputEvent& event) override;
|
||||||
void draw() override;
|
void draw() override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Game state and helpers
|
// Game state and helpers
|
||||||
Player players[MAX_PLAYERS];
|
Player players[MAX_PLAYERS];
|
||||||
@@ -39,8 +40,10 @@ private:
|
|||||||
int selected_action; // 0: Roll, 1: Buy, 2: End Turn
|
int selected_action; // 0: Roll, 1: Buy, 2: End Turn
|
||||||
static constexpr int ACTION_COUNT = 3;
|
static constexpr int ACTION_COUNT = 3;
|
||||||
|
|
||||||
// Modal property window state
|
// Modal games
|
||||||
bool show_property_modal = false;
|
Game* active_modal = nullptr;
|
||||||
|
int last_dice1 = 0;
|
||||||
|
int last_dice2 = 0;
|
||||||
int modal_property_index = -1;
|
int modal_property_index = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user