133 lines
3.4 KiB
Svelte
133 lines
3.4 KiB
Svelte
<script lang="ts">
|
|
import * as skill from '$lib/data/skill';
|
|
import * as spark from '$lib/data/spark';
|
|
import { onMount } from 'svelte';
|
|
import { SvelteMap } from 'svelte/reactivity';
|
|
|
|
let sparks: spark.Spark[] = $state([]);
|
|
let skills: SvelteMap<number, skill.Skill> = new SvelteMap();
|
|
onMount(async () => {
|
|
const [sp, sk] = await Promise.all([spark.sparks(), skill.skills()]);
|
|
sparks = sp;
|
|
for (const s of sk) {
|
|
skills.set(s.skill_id, s);
|
|
}
|
|
});
|
|
|
|
let group = $state(1);
|
|
|
|
const groups = $derived.by(() => {
|
|
const m = new SvelteMap<number, spark.Spark[]>();
|
|
for (const s of sparks) {
|
|
const l = m.get(s.spark_group) ?? [];
|
|
l.push(s);
|
|
m.set(s.spark_group, l);
|
|
}
|
|
return [...m.entries()];
|
|
});
|
|
function describe(eff: spark.Effect) {
|
|
if (eff.target === spark.Target.Skill) {
|
|
const sk = skills.get(eff.value1);
|
|
return `${sk?.name} ${spark.TARGET_NAMES[eff.target]} +${eff.value2}`;
|
|
}
|
|
return `${spark.TARGET_NAMES[eff.target]} +${eff.value1}`;
|
|
}
|
|
const cur = $derived(sparks.find((s) => s.spark_group === group));
|
|
const curEffectGroups = $derived(cur?.effects ?? []);
|
|
const curDescriptions = $derived(curEffectGroups.map((g) => g.map((e) => describe(e))));
|
|
const curClass = $derived.by(() => {
|
|
if (cur == null) {
|
|
return [];
|
|
}
|
|
switch (cur.type) {
|
|
case 1:
|
|
return ['stat'];
|
|
case 2:
|
|
return ['aptitude'];
|
|
case 3:
|
|
return ['unique'];
|
|
case 5:
|
|
case 4:
|
|
case 6:
|
|
case 10:
|
|
case 8:
|
|
case 11:
|
|
case 9:
|
|
return ['white-spark'];
|
|
default:
|
|
return [];
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<h1 class="text-4xl">Spark Explorer</h1>
|
|
<form class="mx-auto mt-8 rounded-md p-4 text-center shadow-md ring md:max-w-2xl">
|
|
<select class="w-full" bind:value={group}>
|
|
{#each groups as [id, s] (id)}
|
|
<option value={id}>{s[0].name}</option>
|
|
{/each}
|
|
</select>
|
|
</form>
|
|
<svelte:boundary>
|
|
<div
|
|
class={[
|
|
'spark mx-auto mt-8 max-w-md flex-1 flex-col rounded-md border p-2 text-center shadow-sm transition-shadow hover:shadow-md',
|
|
curClass,
|
|
]}
|
|
>
|
|
<span class="block text-xl">{cur?.name}</span>
|
|
{#if cur != null}
|
|
<span class="block">
|
|
{spark.TYPE_NAMES[cur.type]} Spark
|
|
</span>
|
|
{/if}
|
|
<span class="block">{cur?.description}</span>
|
|
</div>
|
|
<table class="mx-auto mt-8 w-full max-w-xl table-fixed">
|
|
<caption class="text-xl">Possible Effects</caption>
|
|
<tbody>
|
|
{#each curDescriptions as s (s)}
|
|
<tr class="text-center even:bg-mist-300 dark:even:bg-mist-900">
|
|
<td>
|
|
{#each s as n (n)}
|
|
<span class="block">{n}</span>
|
|
{/each}
|
|
</td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
|
|
{#snippet pending()}
|
|
<div>Loading data...</div>
|
|
{/snippet}
|
|
</svelte:boundary>
|
|
<div class="mx-auto mt-12 w-full max-w-4xl border-t pt-4 md:mt-8">
|
|
<p>
|
|
When a spark activates during inspiration, it has an additional random roll for one of the effects listed in the table here.
|
|
All star levels of each spark have the same possible effects. Higher star levels are more likely to give better rewards.
|
|
</p>
|
|
</div>
|
|
|
|
<style>
|
|
.white-spark {
|
|
--spark-color: light-dark(var(--color-mist-200), var(--color-mist-800));
|
|
}
|
|
|
|
.stat {
|
|
--spark-color: light-dark(var(--color-sky-200), var(--color-sky-800));
|
|
}
|
|
|
|
.aptitude {
|
|
--spark-color: light-dark(var(--color-rose-300), var(--color-rose-800));
|
|
}
|
|
|
|
.unique {
|
|
--spark-color: light-dark(var(--color-lime-400), var(--color-lime-800));
|
|
}
|
|
|
|
.spark {
|
|
background-color: var(--spark-color);
|
|
}
|
|
</style>
|