Dead Pi-Rat reroll rework

This commit is contained in:
2026-06-12 11:32:15 -07:00
parent df7a0cc83f
commit f61201144f
18 changed files with 908 additions and 460 deletions

View File

@@ -1,6 +1,5 @@
<script>
import { apiRequest } from '../lib/api';
import { getSuggestion } from '../lib/suggestions';
import { displayName } from '../lib/cards';
import Card from './Card.svelte';
@@ -20,16 +19,7 @@
let discardCards = [];
let dragNDropInitialized = false;
// Ghost & Re-rolling fate states
let isRolling = false;
let reRollDetails = {
avatar_look: '',
avatar_smell: '',
first_words: '',
good_at_math: ''
};
let rollingError = '';
// Ghost & Re-rolling fate choice
async function becomeGhost() {
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/become-ghost`, 'POST');
@@ -38,6 +28,14 @@
}
}
async function chooseReRoll() {
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/choose-reroll`, 'POST');
} catch(e) {
console.error(e);
}
}
async function finishGame() {
if (!confirm('End the story for everyone? Best saved for when every player has played the Deep, each Pi-Rat has completed a Personal Objective, and all 3 Crew Objectives are done.')) return;
try {
@@ -47,30 +45,6 @@
}
}
async function submitReRoll() {
if (!reRollDetails.avatar_look.trim() ||
!reRollDetails.avatar_smell.trim() ||
!reRollDetails.first_words.trim() ||
!reRollDetails.good_at_math.trim()) {
rollingError = 'Please fill out all character details.';
return;
}
rollingError = '';
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/roll-new-character`, 'POST', reRollDetails);
isRolling = false;
// Clear inputs
reRollDetails = {
avatar_look: '',
avatar_smell: '',
first_words: '',
good_at_math: ''
};
} catch(e) {
rollingError = e.message;
}
}
$: {
if (state && state.game.phase === 'deep_upkeep') {
if (!dragNDropInitialized) {
@@ -182,74 +156,31 @@
<h2>Between Scenes (Scene #{state.game.current_scene_number} Concluded)</h2>
<p class="description">Upkeep and tallying. Nominate a crewmate to Rank Up, redraw hand cards for resting Deep players, and ready up for the next scene.</p>
{#if state.player.is_dead && !state.player.is_ghost}
{#if state.player.is_dead && !state.player.is_ghost && !state.player.needs_reroll}
<!-- Death Fate Panel -->
<div class="glass-panel death-fate-card">
<h2>💀 Your Pi-Rat Has Died!</h2>
<p class="description">
Your story arc is complete! You went out in a blaze of glory (or retired honorably). You must now choose how your journey continues:
</p>
{#if !isRolling}
<div class="fate-choices">
<button class="btn btn-secondary btn-large glow-effect" on:click={becomeGhost}>
👻 Remain as a Ghost
</button>
<button class="btn btn-primary btn-large glow-effect" on:click={() => isRolling = true}>
🐀 Roll a New Character
</button>
</div>
<p class="info-text italic" style="margin-top: 1.5rem;">
Ghosts look back into the living world, watch over friends, and help their crew. New recruits start fresh at Rank 1 with surprise Secret Techniques and a name based on their smell.
</p>
{:else}
<div class="creation-form-wrapper">
<h3>Create Your New Recruit</h3>
{#if rollingError}
<div class="alert alert-danger" style="margin-bottom: 1.5rem;">{rollingError}</div>
{/if}
<div class="form-group">
<label>What does your Pi-Rat look like?</label>
<div class="input-row">
<input type="text" placeholder="e.g. Scruffy snout, wearing a tattered vest" bind:value={reRollDetails.avatar_look} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.avatar_look = getSuggestion('look')}>Suggest</button>
</div>
</div>
<div class="form-group">
<label>What does your Pi-Rat smell like? (Determines name)</label>
<div class="input-row">
<input type="text" placeholder="e.g. Spiced rum, salty cheese, gunpowder" bind:value={reRollDetails.avatar_smell} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.avatar_smell = getSuggestion('smell')}>Suggest</button>
</div>
</div>
<div class="form-group">
<label>What were your first words after transforming?</label>
<div class="input-row">
<input type="text" placeholder="e.g. Shiver my decimals!" bind:value={reRollDetails.first_words} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.first_words = getSuggestion('first_words')}>Suggest</button>
</div>
</div>
<div class="form-group">
<label>Is your Pi-Rat good at Math?</label>
<div class="input-row">
<input type="text" placeholder="e.g. Thinks Pi is a dessert" bind:value={reRollDetails.good_at_math} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.good_at_math = getSuggestion('good_at_math')}>Suggest</button>
</div>
</div>
<div class="form-actions">
<button class="btn btn-secondary" on:click={() => isRolling = false}>Cancel</button>
<button class="btn btn-primary" on:click={submitReRoll}>Submit New Character</button>
</div>
</div>
{/if}
<div class="fate-choices">
<button class="btn btn-secondary btn-large glow-effect" on:click={becomeGhost}>
👻 Remain as a Ghost
</button>
<button class="btn btn-primary btn-large glow-effect" on:click={chooseReRoll}>
🐀 Roll a New Character
</button>
</div>
<p class="info-text italic" style="margin-top: 1.5rem;">
Ghosts look back into the living world, watch over friends, and help their crew. New recruits start fresh at Rank 1 — after upkeep, the whole crew will help create them.
</p>
</div>
{:else}
{#if state.player.needs_reroll}
<div class="notice-banner" style="margin-bottom: 1rem;">
<p style="margin: 0;">🐀 A fresh recruit is on the way! Once upkeep wraps up, you and the crew will create your new Pi-Rat together.</p>
</div>
{/if}
<div class="between-grid">
<!-- Ranks and Voting Card -->
<div class="card glass-panel voting-card">