diff --git a/README.md b/README.md index f192a75..3af9b41 100644 --- a/README.md +++ b/README.md @@ -10,22 +10,30 @@ Each turn, you roll the dice to see what happens in the city. The events will af You can also try to assassinate the emperor. This is a risky move, but if you succeed, you win the game (though you die a martyr). +## Configuration + +This project uses a SQLite database to store game data and configuration. + +You can modify the game's configuration by clicking on the "Configuration" button on the main page. This will take you to a page where you can edit the score thresholds, win conditions, and event descriptions. + ## Technical Details This project is built using: * **Frontend:** HTML, CSS, JavaScript * **Backend:** PHP +* **Database:** SQLite ## How to Run Locally -To run this project locally, you need a PHP server. You can use a local development environment like XAMPP or MAMP, or you can use the built-in PHP server. +To run this project locally, you need a PHP server with the `pdo_sqlite` extension enabled. You can use a local development environment like XAMPP or MAMP, or you can use the built-in PHP server. 1. Clone this repository. -2. Start a PHP server in the project directory. For example, you can run the following command: +2. Make sure the `pdo_sqlite` extension is enabled in your `php.ini` file. +3. Start a PHP server in the project directory. For example, you can run the following command: ```bash php -S localhost:8000 ``` -3. Open your web browser and go to `http://localhost:8000`. +4. Open your web browser and go to `http://localhost:8000`. diff --git a/config.css b/config.css new file mode 100644 index 0000000..07fd860 --- /dev/null +++ b/config.css @@ -0,0 +1,24 @@ +.form-group { + margin-bottom: 1rem; +} + +.form-group label { + display: block; + margin-bottom: 0.5rem; +} + +.form-group input, +.form-group textarea { + width: 100%; + padding: 0.5rem; + border: 1px solid #ccc; + border-radius: 4px; +} + +.form-group textarea { + height: 100px; +} + +button[type="submit"] { + margin-top: 1rem; +} diff --git a/config.php b/config.php new file mode 100644 index 0000000..dbe14c8 --- /dev/null +++ b/config.php @@ -0,0 +1,44 @@ + $value) { + $stmt = $db->prepare('UPDATE configuration SET value = ? WHERE name = ?'); + $stmt->execute([$value, $name]); + } + header('Location: config.php'); + exit; +} + +$stmt = $db->query('SELECT * FROM configuration'); +$config = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); +?> + + + + + + Configuration - Last Days of Rome + + + + +
+

Configuration

