Split Deep challenge stakes into success and failure fields

The Deep now states what happens on success and on failure as two
separate fields when calling a Challenge, instead of one free-text
stakes blob. ChallengePanel shows them as " On success" / " On
failure"; the event log lists both.

- Challenge.stakes_success / stakes_failure (+ migration); the old
  single `stakes` column is kept (vestigial) so in-scene rollback
  snapshots taken before the upgrade still deserialize, and ChallengePanel
  falls back to it for any pre-existing challenge.
- create_challenge / route / DeepControlPanel updated; tests adjusted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 09:28:38 -07:00
parent 5a8919d967
commit 39dc07d6b6
8 changed files with 77 additions and 24 deletions

View File

@@ -78,7 +78,13 @@
</div>
{/if}
</div>
{#if ch.stakes}
{#if ch.stakes_success}
<p class="info-text" style="margin: 0.5rem 0 0 0;"><strong>✅ On success:</strong> {ch.stakes_success}</p>
{/if}
{#if ch.stakes_failure}
<p class="info-text" style="margin: 0.25rem 0 0 0;"><strong>❌ On failure:</strong> {ch.stakes_failure}</p>
{/if}
{#if ch.stakes && !ch.stakes_success && !ch.stakes_failure}
<p class="info-text" style="margin: 0.5rem 0 0 0;"><strong>Stakes:</strong> {ch.stakes}</p>
{/if}
{#if ch.challenge_type === 'pvp'}

View File

@@ -6,7 +6,8 @@
let error = '';
let challengeTargetId = '';
let challengeStakes = '';
let stakesSuccess = '';
let stakesFailure = '';
let selectedObstacles = {};
let captainSelectId = '';
@@ -21,10 +22,12 @@
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/challenge/create`, 'POST', {
target_player_id: challengeTargetId,
obstacle_ids: JSON.stringify(ids),
stakes: challengeStakes
stakes_success: stakesSuccess,
stakes_failure: stakesFailure
});
challengeTargetId = '';
challengeStakes = '';
stakesSuccess = '';
stakesFailure = '';
selectedObstacles = {};
} catch(e) {
error = e.message;
@@ -88,7 +91,8 @@
</label>
{/each}
</div>
<input type="text" class="input-field" placeholder="Stakes (optional): what happens on success/failure?" bind:value={challengeStakes} style="width: 100%; margin-bottom: 0.5rem;">
<input type="text" class="input-field" placeholder="On success (optional): what they win…" bind:value={stakesSuccess} style="width: 100%; margin-bottom: 0.5rem;">
<input type="text" class="input-field" placeholder="On failure (optional): what it costs them…" bind:value={stakesFailure} style="width: 100%; margin-bottom: 0.5rem;">
<button class="btn btn-primary btn-full" on:click={createChallenge}
disabled={!challengeTargetId || !Object.values(selectedObstacles).some(v => v)}>
Call Challenge