piclets / src /lib /components /Battle /BattleControls.svelte
Fraser's picture
MORE
7428b13
raw
history blame
7.23 kB
<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[] = [];
// Load player's roster
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">
<!-- Message Bar -->
<div class="message-bar {battleEnded ? 'special' : ''}">
<p>{currentMessage}</p>
</div>
<!-- Action Area -->
<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 Selection */
.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;
}
/* Piclet Selection */
.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 */
.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>