+
+ $value): ?> +
+ + 80): ?> + + + + +
+ + +
+ Back to Game +
+ + \ No newline at end of file diff --git a/database.php b/database.php new file mode 100644 index 0000000..c784d8c --- /dev/null +++ b/database.php @@ -0,0 +1,51 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +// Create tables if they don't exist +$db->exec('CREATE TABLE IF NOT EXISTS game_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + date_played DATETIME, + flames_score INTEGER, + desolation_score INTEGER, + relocation_score INTEGER, + end_condition TEXT +)'); + +$db->exec('CREATE TABLE IF NOT EXISTS configuration ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + value TEXT +)'); + +// Check if configuration is already seeded +$stmt = $db->query('SELECT COUNT(*) FROM configuration'); +$count = $stmt->fetchColumn(); + +if ($count === 0) { + // Seed the configuration table + $config = [ + ['flames_win', '10'], + ['desolation_win', '10'], + ['relocation_win', '10'], + ['assassination_win', '20'], + ['imperial_palace_event_1', 'The emperor fiddles with manic glee. +1 Flames.'], + ['imperial_palace_event_2', 'The emperor raises another horse to the position of senator. +1 Desolation, +1 Relocation.'], + ['imperial_palace_event_3', 'It\'s execution night at the palace. +1 Relocation.'], + ['imperial_palace_event_4', 'The emperor screams like a baby. +1 Desolation.'], + ['imperial_palace_event_5', 'The emperor sits in front of the flame and commands it to obey. It does not. +1 Flames, +1 Relocation.'], + ['imperial_palace_event_6', 'Work continues on a house made of pure gold. It keeps melting. +1 Flames.'], + ['relative_unrest_event_1', 'People complain - this is unacceptable. Then they go about their business. +1 Relocation.'], + ['relative_unrest_event_2', 'There are no goods at market. +1 Desolation.'], + ['relative_unrest_event_3', 'You receive a letter asking you to reassert your faith in the emperor. In writing. +1 Relocation.'], + ['relative_unrest_event_4', 'Lions are released onto the streets. +1 Desolation, +1 Flames.'], + ['relative_unrest_event_5', 'Is Rome really over? +1 Desolation.'], + ['relative_unrest_event_6', 'The burnings will continue until morale improves. +1 Flames.'], + ]; + + $stmt = $db->prepare('INSERT INTO configuration (name, value) VALUES (?, ?)'); + foreach ($config as $item) { + $stmt->execute($item); + } +} +?> \ No newline at end of file diff --git a/game.php b/game.php index c6033bb..df87f4c 100644 --- a/game.php +++ b/game.php @@ -1,5 +1,10 @@ query('SELECT * FROM configuration'); +$config = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); if (!isset($_SESSION['scores'])) { $_SESSION['scores'] = [ @@ -12,15 +17,21 @@ if (!isset($_SESSION['scores'])) { $action = $_GET['action'] ?? ''; if ($action === 'roll_dice') { - $event = roll_dice(); - $gameState = check_game_state(); + $event = roll_dice($config); + $gameState = check_game_state($config); + if ($gameState !== 'ongoing') { + log_game($gameState); + } echo json_encode([ 'scores' => $_SESSION['scores'], 'event' => $event, 'gameState' => $gameState, ]); } elseif ($action === 'assassinate') { - $assassinationResult = assassinate(); + $assassinationResult = assassinate($config); + if ($assassinationResult['gameState'] !== 'ongoing') { + log_game($assassinationResult['gameState']); + } echo json_encode([ 'event' => $assassinationResult['event'], 'gameState' => $assassinationResult['gameState'], @@ -36,14 +47,14 @@ if ($action === 'roll_dice') { ]); } -function roll_dice() { +function roll_dice($config) { $roll = rand(1, 6); $event = ''; if ($roll <= 3) { - $event = 'In the Imperial Palace: ' . imperial_palace_event(); + $event = 'In the Imperial Palace: ' . imperial_palace_event($config); } elseif ($roll <= 5) { - $event = 'Relative Unrest: ' . relative_unrest_event(); + $event = 'Relative Unrest: ' . relative_unrest_event($config); } else { $_SESSION['scores']['flames']++; $event = 'The fires spread. +1 Flames.'; @@ -51,96 +62,102 @@ function roll_dice() { return $event; } -function imperial_palace_event() { +function imperial_palace_event($config) { $roll = rand(1, 6); $event = ''; switch ($roll) { case 1: $_SESSION['scores']['flames']++; - $event = 'The emperor fiddles with manic glee. +1 Flames.'; + $event = $config['imperial_palace_event_1']; break; case 2: $_SESSION['scores']['desolation']++; $_SESSION['scores']['relocation']++; - $event = 'The emperor raises another horse to the position of senator. +1 Desolation, +1 Relocation.'; + $event = $config['imperial_palace_event_2']; break; case 3: $_SESSION['scores']['relocation']++; - $event = 'It\'s execution night at the palace. +1 Relocation.'; + $event = $config['imperial_palace_event_3']; break; case 4: $_SESSION['scores']['desolation']++; - $event = 'The emperor screams like a baby. +1 Desolation.'; + $event = $config['imperial_palace_event_4']; break; case 5: $_SESSION['scores']['flames']++; $_SESSION['scores']['relocation']++; - $event = 'The emperor sits in front of the flame and commands it to obey. It does not. +1 Flames, +1 Relocation.'; + $event = $config['imperial_palace_event_5']; break; case 6: $_SESSION['scores']['flames']++; - $event = 'Work continues on a house made of pure gold. It keeps melting. +1 Flames.'; + $event = $config['imperial_palace_event_6']; break; } return $event; } -function relative_unrest_event() { +function relative_unrest_event($config) { $roll = rand(1, 6); $event = ''; switch ($roll) { case 1: $_SESSION['scores']['relocation']++; - $event = 'People complain - this is unacceptable. Then they go about their business. +1 Relocation.'; + $event = $config['relative_unrest_event_1']; break; case 2: $_SESSION['scores']['desolation']++; - $event = 'There are no goods at market. +1 Desolation.'; + $event = $config['relative_unrest_event_2']; break; case 3: $_SESSION['scores']['relocation']++; - $event = 'You receive a letter asking you to reassert your faith in the emperor. In writing. +1 Relocation.'; + $event = $config['relative_unrest_event_3']; break; case 4: $_SESSION['scores']['desolation']++; $_SESSION['scores']['flames']++; - $event = 'Lions are released onto the streets. +1 Desolation, +1 Flames.'; + $event = $config['relative_unrest_event_4']; break; case 5: $_SESSION['scores']['desolation']++; - $event = 'Is Rome really over? +1 Desolation.'; + $event = $config['relative_unrest_event_5']; break; case 6: $_SESSION['scores']['flames']++; - $event = 'The burnings will continue until morale improves. +1 Flames.'; + $event = $config['relative_unrest_event_6']; break; } return $event; } -function assassinate() { +function assassinate($config) { $desolation = $_SESSION['scores']['desolation']; $total = 0; for ($i = 0; $i < $desolation; $i++) { $total += rand(1, 6); } - if ($total >= 20) { + if ($total >= $config['assassination_win']) { return ['event' => 'You have assassinated the emperor! You die a martyr.', 'gameState' => 'win_assassination']; } else { return ['event' => 'Your attempt to assassinate the emperor has failed. You are executed.', 'gameState' => 'loss_assassination']; } } -function check_game_state() { - if ($_SESSION['scores']['flames'] >= 10) { +function check_game_state($config) { + if ($_SESSION['scores']['flames'] >= $config['flames_win']) { return 'loss_flames'; } - if ($_SESSION['scores']['desolation'] >= 10) { + if ($_SESSION['scores']['desolation'] >= $config['desolation_win']) { return 'loss_desolation'; } - if ($_SESSION['scores']['relocation'] >= 10) { + if ($_SESSION['scores']['relocation'] >= $config['relocation_win']) { return 'win'; } return 'ongoing'; } + +function log_game($end_condition) { + global $db; + $stmt = $db->prepare('INSERT INTO game_logs (date_played, flames_score, desolation_score, relocation_score, end_condition) VALUES (?, ?, ?, ?, ?)'); + $stmt->execute([date('Y-m-d H:i:s'), $_SESSION['scores']['flames'], $_SESSION['scores']['desolation'], $_SESSION['scores']['relocation'], $end_condition]); +} diff --git a/gemini.md b/gemini.md new file mode 100644 index 0000000..d2ce797 --- /dev/null +++ b/gemini.md @@ -0,0 +1,8 @@ +Make the following updates to the project and update the readme file as needed for documentation. + +Add a sqlite backend for the following: +- Game logs: Track date and time played, final scores, and end condition (escape, loss, assassination outcome, etc). +- Configuration: Score thresholds, win conditions, event descriptions, etc. + - Default configuration should be provided using current hardcoded values. + - Allow user to modify configuration via a simple web form. + - Store configuration changes in the database. diff --git a/index.php b/index.php index 774ac69..cbf7ebe 100644 --- a/index.php +++ b/index.php @@ -19,6 +19,7 @@ + Configuration
diff --git a/style.css b/style.css index 34ad60b..02b5802 100644 --- a/style.css +++ b/style.css @@ -77,6 +77,23 @@ h1 { color: var(--h1-color-light); } &:hover { background-color: var(--button-hover-background-color); } } +.actions a.button { + background-color: var(--button-background-color); + border: none; + color: var(--button-text-color); + cursor: pointer; + display: inline-block; + font-size: 1em; + margin: 0 .5rem 1.5rem; + padding: .5rem 1.5rem; + text-decoration: none; + transition: background-color 0.3s; +} + +.actions a.button:hover { + background-color: var(--button-hover-background-color); +} + .intro { font-size: 1.1rem; line-height: 1.4;