genNextBattle

main
Yanick Champoux 2023-01-12 18:02:29 -05:00
parent 41c6cae377
commit e96a022c8f
8 changed files with 115 additions and 19 deletions

View File

@ -34,6 +34,7 @@
"beercss": "^3.0.4",
"dexie": "^3.2.2",
"fake-indexeddb": "^4.0.1",
"material-dynamic-colors": "^0.1.5"
"material-dynamic-colors": "^0.1.5",
"remeda": "^1.3.0"
}
}

View File

@ -13,7 +13,13 @@
{campaign.name}
</a>
</h6>
<p>chapter 2, second battle.</p>
<p>
{#if campaign.battles}
chapter {currentChapter(campaign)}, battle of {currentCity(
campaign,
)}.
{/if}
</p>
</div>
<button on:click={deleteCampaign(campaign)} class="none"
>Delete</button
@ -42,6 +48,7 @@
</div>
<script>
import * as R from 'remeda';
import { getContext } from 'svelte';
import { goto } from '$app/navigation';
@ -51,6 +58,10 @@
let showNewCampaign = false;
let newCampaignName = '';
const currentChapter = ({ battles }) =>
R.clamp(1 + parseInt(battles?.length / 2), { max: 4 });
const currentCity = ({ battles }) => R.last(battles).city;
async function deleteCampaign({ name, id }) {
if (!window.confirm(`delete campaign ${name}?`)) return;
api.event.deleteCampaign(id);

View File

@ -1,5 +1,7 @@
import * as R from 'remeda';
import Dexie, { liveQuery } from 'dexie';
import { writable, derived } from 'svelte/store';
import { genNextBattle } from './genNextBattle.js';
const seedCampaign = {
battles: [],
@ -12,21 +14,18 @@ export function genApi(options = {}) {
campaigns: '++id,name',
});
const campaigns = liveQuery(async () => {
const c = [];
await storage.campaigns
.toCollection()
.each(({ id, name }) => c.push({ id, name }));
return c;
});
const campaigns = writable([]);
storage.campaigns.toArray().then((c) => campaigns.set(c));
const activeCampaignId = writable();
const activeCampaign = derived(activeCampaignId, async (id, set) => {
const x = await storage.campaigns.get({ id });
console.log({ x });
set(x);
});
const activeCampaign = derived(
[activeCampaignId, campaigns],
async ([id, campaigns], set) => {
const x = campaigns.find((c) => c.id === id);
set(x);
},
);
return {
campaigns,
@ -34,7 +33,11 @@ export function genApi(options = {}) {
storage,
event: {
addCampaign: (name) =>
storage.campaigns.add({ name, ...seedCampaign }),
storage.campaigns.add({
name,
...seedCampaign,
battles: [genNextBattle()],
}),
deleteCampaign: (id) => storage.campaigns.delete(id),
setActiveCampaign: async (id) => {
activeCampaignId.set(id);

40
src/lib/store/chapters.js Normal file
View File

@ -0,0 +1,40 @@
export default [
{
cities: ['Havana', 'Montreal', 'Mexico City', 'Rio de Janeiro'],
characters: [
'Clinton Harper',
'Jackson Moss',
'Lucia Ortego',
'Samantha Legrand',
],
scenarios: [
'Evacuation',
'Reinforcements',
'Battle for the sky',
'Satellites',
],
},
{
cities: ['Johannesburg', 'Moscow', 'Cairo', 'London', 'Paris'],
characters: [
'Jaroslav Ruzicka',
'Karima Almasi',
'Shanti Aumann',
'Pieter Bernstein',
],
scenarios: [
'Command ship',
'Reactor leak',
'Dangerous research',
'Repairing the base',
],
},
{
cities: ['Seoul', 'Beijing', 'Tokyo', 'Sydney', 'Singapore'],
characters: ['Wang Lin', "Iz'ox", 'Jang Chanwook', 'Archie Bell'],
scenarios: ['Storm', 'Contamination', 'Kamikaze', 'Saboteur'],
},
{
scenarios: ['The final battle'],
},
];

View File

@ -0,0 +1,28 @@
import * as R from 'remeda';
import chapters from './chapters.js';
const pickOne = (choices) => choices[parseInt(Math.random() * choices.length)];
export function genNextBattle(battles = []) {
let chapter = R.clamp(1 + parseInt(battles.length / 2), { min: 1, max: 4 });
if (chapter === 1) {
const scenario = pickOne(
chapters[chapter - 1].scenarios.filter(
(s) => !battles.map(R.prop('scenario')).includes(s),
),
);
const character = pickOne(
chapters[chapter - 1].characters.filter(
(s) => !battles.map(R.prop('character')).includes(s),
),
);
const city = pickOne(
chapters[chapter - 1].cities.filter(
(s) => !battles.map(R.prop('city')).includes(s),
),
);
return { scenario, character, city, status: 'upcoming' };
}
}

View File

@ -0,0 +1,9 @@
import { test, expect } from 'vitest';
import { genNextBattle } from './genNextBattle.js';
test('generate for the first chapter', () => {
const next = genNextBattle();
expect(next).toHaveProperty('city');
expect(next).toHaveProperty('status', 'upcoming');
});

1
src/routes/+layout.js Normal file
View File

@ -0,0 +1 @@
export const ssr = false;

View File

@ -1,12 +1,15 @@
<article>
<h5>{$activeCampaign.name}</h5>
<h6>Chapter 1</h6>
{#if $activeCampaign}
<h5>{$activeCampaign.name}</h5>
<h6>Chapter 1</h6>
<ul>
<li>Battle of New York, ongoing</li>
</ul>
{/if}
</article>
<script>
import { getContext } from 'svelte';
const { activeCampaign } = getContext('api');
$: console.log({ activeCampaign: $activeCampaign });
</script>