|
<script lang="ts"> |
|
import { fade } from 'svelte/transition'; |
|
import type { PicletInstance } from '$lib/db/schema'; |
|
import LLMBattleEngine from '../Battle/LLMBattleEngine.svelte'; |
|
import type { GradioClient } from '$lib/types'; |
|
|
|
interface Props { |
|
playerPiclet: PicletInstance; |
|
enemyPiclet: PicletInstance; |
|
isWildBattle: boolean; |
|
rosterPiclets?: PicletInstance[]; |
|
onBattleEnd: (result: { winner: 'player' | 'enemy'; capturedPiclet?: PicletInstance }) => void; |
|
commandClient: GradioClient; |
|
} |
|
|
|
let { playerPiclet, enemyPiclet, isWildBattle, rosterPiclets, onBattleEnd, commandClient }: Props = $props(); |
|
|
|
|
|
let battleEnded = $state(false); |
|
let battleResult: { winner: 'player' | 'enemy'; capturedPiclet?: PicletInstance } | null = $state(null); |
|
|
|
|
|
function handleBattleEnd(winner: 'player' | 'enemy') { |
|
battleEnded = true; |
|
|
|
|
|
battleResult = { winner }; |
|
|
|
|
|
setTimeout(() => { |
|
onBattleEnd(battleResult!); |
|
}, 2000); |
|
} |
|
</script> |
|
|
|
<div class="battle-page" transition:fade> |
|
|
|
<div class="battle-header"> |
|
<h2>{isWildBattle ? 'Wild Battle' : 'Trainer Battle'}</h2> |
|
<div class="battle-participants"> |
|
<div class="participant player"> |
|
<img src={playerPiclet.imageUrl} alt={playerPiclet.typeId} /> |
|
<h3>{playerPiclet.typeId}</h3> |
|
<span class="tier tier-{playerPiclet.tier}">{playerPiclet.tier}</span> |
|
</div> |
|
|
|
<div class="vs-indicator"> |
|
<span>VS</span> |
|
</div> |
|
|
|
<div class="participant enemy"> |
|
<img src={enemyPiclet.imageUrl} alt={enemyPiclet.typeId} /> |
|
<h3>{enemyPiclet.typeId}</h3> |
|
<span class="tier tier-{enemyPiclet.tier}">{enemyPiclet.tier}</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="battle-main"> |
|
{#if !battleEnded} |
|
<LLMBattleEngine |
|
{playerPiclet} |
|
{enemyPiclet} |
|
{rosterPiclets} |
|
{commandClient} |
|
onBattleEnd={handleBattleEnd} |
|
/> |
|
{:else} |
|
<div class="battle-results"> |
|
<h2>{battleResult?.winner === 'player' ? 'π Victory!' : 'π Defeat!'}</h2> |
|
|
|
{#if battleResult?.winner === 'player'} |
|
<p>You defeated {enemyPiclet.typeId}!</p> |
|
{:else} |
|
<p>{playerPiclet.typeId} was defeated by {enemyPiclet.typeId}...</p> |
|
<p>Better luck next time!</p> |
|
{/if} |
|
</div> |
|
{/if} |
|
</div> |
|
</div> |
|
|
|
<style> |
|
.battle-page { |
|
height: 100vh; |
|
display: flex; |
|
flex-direction: column; |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
color: white; |
|
} |
|
|
|
.battle-header { |
|
padding: 1rem; |
|
text-align: center; |
|
background: rgba(0, 0, 0, 0.1); |
|
backdrop-filter: blur(10px); |
|
} |
|
|
|
.battle-participants { |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
gap: 2rem; |
|
margin-top: 1rem; |
|
} |
|
|
|
.participant { |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
gap: 0.5rem; |
|
} |
|
|
|
.participant img { |
|
width: 80px; |
|
height: 80px; |
|
object-fit: cover; |
|
border-radius: 50%; |
|
border: 3px solid rgba(255, 255, 255, 0.3); |
|
} |
|
|
|
.participant.player img { |
|
border-color: #007bff; |
|
} |
|
|
|
.participant.enemy img { |
|
border-color: #dc3545; |
|
} |
|
|
|
.tier { |
|
padding: 0.25rem 0.5rem; |
|
border-radius: 12px; |
|
font-size: 0.8rem; |
|
font-weight: bold; |
|
text-transform: uppercase; |
|
} |
|
|
|
.tier-low { background: #6c757d; } |
|
.tier-medium { background: #28a745; } |
|
.tier-high { background: #fd7e14; } |
|
.tier-legendary { background: #dc3545; } |
|
|
|
.vs-indicator { |
|
font-size: 2rem; |
|
font-weight: bold; |
|
color: #ffd700; |
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); |
|
} |
|
|
|
.battle-main { |
|
flex: 1; |
|
display: flex; |
|
flex-direction: column; |
|
background: white; |
|
color: #333; |
|
border-radius: 20px 20px 0 0; |
|
overflow: hidden; |
|
} |
|
|
|
.battle-results { |
|
flex: 1; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
justify-content: center; |
|
text-align: center; |
|
padding: 2rem; |
|
gap: 1rem; |
|
} |
|
|
|
.battle-results h2 { |
|
font-size: 2.5rem; |
|
margin: 0; |
|
} |
|
|
|
</style> |