zenno/chara/convo: include character icons
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline failed

This commit is contained in:
2026-09-06 14:21:09 -04:00
parent 869235a8c2
commit ad02e0711d
2 changed files with 33 additions and 22 deletions
+5 -1
View File
@@ -43,10 +43,14 @@ export enum Required {
Chara3 = 4, Chara3 = 4,
} }
export function convoCharas(c: Conversation): number[] {
return [c.chara_1, c.chara_2, c.chara_3].filter((id) => id != null);
}
export function requiredCharas(c: Conversation): number[] { export function requiredCharas(c: Conversation): number[] {
switch (c.condition_type) { switch (c.condition_type) {
case Required.None: return [] case Required.None: return []
case Required.All: return [c.chara_1, c.chara_2, c.chara_3].filter((id) => id != null); case Required.All: return convoCharas(c);
case Required.Chara1: return [c.chara_1]; case Required.Chara1: return [c.chara_1];
case Required.Chara2: return [c.chara_2!]; case Required.Chara2: return [c.chara_2!];
case Required.Chara3: return [c.chara_3!]; case Required.Chara3: return [c.chara_3!];
+28 -21
View File
@@ -1,15 +1,24 @@
<script lang="ts"> <script lang="ts">
import { character, charaNames, type Character } from '$lib/data/character'; import { character, charaNames, type Character } from '$lib/data/character';
import { byChara, locations, groupPopulars, conversation, type Conversation, requiredCharas } from '$lib/data/convo'; import {
byChara,
locations,
groupPopulars,
conversation,
type Conversation,
requiredCharas,
convoCharas,
} from '$lib/data/convo';
import CharaPick from '$lib/CharaPick.svelte'; import CharaPick from '$lib/CharaPick.svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import CharaIcon from '$lib/CharaIcon.svelte';
let conversations: Conversation[] = $state([]); let conversations: Conversation[] = $state([]);
const convoMap = $derived(byChara(conversations)); const convoMap = $derived(byChara(conversations));
const popular = $derived(groupPopulars(conversations)); const popular = $derived(groupPopulars(conversations));
let characters: Character[] = $state([]); let characters: Character[] = $state([]);
const selCharas = $derived(characters.filter((c) => convoMap.has(c.chara_id))); const selCharas = $derived(characters.filter((c) => convoMap.has(c.chara_id)));
const names = $derived(charaNames(characters ?? [])); const names = $derived(charaNames(characters));
const minSuggest = 8; const minSuggest = 8;
onMount(async () => { onMount(async () => {
@@ -21,9 +30,8 @@
const options = $derived(convoMap.get(chara?.chara_id ?? 0) ?? []); const options = $derived(convoMap.get(chara?.chara_id ?? 0) ?? []);
const cur = $derived(options.find((c) => c.number === convo)); const cur = $derived(options.find((c) => c.number === convo));
const cur1Name = $derived(cur?.chara_1 && names.get(cur.chara_1)?.en); const charaIDs = $derived(cur != null ? convoCharas(cur) : []);
const cur2Name = $derived(cur?.chara_2 && names.get(cur.chara_2)?.en); const charas = $derived(charaIDs.map((id) => names.get(id)!));
const cur3Name = $derived(cur?.chara_3 && names.get(cur.chara_3)?.en);
const suggested = $derived.by(() => { const suggested = $derived.by(() => {
if (cur == null) { if (cur == null) {
return []; return [];
@@ -55,24 +63,22 @@
</div> </div>
{#if cur} {#if cur}
<div class="shadow-sm transition-shadow hover:shadow-md"> <div class="shadow-sm transition-shadow hover:shadow-md">
<div class="mt-8 flex text-center text-lg"> <div class="mt-8 flex flex-col text-center text-lg md:flex-row">
<span class={{ 'flex-1': true, 'font-bold italic': req.includes(cur.chara_1) }}>{cur1Name}</span> {#each charaIDs as id, i (id)}
{#if cur2Name} <span class={{ 'flex-1': true, 'font-bold italic': req.includes(id) }}>
<span class={{ 'flex-1': true, 'font-bold italic': cur.chara_2 != null && req.includes(cur.chara_2) }}>{cur2Name}</span> <CharaIcon chara_id={id} size={64} />
{/if} {charas[i].en}
{#if cur3Name} </span>
<span class={{ 'flex-1': true, 'font-bold italic': cur.chara_3 != null && req.includes(cur.chara_3) }}>{cur3Name}</span> {/each}
{/if}
</div> </div>
<div class="flex w-full text-center text-lg"> <div class="block w-full text-center text-lg">
<span class="flex-1">at {curLoc?.name.en}</span> at the {curLoc?.name.en}
</div> </div>
{#if req.length > 0} {#if req.length > 0}
<div class="mt-2 flex w-full text-center text-sm italic"> <span class="mx-auto mt-4 block text-center text-sm">
<span class="flex-1"> The conversation will not appear unless you own a trainee or support card of all characters with names in
The conversation will not appear unless you own a trainee or support card of all characters with names in italics. <span class="font-bold italic">bold italics</span>.
</span> </span>
</div>
{/if} {/if}
</div> </div>
<div class="mt-4 block text-center"> <div class="mt-4 block text-center">
@@ -85,7 +91,8 @@
</div> </div>
<div class="mt-4 block text-center"> <div class="mt-4 block text-center">
<span> <span>
Set these characters to fixed positions (main, upgrades, story, races) to maximize the chance of getting this conversation. Setting these characters to fixed positions (main, upgrades, story, races) may maximize the chance of getting this
conversation.
</span> </span>
</div> </div>
{/if} {/if}