|
<script lang="ts"> |
|
import type { PicletInstance } from '$lib/db/schema'; |
|
import { db } from '$lib/db'; |
|
import ActionButtons from './ActionButtons.svelte'; |
|
|
|
export let currentMessage: string; |
|
export let battlePhase: 'intro' | 'main' | 'moveSelect' | 'picletSelect' | 'ended'; |
|
export let processingTurn: boolean; |
|
export let battleEnded: boolean; |
|
export let isWildBattle: boolean; |
|
export let playerPiclet: PicletInstance; |
|
export let onAction: (action: string) => void; |
|
export let onMoveSelect: (move: any) => void; |
|
export let onPicletSelect: (piclet: PicletInstance) => void; |
|
export let onBack: () => void; |
|
|
|
let availablePiclets: PicletInstance[] = []; |
|
|
|
|
|
async function loadRoster() { |
|
const roster = await db.picletInstances |
|
.where('isInRoster') |
|
.equals(1) |
|
.toArray(); |
|
availablePiclets = roster.filter(p => p.currentHp > 0 && p.id !== playerPiclet.id); |
|
} |
|
|
|
$: if (battlePhase === 'picletSelect') { |
|
loadRoster(); |
|
} |
|
</script> |
|
|
|
<div class="battle-controls"> |
|
|
|
<div class="message-bar {battleEnded ? 'special' : ''}"> |
|
<p>{currentMessage}</p> |
|
</div> |
|
|
|
|
|
<div class="action-area"> |
|
{#if battlePhase === 'main' && !processingTurn && !battleEnded} |
|
<ActionButtons |
|
{isWildBattle} |
|
{onAction} |
|
/> |
|
{:else if battlePhase === 'moveSelect'} |
|
<div class="move-select"> |
|
<div class="section-header"> |
|
<h3>Select a move</h3> |
|
<button class="back-btn" on:click={onBack}>← Back</button> |
|
</div> |
|
<div class="moves-grid"> |
|
{#each playerPiclet.moves as move} |
|
<button |
|
class="move-button" |
|
on:click={() => onMoveSelect(move)} |
|
disabled={move.currentPp <= 0} |
|
> |
|
<span class="move-name">{move.name}</span> |
|
<span class="move-type">{move.type}</span> |
|
<span class="move-pp">PP: {move.currentPp}/{move.pp}</span> |
|
</button> |
|
{/each} |
|
</div> |
|
</div> |
|
{:else if battlePhase === 'picletSelect'} |
|
<div class="piclet-select"> |
|
<div class="section-header"> |
|
<h3>Select a Piclet</h3> |
|
<button class="back-btn" on:click={onBack}>← Back</button> |
|
</div> |
|
<div class="piclets-list"> |
|
{#if availablePiclets.length === 0} |
|
<p class="no-piclets">No other healthy Piclets available!</p> |
|
{:else} |
|
{#each availablePiclets as piclet} |
|
<button |
|
class="piclet-option" |
|
on:click={() => onPicletSelect(piclet)} |
|
> |
|
<img |
|
src={piclet.imageUrl} |
|
alt={piclet.nickname} |
|
on:error={(e) => e.currentTarget.src = 'https://via.placeholder.com/50x50?text=P'} |
|
/> |
|
<div class="piclet-details"> |
|
<span class="piclet-name">{piclet.nickname}</span> |
|
<span class="piclet-stats">Lv.{piclet.level} - HP: {piclet.currentHp}/{piclet.maxHp}</span> |
|
</div> |
|
<div class="hp-preview"> |
|
<div class="hp-preview-bar"> |
|
<div |
|
class="hp-preview-fill" |
|
style="width: {(piclet.currentHp / piclet.maxHp) * 100}%" |
|
></div> |
|
</div> |
|
</div> |
|
</button> |
|
{/each} |
|
{/if} |
|
</div> |
|
</div> |
|
{:else if battleEnded} |
|
<div class="battle-end"> |
|
<button class="continue-btn" on:click={() => window.history.back()}> |
|
Continue |
|
</button> |
|
</div> |
|
{/if} |
|
</div> |
|
</div> |
|
|
|
<style> |
|
.battle-controls { |
|
flex: 1; |
|
display: flex; |
|
flex-direction: column; |
|
background: white; |
|
border-top: 1px solid #e0e0e0; |
|
} |
|
|
|
.message-bar { |
|
padding: 1rem; |
|
background: #f8f9fa; |
|
border-bottom: 1px solid #e0e0e0; |
|
text-align: center; |
|
} |
|
|
|
.message-bar.special { |
|
background: rgba(255, 152, 0, 0.1); |
|
border-color: rgba(255, 152, 0, 0.3); |
|
} |
|
|
|
.message-bar p { |
|
margin: 0; |
|
font-size: 1rem; |
|
color: #333; |
|
} |
|
|
|
.action-area { |
|
flex: 1; |
|
padding: 1rem; |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
|
|
|
|
.move-select, .piclet-select { |
|
display: flex; |
|
flex-direction: column; |
|
height: 100%; |
|
} |
|
|
|
.section-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.section-header h3 { |
|
margin: 0; |
|
font-size: 1.125rem; |
|
color: #1a1a1a; |
|
} |
|
|
|
.back-btn { |
|
background: none; |
|
border: none; |
|
color: #007bff; |
|
font-size: 0.875rem; |
|
cursor: pointer; |
|
padding: 0.25rem 0.5rem; |
|
} |
|
|
|
.moves-grid { |
|
display: grid; |
|
grid-template-columns: repeat(2, 1fr); |
|
gap: 0.75rem; |
|
} |
|
|
|
.move-button { |
|
padding: 1rem; |
|
background: #f8f9fa; |
|
border: 2px solid #e0e0e0; |
|
border-radius: 8px; |
|
cursor: pointer; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: flex-start; |
|
gap: 0.25rem; |
|
transition: all 0.2s ease; |
|
} |
|
|
|
.move-button:hover:not(:disabled) { |
|
background: #e9ecef; |
|
border-color: #007bff; |
|
} |
|
|
|
.move-button:disabled { |
|
opacity: 0.5; |
|
cursor: not-allowed; |
|
} |
|
|
|
.move-name { |
|
font-weight: 600; |
|
color: #1a1a1a; |
|
} |
|
|
|
.move-type { |
|
font-size: 0.75rem; |
|
color: #666; |
|
text-transform: uppercase; |
|
} |
|
|
|
.move-pp { |
|
font-size: 0.75rem; |
|
color: #999; |
|
} |
|
|
|
|
|
.piclets-list { |
|
flex: 1; |
|
overflow-y: auto; |
|
display: flex; |
|
flex-direction: column; |
|
gap: 0.5rem; |
|
} |
|
|
|
.no-piclets { |
|
text-align: center; |
|
color: #666; |
|
padding: 2rem; |
|
} |
|
|
|
.piclet-option { |
|
display: flex; |
|
align-items: center; |
|
gap: 1rem; |
|
padding: 0.75rem; |
|
background: #f8f9fa; |
|
border: 2px solid #e0e0e0; |
|
border-radius: 8px; |
|
cursor: pointer; |
|
transition: all 0.2s ease; |
|
} |
|
|
|
.piclet-option:hover { |
|
background: #e9ecef; |
|
border-color: #007bff; |
|
} |
|
|
|
.piclet-option img { |
|
width: 50px; |
|
height: 50px; |
|
object-fit: cover; |
|
border-radius: 4px; |
|
} |
|
|
|
.piclet-details { |
|
flex: 1; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: flex-start; |
|
} |
|
|
|
.piclet-name { |
|
font-weight: 600; |
|
color: #1a1a1a; |
|
} |
|
|
|
.piclet-stats { |
|
font-size: 0.75rem; |
|
color: #666; |
|
} |
|
|
|
.hp-preview { |
|
width: 80px; |
|
} |
|
|
|
.hp-preview-bar { |
|
height: 6px; |
|
background: #e0e0e0; |
|
border-radius: 3px; |
|
overflow: hidden; |
|
} |
|
|
|
.hp-preview-fill { |
|
height: 100%; |
|
background: #4caf50; |
|
transition: width 0.3s ease; |
|
} |
|
|
|
|
|
.battle-end { |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
height: 100%; |
|
} |
|
|
|
.continue-btn { |
|
padding: 1rem 2rem; |
|
background: #007bff; |
|
color: white; |
|
border: none; |
|
border-radius: 8px; |
|
font-size: 1rem; |
|
font-weight: 600; |
|
cursor: pointer; |
|
transition: background 0.2s ease; |
|
} |
|
|
|
.continue-btn:hover { |
|
background: #0056b3; |
|
} |
|
</style> |