From 471dc33f0e3ad217eeaf3965772a16e01043020f Mon Sep 17 00:00:00 2001 From: Marvin Date: Sat, 24 Oct 2026 20:32:37 +0200 Subject: [PATCH] added item probability --- .env.example | 7 +++- .gitignore | 0 README.md | 1 + actionBlocks_server/.dockerignore | 0 actionBlocks_server/.gitignore | 0 actionBlocks_server/ActionBlocks.Server.sln | 0 actionBlocks_server/Dockerfile | 0 .../ActionBlocks.Game.csproj | 0 .../src/ActionBlocks.Game/Core/Board.cs | 2 +- .../src/ActionBlocks.Game/Core/Cell.cs | 0 .../src/ActionBlocks.Game/Core/Piece.cs | 8 ++-- .../Core/PieceDefinitions.cs | 0 .../src/ActionBlocks.Game/Core/PieceType.cs | 0 .../src/ActionBlocks.Game/Core/Randomizer.cs | 0 .../ActionBlocks.Game/Core/RotationSystem.cs | 0 .../src/ActionBlocks.Game/GameSettings.cs | 2 +- .../Garbage/GarbageCalculator.cs | 0 .../src/ActionBlocks.Game/Items/IItem.cs | 0 .../ActionBlocks.Game/Items/ItemRegistry.cs | 21 ++++++++-- .../src/ActionBlocks.Game/Items/Items.cs | 0 .../src/ActionBlocks.Game/Match.cs | 0 .../src/ActionBlocks.Game/PlayerGame.cs | 0 .../Targeting/GarbageTargeter.cs | 0 .../ActionBlocks.Server.csproj | 0 .../src/ActionBlocks.Server/Dtos/Dtos.cs | 6 ++- .../Dtos/SnapshotMapper.cs | 6 ++- .../src/ActionBlocks.Server/Hubs/GameHub.cs | 0 .../src/ActionBlocks.Server/Lobbies/Lobby.cs | 0 .../Lobbies/LobbyManager.cs | 0 .../Lobbies/MatchRunner.cs | 0 .../src/ActionBlocks.Server/Program.cs | 0 .../src/ActionBlocks.Server/appsettings.json | 0 .../ActionBlocks.Game.Tests.csproj | 0 .../ActionBlocks.Game.Tests/CoreTests.cs | 0 .../ItemAndMatchTests.cs | 37 ++++++++++++++++++ .../PlayerGameTests.cs | 11 +++--- .../ActionBlocks.Game.Tests/TestHelpers.cs | 0 actionBlocks_website/.dockerignore | 0 actionBlocks_website/.gitignore | 0 actionBlocks_website/Dockerfile | 0 actionBlocks_website/docker/nginx.conf | 0 actionBlocks_website/index.html | 0 actionBlocks_website/package-lock.json | 0 actionBlocks_website/package.json | 0 .../public/assets/favicon.svg | 0 .../public/assets/items/add_line.svg | 0 .../public/assets/items/blind.svg | 0 .../public/assets/items/clear_line.svg | 0 .../public/assets/items/nuke.svg | 0 .../public/assets/items/swap.svg | 0 .../public/assets/items/unknown.svg | 0 .../public/assets/sounds/README.md | 0 .../public/assets/sounds/music/.gitkeep | 0 .../public/assets/ui/sound_off.svg | 0 .../public/assets/ui/sound_on.svg | 0 actionBlocks_website/public/config.js | 0 actionBlocks_website/src/App.module.css | 0 actionBlocks_website/src/App.tsx | 0 actionBlocks_website/src/audio/AudioEngine.ts | 0 .../src/audio/MusicPlaylist.ts | 0 .../src/audio/SoundContext.tsx | 0 actionBlocks_website/src/audio/music.ts | 0 actionBlocks_website/src/audio/pitch.ts | 0 actionBlocks_website/src/audio/settings.ts | 0 actionBlocks_website/src/audio/songs.ts | 0 actionBlocks_website/src/audio/synthSounds.ts | 0 actionBlocks_website/src/audio/types.ts | 0 .../src/audio/useGameSounds.ts | 0 .../src/components/BoardCanvas.module.css | 0 .../src/components/BoardCanvas.tsx | 0 .../src/components/CornerControls.module.css | 0 .../src/components/CornerControls.tsx | 0 .../src/components/ItemBar.module.css | 0 .../src/components/ItemBar.tsx | 0 .../components/ItemFlashOverlay.module.css | 0 .../src/components/ItemFlashOverlay.tsx | 0 .../src/components/Logo.module.css | 0 actionBlocks_website/src/components/Logo.tsx | 0 .../src/components/MiniBoard.module.css | 0 .../src/components/MiniBoard.tsx | 0 .../src/components/MusicTracks.module.css | 0 .../src/components/MusicTracks.tsx | 0 .../src/components/PiecePreview.module.css | 0 .../src/components/PiecePreview.tsx | 0 .../src/components/SoundMenu.module.css | 0 .../src/components/SoundMenu.tsx | 0 .../src/components/ui/Button.module.css | 0 .../src/components/ui/Button.tsx | 0 .../src/components/ui/Panel.module.css | 0 .../src/components/ui/Panel.tsx | 0 .../src/config/keybindings.ts | 0 .../src/config/runtimeConfig.ts | 0 actionBlocks_website/src/config/sound.ts | 0 .../src/input/useKeyboardInput.ts | 0 actionBlocks_website/src/main.tsx | 0 actionBlocks_website/src/net/hubClient.ts | 0 actionBlocks_website/src/net/types.ts | 8 ++-- .../src/net/useGameConnection.ts | 0 .../src/pages/GamePage.module.css | 0 actionBlocks_website/src/pages/GamePage.tsx | 0 .../src/pages/HomePage.module.css | 0 actionBlocks_website/src/pages/HomePage.tsx | 0 .../src/pages/LobbyPage.module.css | 0 actionBlocks_website/src/pages/LobbyPage.tsx | 0 actionBlocks_website/src/render/draw.ts | 6 ++- actionBlocks_website/src/render/shapes.ts | 0 actionBlocks_website/src/theme/assets.ts | 0 actionBlocks_website/src/theme/colors.ts | 0 actionBlocks_website/src/theme/global.css | 0 actionBlocks_website/tsconfig.json | 0 actionBlocks_website/vite.config.ts | 0 doc/README.md | 0 doc/architecture.md | 0 doc/deployment.md | 3 +- doc/development.md | 0 doc/extending.md | 3 +- doc/frontend.md | 0 doc/game-rules.md | 2 +- doc/protocol.md | 7 ++-- doc/server.md | 4 +- docker-compose.yml | 1 + instructions.md | 0 .../Tetris Guideline - TetrisWiki.html | 0 .../250px-The_Tetris_Company_logo_2019.png | Bin .../500px-Tetrominoes.png | Bin .../88x31.png | Bin .../gtm.js | 0 .../load(1).php | 0 .../load(2).php | 0 .../load.php | 0 .../poweredby_mediawiki.svg | 0 ...01823e78c4301a35b7e07294d87301792088814092 | 0 132 files changed, 99 insertions(+), 36 deletions(-) mode change 100644 => 100755 .env.example mode change 100644 => 100755 .gitignore mode change 100644 => 100755 README.md mode change 100644 => 100755 actionBlocks_server/.dockerignore mode change 100644 => 100755 actionBlocks_server/.gitignore mode change 100644 => 100755 actionBlocks_server/ActionBlocks.Server.sln mode change 100644 => 100755 actionBlocks_server/Dockerfile mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/ActionBlocks.Game.csproj mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Core/Board.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Core/Cell.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Core/Piece.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Core/PieceDefinitions.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Core/PieceType.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Core/Randomizer.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Core/RotationSystem.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/GameSettings.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Garbage/GarbageCalculator.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Items/IItem.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Items/ItemRegistry.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Items/Items.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Match.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/PlayerGame.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Game/Targeting/GarbageTargeter.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/ActionBlocks.Server.csproj mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/Dtos/Dtos.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/Dtos/SnapshotMapper.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/Hubs/GameHub.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/Lobbies/Lobby.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/Lobbies/LobbyManager.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/Lobbies/MatchRunner.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/Program.cs mode change 100644 => 100755 actionBlocks_server/src/ActionBlocks.Server/appsettings.json mode change 100644 => 100755 actionBlocks_server/tests/ActionBlocks.Game.Tests/ActionBlocks.Game.Tests.csproj mode change 100644 => 100755 actionBlocks_server/tests/ActionBlocks.Game.Tests/CoreTests.cs mode change 100644 => 100755 actionBlocks_server/tests/ActionBlocks.Game.Tests/ItemAndMatchTests.cs mode change 100644 => 100755 actionBlocks_server/tests/ActionBlocks.Game.Tests/PlayerGameTests.cs mode change 100644 => 100755 actionBlocks_server/tests/ActionBlocks.Game.Tests/TestHelpers.cs mode change 100644 => 100755 actionBlocks_website/.dockerignore mode change 100644 => 100755 actionBlocks_website/.gitignore mode change 100644 => 100755 actionBlocks_website/Dockerfile mode change 100644 => 100755 actionBlocks_website/docker/nginx.conf mode change 100644 => 100755 actionBlocks_website/index.html mode change 100644 => 100755 actionBlocks_website/package-lock.json mode change 100644 => 100755 actionBlocks_website/package.json mode change 100644 => 100755 actionBlocks_website/public/assets/favicon.svg mode change 100644 => 100755 actionBlocks_website/public/assets/items/add_line.svg mode change 100644 => 100755 actionBlocks_website/public/assets/items/blind.svg mode change 100644 => 100755 actionBlocks_website/public/assets/items/clear_line.svg mode change 100644 => 100755 actionBlocks_website/public/assets/items/nuke.svg mode change 100644 => 100755 actionBlocks_website/public/assets/items/swap.svg mode change 100644 => 100755 actionBlocks_website/public/assets/items/unknown.svg mode change 100644 => 100755 actionBlocks_website/public/assets/sounds/README.md mode change 100644 => 100755 actionBlocks_website/public/assets/sounds/music/.gitkeep mode change 100644 => 100755 actionBlocks_website/public/assets/ui/sound_off.svg mode change 100644 => 100755 actionBlocks_website/public/assets/ui/sound_on.svg mode change 100644 => 100755 actionBlocks_website/public/config.js mode change 100644 => 100755 actionBlocks_website/src/App.module.css mode change 100644 => 100755 actionBlocks_website/src/App.tsx mode change 100644 => 100755 actionBlocks_website/src/audio/AudioEngine.ts mode change 100644 => 100755 actionBlocks_website/src/audio/MusicPlaylist.ts mode change 100644 => 100755 actionBlocks_website/src/audio/SoundContext.tsx mode change 100644 => 100755 actionBlocks_website/src/audio/music.ts mode change 100644 => 100755 actionBlocks_website/src/audio/pitch.ts mode change 100644 => 100755 actionBlocks_website/src/audio/settings.ts mode change 100644 => 100755 actionBlocks_website/src/audio/songs.ts mode change 100644 => 100755 actionBlocks_website/src/audio/synthSounds.ts mode change 100644 => 100755 actionBlocks_website/src/audio/types.ts mode change 100644 => 100755 actionBlocks_website/src/audio/useGameSounds.ts mode change 100644 => 100755 actionBlocks_website/src/components/BoardCanvas.module.css mode change 100644 => 100755 actionBlocks_website/src/components/BoardCanvas.tsx mode change 100644 => 100755 actionBlocks_website/src/components/CornerControls.module.css mode change 100644 => 100755 actionBlocks_website/src/components/CornerControls.tsx mode change 100644 => 100755 actionBlocks_website/src/components/ItemBar.module.css mode change 100644 => 100755 actionBlocks_website/src/components/ItemBar.tsx mode change 100644 => 100755 actionBlocks_website/src/components/ItemFlashOverlay.module.css mode change 100644 => 100755 actionBlocks_website/src/components/ItemFlashOverlay.tsx mode change 100644 => 100755 actionBlocks_website/src/components/Logo.module.css mode change 100644 => 100755 actionBlocks_website/src/components/Logo.tsx mode change 100644 => 100755 actionBlocks_website/src/components/MiniBoard.module.css mode change 100644 => 100755 actionBlocks_website/src/components/MiniBoard.tsx mode change 100644 => 100755 actionBlocks_website/src/components/MusicTracks.module.css mode change 100644 => 100755 actionBlocks_website/src/components/MusicTracks.tsx mode change 100644 => 100755 actionBlocks_website/src/components/PiecePreview.module.css mode change 100644 => 100755 actionBlocks_website/src/components/PiecePreview.tsx mode change 100644 => 100755 actionBlocks_website/src/components/SoundMenu.module.css mode change 100644 => 100755 actionBlocks_website/src/components/SoundMenu.tsx mode change 100644 => 100755 actionBlocks_website/src/components/ui/Button.module.css mode change 100644 => 100755 actionBlocks_website/src/components/ui/Button.tsx mode change 100644 => 100755 actionBlocks_website/src/components/ui/Panel.module.css mode change 100644 => 100755 actionBlocks_website/src/components/ui/Panel.tsx mode change 100644 => 100755 actionBlocks_website/src/config/keybindings.ts mode change 100644 => 100755 actionBlocks_website/src/config/runtimeConfig.ts mode change 100644 => 100755 actionBlocks_website/src/config/sound.ts mode change 100644 => 100755 actionBlocks_website/src/input/useKeyboardInput.ts mode change 100644 => 100755 actionBlocks_website/src/main.tsx mode change 100644 => 100755 actionBlocks_website/src/net/hubClient.ts mode change 100644 => 100755 actionBlocks_website/src/net/types.ts mode change 100644 => 100755 actionBlocks_website/src/net/useGameConnection.ts mode change 100644 => 100755 actionBlocks_website/src/pages/GamePage.module.css mode change 100644 => 100755 actionBlocks_website/src/pages/GamePage.tsx mode change 100644 => 100755 actionBlocks_website/src/pages/HomePage.module.css mode change 100644 => 100755 actionBlocks_website/src/pages/HomePage.tsx mode change 100644 => 100755 actionBlocks_website/src/pages/LobbyPage.module.css mode change 100644 => 100755 actionBlocks_website/src/pages/LobbyPage.tsx mode change 100644 => 100755 actionBlocks_website/src/render/draw.ts mode change 100644 => 100755 actionBlocks_website/src/render/shapes.ts mode change 100644 => 100755 actionBlocks_website/src/theme/assets.ts mode change 100644 => 100755 actionBlocks_website/src/theme/colors.ts mode change 100644 => 100755 actionBlocks_website/src/theme/global.css mode change 100644 => 100755 actionBlocks_website/tsconfig.json mode change 100644 => 100755 actionBlocks_website/vite.config.ts mode change 100644 => 100755 doc/README.md mode change 100644 => 100755 doc/architecture.md mode change 100644 => 100755 doc/deployment.md mode change 100644 => 100755 doc/development.md mode change 100644 => 100755 doc/extending.md mode change 100644 => 100755 doc/frontend.md mode change 100644 => 100755 doc/game-rules.md mode change 100644 => 100755 doc/protocol.md mode change 100644 => 100755 doc/server.md mode change 100644 => 100755 docker-compose.yml mode change 100644 => 100755 instructions.md mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki.html mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/250px-The_Tetris_Company_logo_2019.png mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/500px-Tetrominoes.png mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/88x31.png mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/gtm.js mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/load(1).php mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/load(2).php mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/load.php mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/poweredby_mediawiki.svg mode change 100644 => 100755 tetris_instructions/Tetris Guideline - TetrisWiki_files/vce701823e78c4301a35b7e07294d87301792088814092 diff --git a/.env.example b/.env.example old mode 100644 new mode 100755 index c758bdd..24cd307 --- a/.env.example +++ b/.env.example @@ -11,7 +11,10 @@ PATH_BASE= # Comma separated origins allowed to connect to the hub. Empty = allow any origin. ALLOWED_ORIGINS=https://game.example.com -# Optional gameplay tuning, passed to the server as Game__ (see GameSettings.cs). +# Chance (0..1) that each block of a new piece carries an item. Every block rolls on its +# own, so one piece can carry several items. 0 = no items, 1 = every block has one. +ITEM_SPAWN_CHANCE=0.1 + +# Other optional gameplay tuning, passed to the server as Game__ (see GameSettings.cs). # Add these under the server's "environment:" in docker-compose.yml to use them. -# Game__ItemSpawnChance=0.1 # Game__CountdownSeconds=3 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 6261d19..2d086e3 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ The reverse proxy (attached to both networks) should route: | `ALLOWED_ORIGINS` | server | Comma-separated CORS origins. Empty allows any origin. | | `HUB_PATH` | server | Hub endpoint path (default `/hub`). | | `PATH_BASE` | server | Prefix to accept when the proxy forwards a sub-path unstripped, e.g. `/server`. | +| `ITEM_SPAWN_CHANCE` | server | Chance (0..1) that each block of a new piece carries an item. Default `0.1`. Passed as `Game__ItemSpawnChance`. | | `Game__*` | server | Overrides any `GameSettings` value, e.g. `Game__ItemSpawnChance=0.2`. | ## Extending diff --git a/actionBlocks_server/.dockerignore b/actionBlocks_server/.dockerignore old mode 100644 new mode 100755 diff --git a/actionBlocks_server/.gitignore b/actionBlocks_server/.gitignore old mode 100644 new mode 100755 diff --git a/actionBlocks_server/ActionBlocks.Server.sln b/actionBlocks_server/ActionBlocks.Server.sln old mode 100644 new mode 100755 diff --git a/actionBlocks_server/Dockerfile b/actionBlocks_server/Dockerfile old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/ActionBlocks.Game.csproj b/actionBlocks_server/src/ActionBlocks.Game/ActionBlocks.Game.csproj old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Core/Board.cs b/actionBlocks_server/src/ActionBlocks.Game/Core/Board.cs old mode 100644 new mode 100755 index 4be696b..4bd4461 --- a/actionBlocks_server/src/ActionBlocks.Game/Core/Board.cs +++ b/actionBlocks_server/src/ActionBlocks.Game/Core/Board.cs @@ -41,7 +41,7 @@ public sealed class Board var i = 0; foreach (var c in piece.Cells()) { - var item = i == piece.Spec.ItemMinoIndex ? piece.Spec.ItemId : null; + var item = piece.Spec.Items is { } items && i < items.Count ? items[i] : null; _rows[c.Y][c.X] = new Cell((byte)piece.Type, item); i++; } diff --git a/actionBlocks_server/src/ActionBlocks.Game/Core/Cell.cs b/actionBlocks_server/src/ActionBlocks.Game/Core/Cell.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Core/Piece.cs b/actionBlocks_server/src/ActionBlocks.Game/Core/Piece.cs old mode 100644 new mode 100755 index c3659a0..d55308b --- a/actionBlocks_server/src/ActionBlocks.Game/Core/Piece.cs +++ b/actionBlocks_server/src/ActionBlocks.Game/Core/Piece.cs @@ -1,12 +1,12 @@ namespace ActionBlocks.Game.Core; /// -/// A piece definition as it travels through the queue: its shape plus an optional item -/// hidden inside one of its minos. +/// A piece definition as it travels through the queue: its shape plus optional items +/// hidden inside its minos. [i] is the item in mino i (null = none). /// -public sealed record PieceSpec(PieceType Type, string? ItemId = null, int ItemMinoIndex = -1) +public sealed record PieceSpec(PieceType Type, IReadOnlyList? Items = null) { - public bool HasItem => ItemId is not null; + public bool HasItem => Items?.Any(i => i is not null) == true; } /// A piece placed somewhere on the board (position = top-left corner of its bounding box). diff --git a/actionBlocks_server/src/ActionBlocks.Game/Core/PieceDefinitions.cs b/actionBlocks_server/src/ActionBlocks.Game/Core/PieceDefinitions.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Core/PieceType.cs b/actionBlocks_server/src/ActionBlocks.Game/Core/PieceType.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Core/Randomizer.cs b/actionBlocks_server/src/ActionBlocks.Game/Core/Randomizer.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Core/RotationSystem.cs b/actionBlocks_server/src/ActionBlocks.Game/Core/RotationSystem.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/GameSettings.cs b/actionBlocks_server/src/ActionBlocks.Game/GameSettings.cs old mode 100644 new mode 100755 index 8e00ec6..699623c --- a/actionBlocks_server/src/ActionBlocks.Game/GameSettings.cs +++ b/actionBlocks_server/src/ActionBlocks.Game/GameSettings.cs @@ -18,7 +18,7 @@ public sealed record GameSettings public int LinesPerLevel { get; init; } = 10; public int MaxLevel { get; init; } = 15; - /// Chance (0..1) that a newly generated piece carries an item. + /// Chance (0..1) that each mino of a newly generated piece carries an item. public double ItemSpawnChance { get; init; } = 0.1; public int MaxInventory { get; init; } = 10; diff --git a/actionBlocks_server/src/ActionBlocks.Game/Garbage/GarbageCalculator.cs b/actionBlocks_server/src/ActionBlocks.Game/Garbage/GarbageCalculator.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Items/IItem.cs b/actionBlocks_server/src/ActionBlocks.Game/Items/IItem.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Items/ItemRegistry.cs b/actionBlocks_server/src/ActionBlocks.Game/Items/ItemRegistry.cs old mode 100644 new mode 100755 index b0fb796..40057bb --- a/actionBlocks_server/src/ActionBlocks.Game/Items/ItemRegistry.cs +++ b/actionBlocks_server/src/ActionBlocks.Game/Items/ItemRegistry.cs @@ -39,16 +39,29 @@ public sealed class ItemRegistry } } -/// Decides whether a new piece carries an item and in which of its minos. +/// Decides which minos of a new piece carry an item. Each mino rolls chance (0..1) on its own. public sealed class ItemSpawner(ItemRegistry registry, double chance, Random random) { + private const int MinosPerPiece = 4; + + private readonly double _chance = double.IsNaN(chance) ? 0 : Math.Clamp(chance, 0, 1); + public Core.PieceSpec Decorate(Core.PieceType type) { - if (registry.All.Count == 0 || random.NextDouble() >= chance) + if (registry.All.Count == 0) { return new Core.PieceSpec(type); } - var item = registry.PickRandom(random); - return new Core.PieceSpec(type, item.Id, random.Next(4)); + var items = new string?[MinosPerPiece]; + var any = false; + for (var i = 0; i < MinosPerPiece; i++) + { + if (random.NextDouble() < _chance) + { + items[i] = registry.PickRandom(random).Id; + any = true; + } + } + return any ? new Core.PieceSpec(type, items) : new Core.PieceSpec(type); } } diff --git a/actionBlocks_server/src/ActionBlocks.Game/Items/Items.cs b/actionBlocks_server/src/ActionBlocks.Game/Items/Items.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Match.cs b/actionBlocks_server/src/ActionBlocks.Game/Match.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/PlayerGame.cs b/actionBlocks_server/src/ActionBlocks.Game/PlayerGame.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Game/Targeting/GarbageTargeter.cs b/actionBlocks_server/src/ActionBlocks.Game/Targeting/GarbageTargeter.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Server/ActionBlocks.Server.csproj b/actionBlocks_server/src/ActionBlocks.Server/ActionBlocks.Server.csproj old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Server/Dtos/Dtos.cs b/actionBlocks_server/src/ActionBlocks.Server/Dtos/Dtos.cs old mode 100644 new mode 100755 index 4ed7445..4aa4632 --- a/actionBlocks_server/src/ActionBlocks.Server/Dtos/Dtos.cs +++ b/actionBlocks_server/src/ActionBlocks.Server/Dtos/Dtos.cs @@ -14,11 +14,13 @@ public sealed record LobbyDto( public sealed record JoinResultDto(string PlayerId, LobbyDto Lobby); -public sealed record PieceDto(int Type, string? ItemId, int ItemIndex); +/// [i] is the item in mino i, null if none. +public sealed record PieceDto(int Type, string?[] Items); public sealed record ItemCellDto(int X, int Y, string ItemId); -public sealed record ActivePieceDto(int Type, int[][] Cells, int ItemIndex, string? ItemId); +/// [i] is the item in [i], null if none. +public sealed record ActivePieceDto(int Type, int[][] Cells, string?[] Items); public sealed record PlayerStateDto( string Id, diff --git a/actionBlocks_server/src/ActionBlocks.Server/Dtos/SnapshotMapper.cs b/actionBlocks_server/src/ActionBlocks.Server/Dtos/SnapshotMapper.cs old mode 100644 new mode 100755 index 6a748d4..e0c11a7 --- a/actionBlocks_server/src/ActionBlocks.Server/Dtos/SnapshotMapper.cs +++ b/actionBlocks_server/src/ActionBlocks.Server/Dtos/SnapshotMapper.cs @@ -55,12 +55,14 @@ public static class SnapshotMapper } private static ActivePieceDto ToDto(ActivePiece piece, Board board) => - new((int)piece.Type, ToCells(piece, board), piece.Spec.ItemMinoIndex, piece.Spec.ItemId); + new((int)piece.Type, ToCells(piece, board), ToItems(piece.Spec)); private static int[][] ToCells(ActivePiece piece, Board board) => piece.Cells().Select(c => new[] { c.X, c.Y - board.BufferRows }).ToArray(); - private static PieceDto ToDto(PieceSpec spec) => new((int)spec.Type, spec.ItemId, spec.ItemMinoIndex); + private static PieceDto ToDto(PieceSpec spec) => new((int)spec.Type, ToItems(spec)); + + private static string?[] ToItems(PieceSpec spec) => spec.Items?.ToArray() ?? new string?[4]; private static MatchEventDto ToDto(MatchEvent e) => e switch { diff --git a/actionBlocks_server/src/ActionBlocks.Server/Hubs/GameHub.cs b/actionBlocks_server/src/ActionBlocks.Server/Hubs/GameHub.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Server/Lobbies/Lobby.cs b/actionBlocks_server/src/ActionBlocks.Server/Lobbies/Lobby.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Server/Lobbies/LobbyManager.cs b/actionBlocks_server/src/ActionBlocks.Server/Lobbies/LobbyManager.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Server/Lobbies/MatchRunner.cs b/actionBlocks_server/src/ActionBlocks.Server/Lobbies/MatchRunner.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Server/Program.cs b/actionBlocks_server/src/ActionBlocks.Server/Program.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/src/ActionBlocks.Server/appsettings.json b/actionBlocks_server/src/ActionBlocks.Server/appsettings.json old mode 100644 new mode 100755 diff --git a/actionBlocks_server/tests/ActionBlocks.Game.Tests/ActionBlocks.Game.Tests.csproj b/actionBlocks_server/tests/ActionBlocks.Game.Tests/ActionBlocks.Game.Tests.csproj old mode 100644 new mode 100755 diff --git a/actionBlocks_server/tests/ActionBlocks.Game.Tests/CoreTests.cs b/actionBlocks_server/tests/ActionBlocks.Game.Tests/CoreTests.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_server/tests/ActionBlocks.Game.Tests/ItemAndMatchTests.cs b/actionBlocks_server/tests/ActionBlocks.Game.Tests/ItemAndMatchTests.cs old mode 100644 new mode 100755 index 43b8ad2..6246c7c --- a/actionBlocks_server/tests/ActionBlocks.Game.Tests/ItemAndMatchTests.cs +++ b/actionBlocks_server/tests/ActionBlocks.Game.Tests/ItemAndMatchTests.cs @@ -125,6 +125,43 @@ public class ItemTests { Assert.Equal(5, ItemRegistry.Default.All.Select(i => i.Id).Distinct().Count()); } + + [Theory] + [InlineData(0)] + [InlineData(-1)] + public void Spawner_with_zero_chance_never_adds_items(double chance) + { + var spawner = new ItemSpawner(ItemRegistry.Default, chance, new Random(1)); + + Assert.All(Enumerable.Range(0, 100), _ => Assert.False(spawner.Decorate(PieceType.T).HasItem)); + } + + [Theory] + [InlineData(1)] + [InlineData(2)] + public void Spawner_with_full_chance_puts_an_item_in_every_mino(double chance) + { + var spawner = new ItemSpawner(ItemRegistry.Default, chance, new Random(1)); + + var spec = spawner.Decorate(PieceType.T); + + Assert.NotNull(spec.Items); + Assert.Equal(4, spec.Items.Count); + Assert.All(spec.Items, i => Assert.NotNull(i)); + } + + [Fact] + public void Spawner_rolls_each_mino_separately() + { + var spawner = new ItemSpawner(ItemRegistry.Default, 0.5, new Random(1)); + + var counts = Enumerable.Range(0, 1000) + .Select(_ => spawner.Decorate(PieceType.T).Items?.Count(i => i is not null) ?? 0) + .ToList(); + + Assert.Contains(counts, c => c >= 2); + Assert.InRange(counts.Average(), 1.8, 2.2); + } } public class MatchTests diff --git a/actionBlocks_server/tests/ActionBlocks.Game.Tests/PlayerGameTests.cs b/actionBlocks_server/tests/ActionBlocks.Game.Tests/PlayerGameTests.cs old mode 100644 new mode 100755 index bad8e1d..219f865 --- a/actionBlocks_server/tests/ActionBlocks.Game.Tests/PlayerGameTests.cs +++ b/actionBlocks_server/tests/ActionBlocks.Game.Tests/PlayerGameTests.cs @@ -35,17 +35,18 @@ public class PlayerGameTests } [Fact] - public void Item_inside_piece_is_collected_when_its_row_clears() + public void Items_inside_piece_are_collected_when_their_row_clears() { var player = CreatePlayer(itemChance: 1, pieces: PieceType.I); FillRow(player.Board, Bottom(player.Board), 3, 4, 5, 6); player.Start(); - var itemId = player.Active!.Spec.ItemId; - Assert.NotNull(itemId); + var items = player.Active!.Spec.Items; + Assert.NotNull(items); + Assert.All(items, i => Assert.NotNull(i)); player.HandleInput(InputAction.HardDrop); - Assert.Equal([itemId!], player.Inventory); + Assert.Equal(items.Order(), player.Inventory.Order()); } [Fact] @@ -58,7 +59,7 @@ public class PlayerGameTests Assert.Empty(player.Inventory); var bottom = Bottom(player.Board); - Assert.Contains(Enumerable.Range(0, 10), x => player.Board[x, bottom].ItemId is not null); + Assert.Equal(4, Enumerable.Range(0, 10).Count(x => player.Board[x, bottom].ItemId is not null)); } [Fact] diff --git a/actionBlocks_server/tests/ActionBlocks.Game.Tests/TestHelpers.cs b/actionBlocks_server/tests/ActionBlocks.Game.Tests/TestHelpers.cs old mode 100644 new mode 100755 diff --git a/actionBlocks_website/.dockerignore b/actionBlocks_website/.dockerignore old mode 100644 new mode 100755 diff --git a/actionBlocks_website/.gitignore b/actionBlocks_website/.gitignore old mode 100644 new mode 100755 diff --git a/actionBlocks_website/Dockerfile b/actionBlocks_website/Dockerfile old mode 100644 new mode 100755 diff --git a/actionBlocks_website/docker/nginx.conf b/actionBlocks_website/docker/nginx.conf old mode 100644 new mode 100755 diff --git a/actionBlocks_website/index.html b/actionBlocks_website/index.html old mode 100644 new mode 100755 diff --git a/actionBlocks_website/package-lock.json b/actionBlocks_website/package-lock.json old mode 100644 new mode 100755 diff --git a/actionBlocks_website/package.json b/actionBlocks_website/package.json old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/favicon.svg b/actionBlocks_website/public/assets/favicon.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/items/add_line.svg b/actionBlocks_website/public/assets/items/add_line.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/items/blind.svg b/actionBlocks_website/public/assets/items/blind.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/items/clear_line.svg b/actionBlocks_website/public/assets/items/clear_line.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/items/nuke.svg b/actionBlocks_website/public/assets/items/nuke.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/items/swap.svg b/actionBlocks_website/public/assets/items/swap.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/items/unknown.svg b/actionBlocks_website/public/assets/items/unknown.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/sounds/README.md b/actionBlocks_website/public/assets/sounds/README.md old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/sounds/music/.gitkeep b/actionBlocks_website/public/assets/sounds/music/.gitkeep old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/ui/sound_off.svg b/actionBlocks_website/public/assets/ui/sound_off.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/assets/ui/sound_on.svg b/actionBlocks_website/public/assets/ui/sound_on.svg old mode 100644 new mode 100755 diff --git a/actionBlocks_website/public/config.js b/actionBlocks_website/public/config.js old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/App.module.css b/actionBlocks_website/src/App.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/App.tsx b/actionBlocks_website/src/App.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/AudioEngine.ts b/actionBlocks_website/src/audio/AudioEngine.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/MusicPlaylist.ts b/actionBlocks_website/src/audio/MusicPlaylist.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/SoundContext.tsx b/actionBlocks_website/src/audio/SoundContext.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/music.ts b/actionBlocks_website/src/audio/music.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/pitch.ts b/actionBlocks_website/src/audio/pitch.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/settings.ts b/actionBlocks_website/src/audio/settings.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/songs.ts b/actionBlocks_website/src/audio/songs.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/synthSounds.ts b/actionBlocks_website/src/audio/synthSounds.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/types.ts b/actionBlocks_website/src/audio/types.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/audio/useGameSounds.ts b/actionBlocks_website/src/audio/useGameSounds.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/BoardCanvas.module.css b/actionBlocks_website/src/components/BoardCanvas.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/BoardCanvas.tsx b/actionBlocks_website/src/components/BoardCanvas.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/CornerControls.module.css b/actionBlocks_website/src/components/CornerControls.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/CornerControls.tsx b/actionBlocks_website/src/components/CornerControls.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ItemBar.module.css b/actionBlocks_website/src/components/ItemBar.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ItemBar.tsx b/actionBlocks_website/src/components/ItemBar.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ItemFlashOverlay.module.css b/actionBlocks_website/src/components/ItemFlashOverlay.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ItemFlashOverlay.tsx b/actionBlocks_website/src/components/ItemFlashOverlay.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/Logo.module.css b/actionBlocks_website/src/components/Logo.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/Logo.tsx b/actionBlocks_website/src/components/Logo.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/MiniBoard.module.css b/actionBlocks_website/src/components/MiniBoard.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/MiniBoard.tsx b/actionBlocks_website/src/components/MiniBoard.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/MusicTracks.module.css b/actionBlocks_website/src/components/MusicTracks.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/MusicTracks.tsx b/actionBlocks_website/src/components/MusicTracks.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/PiecePreview.module.css b/actionBlocks_website/src/components/PiecePreview.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/PiecePreview.tsx b/actionBlocks_website/src/components/PiecePreview.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/SoundMenu.module.css b/actionBlocks_website/src/components/SoundMenu.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/SoundMenu.tsx b/actionBlocks_website/src/components/SoundMenu.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ui/Button.module.css b/actionBlocks_website/src/components/ui/Button.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ui/Button.tsx b/actionBlocks_website/src/components/ui/Button.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ui/Panel.module.css b/actionBlocks_website/src/components/ui/Panel.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/components/ui/Panel.tsx b/actionBlocks_website/src/components/ui/Panel.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/config/keybindings.ts b/actionBlocks_website/src/config/keybindings.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/config/runtimeConfig.ts b/actionBlocks_website/src/config/runtimeConfig.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/config/sound.ts b/actionBlocks_website/src/config/sound.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/input/useKeyboardInput.ts b/actionBlocks_website/src/input/useKeyboardInput.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/main.tsx b/actionBlocks_website/src/main.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/net/hubClient.ts b/actionBlocks_website/src/net/hubClient.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/net/types.ts b/actionBlocks_website/src/net/types.ts old mode 100644 new mode 100755 index 1af5ea3..b439307 --- a/actionBlocks_website/src/net/types.ts +++ b/actionBlocks_website/src/net/types.ts @@ -30,8 +30,8 @@ export interface JoinResult { export interface PieceInfo { type: number; - itemId: string | null; - itemIndex: number; + /** items[i] is the item in mino i, null if none. */ + items: (string | null)[]; } export interface ItemCell { @@ -43,8 +43,8 @@ export interface ItemCell { export interface ActivePieceState { type: number; cells: [number, number][]; - itemIndex: number; - itemId: string | null; + /** items[i] is the item in cells[i], null if none. */ + items: (string | null)[]; } export interface PlayerState { diff --git a/actionBlocks_website/src/net/useGameConnection.ts b/actionBlocks_website/src/net/useGameConnection.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/pages/GamePage.module.css b/actionBlocks_website/src/pages/GamePage.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/pages/GamePage.tsx b/actionBlocks_website/src/pages/GamePage.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/pages/HomePage.module.css b/actionBlocks_website/src/pages/HomePage.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/pages/HomePage.tsx b/actionBlocks_website/src/pages/HomePage.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/pages/LobbyPage.module.css b/actionBlocks_website/src/pages/LobbyPage.module.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/pages/LobbyPage.tsx b/actionBlocks_website/src/pages/LobbyPage.tsx old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/render/draw.ts b/actionBlocks_website/src/render/draw.ts old mode 100644 new mode 100755 index 3aae562..4045e51 --- a/actionBlocks_website/src/render/draw.ts +++ b/actionBlocks_website/src/render/draw.ts @@ -115,7 +115,8 @@ export function drawBoard( active.cells.forEach(([x, y], index) => { if (y < 0) return; drawBlock(ctx, x * cell, y * cell, cell, color); - if (active.itemId && index === active.itemIndex) drawItemIcon(ctx, x * cell, y * cell, cell, active.itemId); + const itemId = active.items[index]; + if (itemId) drawItemIcon(ctx, x * cell, y * cell, cell, itemId); }); } @@ -141,6 +142,7 @@ export function drawPreviewPiece( const px = Math.round(ox + x * cell); const py = Math.round(oy + y * cell); drawBlock(ctx, px, py, cell, color); - if (piece.itemId && index === piece.itemIndex) drawItemIcon(ctx, px, py, cell, piece.itemId); + const itemId = piece.items[index]; + if (itemId) drawItemIcon(ctx, px, py, cell, itemId); }); } diff --git a/actionBlocks_website/src/render/shapes.ts b/actionBlocks_website/src/render/shapes.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/theme/assets.ts b/actionBlocks_website/src/theme/assets.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/theme/colors.ts b/actionBlocks_website/src/theme/colors.ts old mode 100644 new mode 100755 diff --git a/actionBlocks_website/src/theme/global.css b/actionBlocks_website/src/theme/global.css old mode 100644 new mode 100755 diff --git a/actionBlocks_website/tsconfig.json b/actionBlocks_website/tsconfig.json old mode 100644 new mode 100755 diff --git a/actionBlocks_website/vite.config.ts b/actionBlocks_website/vite.config.ts old mode 100644 new mode 100755 diff --git a/doc/README.md b/doc/README.md old mode 100644 new mode 100755 diff --git a/doc/architecture.md b/doc/architecture.md old mode 100644 new mode 100755 diff --git a/doc/deployment.md b/doc/deployment.md old mode 100644 new mode 100755 index 454dd3c..e550a5c --- a/doc/deployment.md +++ b/doc/deployment.md @@ -59,7 +59,8 @@ cp .env.example .env | `ALLOWED_ORIGINS` | server | empty → any origin | Comma-separated list of origins allowed to connect, e.g. `https://game.example.com` | | `PATH_BASE` | server | empty | Prefix to accept if the proxy forwards a sub-path **without stripping it**, e.g. `/server` | | `HUB_PATH` | server | `/hub` | Hub endpoint path. It is fixed to `/hub` in the compose file | -| `Game__` | server | see `GameSettings.cs` | Overrides gameplay values, e.g. `Game__ItemSpawnChance=0.2`. Add these under the server's `environment:` in the compose file | +| `ITEM_SPAWN_CHANCE` | server | `0.1` | Chance (0..1) that each block of a new piece carries an item. Passed to the server as `Game__ItemSpawnChance` | +| `Game__` | server | see `GameSettings.cs` | Overrides other gameplay values, e.g. `Game__CountdownSeconds=5`. Add these under the server's `environment:` in the compose file | Start or update: diff --git a/doc/development.md b/doc/development.md old mode 100644 new mode 100755 diff --git a/doc/extending.md b/doc/extending.md old mode 100644 new mode 100755 index f6b4be9..4acb029 --- a/doc/extending.md +++ b/doc/extending.md @@ -95,11 +95,12 @@ All numbers are in `ActionBlocks.Game/GameSettings.cs`. There are two ways to ch ```yaml actionblocks-server: environment: - Game__ItemSpawnChance: "0.15" Game__MaxInventory: "6" Game__LockDelaySeconds: "0.6" ``` + The item chance already has its own variable: set `ITEM_SPAWN_CHANCE` in `.env` (the compose file passes it as `Game__ItemSpawnChance`). + To add a **new** setting, add an `init` property with a default to `GameSettings` and read it where needed. Configuration binding picks it up automatically. If you change the board width or height, the website adapts automatically, because `MatchState.width`/`height` drive the rendering. diff --git a/doc/frontend.md b/doc/frontend.md old mode 100644 new mode 100755 diff --git a/doc/game-rules.md b/doc/game-rules.md old mode 100644 new mode 100755 index b0b4c43..73909f4 --- a/doc/game-rules.md +++ b/doc/game-rules.md @@ -114,7 +114,7 @@ A player is eliminated when any of these happens: ### Spawning and collecting -- Each **newly generated** piece has a 10% chance (`GameSettings.ItemSpawnChance`) to carry an item. The item sits in one random mino of the four. The roll happens when the piece enters the queue, so items are already visible in the preview and in hold (`Items/ItemRegistry.cs`, `ItemSpawner`). +- Each of the four minos of a **newly generated** piece has its own 10% chance (`GameSettings.ItemSpawnChance`, env `ITEM_SPAWN_CHANCE`) to carry an item, so one piece can carry several items (up to four). Each item is picked separately. The roll happens when the piece enters the queue, so items are already visible in the preview and in hold (`Items/ItemRegistry.cs`, `ItemSpawner`). - When the piece locks, the item stays in that cell of the board. Item cells move with the board: they drop when lines below them clear, rise with garbage, and travel along when boards are swapped. - **Clearing the row that contains the item cell** moves the item into the player's inventory. - If the cell is destroyed another way (for example by *Clear Line* or *Wipe Out*), the item is lost. diff --git a/doc/protocol.md b/doc/protocol.md old mode 100644 new mode 100755 index f5c82f4..8e418f5 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -132,13 +132,12 @@ sequenceDiagram "active": { "type": 7, "cells": [[4,-1],[3,0],[4,0],[5,0]], - "itemIndex": 2, // which of the 4 cells carries the item, -1 if none - "itemId": "swap" + "items": [null, null, "swap", null] // items[i] is the item in cells[i], null if none }, "ghost": [[4,17],[3,18],[4,18],[5,18]], - "hold": { "type": 3, "itemId": null, "itemIndex": -1 }, + "hold": { "type": 3, "items": [null, null, null, null] }, "holdUsed": false, - "next": [ { "type": 4, "itemId": null, "itemIndex": -1 }, … ], + "next": [ { "type": 4, "items": ["nuke", null, null, "blind"] }, … ], "inventory": ["add_line", "blind"], // oldest first; inventory[0] is used by F "score": 1250, "lines": 12, diff --git a/doc/server.md b/doc/server.md old mode 100644 new mode 100755 index 41d9ffd..687aa1a --- a/doc/server.md +++ b/doc/server.md @@ -50,7 +50,7 @@ actionBlocks_server/ ```csharp readonly record struct Cell(byte Color, string? ItemId = null) // Color 0 = empty, 1-7 pieces, 8 garbage -sealed record PieceSpec(PieceType Type, string? ItemId, int ItemMinoIndex) // what sits in the queue +sealed record PieceSpec(PieceType Type, IReadOnlyList? Items) // what sits in the queue; Items[i] = item in mino i sealed record ActivePiece(PieceSpec Spec, int X, int Y, int Rotation) // a spec placed on the board ``` @@ -115,7 +115,7 @@ public sealed record ItemContext(PlayerGame User, PlayerGame Target, Random Rand ``` - `ItemRegistry.Default` lists all active items. `ItemRegistry.PickRandom` chooses an item weighted by `SpawnWeight`. -- `ItemSpawner.Decorate(type)` turns a raw piece type into a `PieceSpec`, sometimes with an item. +- `ItemSpawner.Decorate(type)` turns a raw piece type into a `PieceSpec`. Each mino rolls `ItemSpawnChance` on its own, so a piece can carry 0–4 items. See [Extending → Add an item](extending.md#add-a-new-item). diff --git a/docker-compose.yml b/docker-compose.yml old mode 100644 new mode 100755 index bfbb46f..414a09a --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,7 @@ services: ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-} HUB_PATH: /hub PATH_BASE: ${PATH_BASE:-} + Game__ItemSpawnChance: ${ITEM_SPAWN_CHANCE:-0.1} networks: - actionBlocks_server diff --git a/instructions.md b/instructions.md old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki.html b/tetris_instructions/Tetris Guideline - TetrisWiki.html old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/250px-The_Tetris_Company_logo_2019.png b/tetris_instructions/Tetris Guideline - TetrisWiki_files/250px-The_Tetris_Company_logo_2019.png old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/500px-Tetrominoes.png b/tetris_instructions/Tetris Guideline - TetrisWiki_files/500px-Tetrominoes.png old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/88x31.png b/tetris_instructions/Tetris Guideline - TetrisWiki_files/88x31.png old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/gtm.js b/tetris_instructions/Tetris Guideline - TetrisWiki_files/gtm.js old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/load(1).php b/tetris_instructions/Tetris Guideline - TetrisWiki_files/load(1).php old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/load(2).php b/tetris_instructions/Tetris Guideline - TetrisWiki_files/load(2).php old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/load.php b/tetris_instructions/Tetris Guideline - TetrisWiki_files/load.php old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/poweredby_mediawiki.svg b/tetris_instructions/Tetris Guideline - TetrisWiki_files/poweredby_mediawiki.svg old mode 100644 new mode 100755 diff --git a/tetris_instructions/Tetris Guideline - TetrisWiki_files/vce701823e78c4301a35b7e07294d87301792088814092 b/tetris_instructions/Tetris Guideline - TetrisWiki_files/vce701823e78c4301a35b7e07294d87301792088814092 old mode 100644 new mode 100755