From 09c9a50e0b7dd6421598a7faea1bdf3f3b3db60d Mon Sep 17 00:00:00 2001 From: Doar Mihai Date: Sun, 28 Jun 2026 18:12:12 +0300 Subject: [PATCH] docs: add escape from jail design spec --- .../2026-06-28-escape-from-jail-design.md | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-28-escape-from-jail-design.md diff --git a/docs/superpowers/specs/2026-06-28-escape-from-jail-design.md b/docs/superpowers/specs/2026-06-28-escape-from-jail-design.md new file mode 100644 index 0000000..af30550 --- /dev/null +++ b/docs/superpowers/specs/2026-06-28-escape-from-jail-design.md @@ -0,0 +1,138 @@ +# Escape from Jail — Design Spec + +**Date:** 2026-06-28 +**Status:** Approved + +--- + +## Overview + +Add a **Bust Out** mechanic to the jail page. A jailed character can spend cash to attempt an escape. Success rate is based on `dexterity + speed` stats. Success releases immediately; failure multiplies remaining sentence by 1.5×. Cash is always deducted regardless of outcome. + +--- + +## Data Model + +No new tables or columns required. Uses existing `characters.status` and `characters.in_jail_until`. + +--- + +## Bust-Out Mechanics + +### Cost +1000 cash (from `config('game.jail.breakout_cost')`). Deducted whether the attempt succeeds or fails. + +### Success Rate Formula +``` +success_rate = min( + config('game.jail.bust_out_max_chance'), + config('game.jail.breakout_chance') + (dexterity + speed) * config('game.jail.bust_out_stat_multiplier') +) +``` + +With defaults: +- `breakout_chance` = 0.05 (existing) +- `bust_out_stat_multiplier` = 0.003 (new) +- `bust_out_max_chance` = 0.80 (new) + +A fresh character (dex=5, speed=5) starts at **8%**. A well-trained character (dex=50, speed=50) reaches **35%**. Max possible is **80%**. + +### On Success +- Deduct `breakout_cost` cash +- Set `status → active` +- Set `in_jail_until → null` +- Redirect to `game.dashboard` with success flash + +### On Failure +- Deduct `breakout_cost` cash +- Multiply remaining jail time by `sentence_multiplier` (1.5×): + `in_jail_until = now()->addSeconds(ceil($character->in_jail_until->diffInSeconds(now()) * 1.5))` +- Redirect back to `game.jail` with failure flash showing new release time + +--- + +## Config Changes (`config/game.php`) + +Add two keys to the existing `jail` block: + +```php +'jail' => [ + 'sentence_length' => 3600, + 'breakout_chance' => 0.05, + 'breakout_cost' => 1000, + 'sentence_multiplier' => 1.5, + 'bust_out_stat_multiplier' => 0.003, // per combined dex+speed point + 'bust_out_max_chance' => 0.80, // cap at 80% +], +``` + +--- + +## New Files + +| File | Purpose | +|------|---------| +| `app/Services/Game/JailService.php` | `bustOut(Character): array`, `sendToJail(Character, int): void`, `releaseFromJail(Character): void` | +| `app/Http/Controllers/Game/JailController.php` | `bustOut(Request): RedirectResponse` | + +### `JailService` interface + +```php +/** + * @return array{success: bool, message: string} + */ +public function bustOut(Character $character): array + +public function sendToJail(Character $character, int $seconds): void + +public function releaseFromJail(Character $character): void +``` + +`bustOut()` returns `['success' => true/false, 'message' => string]`. The message is a human-readable outcome description suitable for a flash notice. + +--- + +## Modified Files + +| File | Change | +|------|--------| +| `config/game.php` | Add `bust_out_stat_multiplier` and `bust_out_max_chance` to `jail` block | +| `resources/views/game/jail.blade.php` | Add Bust Out card below status card | +| `routes/game.php` | Add `POST /game/jail/bust-out` → `JailController@bustOut` | + +--- + +## Routes + +```php +Route::middleware(['auth'])->group(function () { + Route::post('/game/jail/bust-out', [JailController::class, 'bustOut'])->name('game.jail.bust-out'); +}); +``` + +The bust-out route lives in the same `auth`-only group as the existing jail view route (no `verify.character` needed — jailed characters can't have characters, but do need auth). + +--- + +## UI — Jail Page + +Dark crime theme, consistent with existing pages. + +**Bust Out card** sits below the existing status card. Contains: +- Success percentage (calculated from character stats, shown as e.g. "12% chance") +- Cash cost ("Costs $1,000") +- "Bust Out" button — disabled with tooltip if character has < 1000 cash +- CSRF-protected POST form + +**Flash messages:** +- Success: "You escaped! You're free." → redirects to dashboard +- Failure: "Bust failed — your sentence was extended to [new release time]." → stays on jail page + +--- + +## Out of Scope (this iteration) + +- Busting out another player (requires PvP) +- Nerve/energy cost for bust attempts +- Per-attempt cooldown (failure penalty is time extension only) +- Bust attempt history / activity log entry (can add later) \ No newline at end of file