Merge branch 'sky9-pick-first-battle'
This commit is contained in:
commit
aac908afce
@ -34,6 +34,7 @@
|
|||||||
"beercss": "^3.0.4",
|
"beercss": "^3.0.4",
|
||||||
"dexie": "^3.2.2",
|
"dexie": "^3.2.2",
|
||||||
"fake-indexeddb": "^4.0.1",
|
"fake-indexeddb": "^4.0.1",
|
||||||
"material-dynamic-colors": "^0.1.5"
|
"material-dynamic-colors": "^0.1.5",
|
||||||
|
"remeda": "^1.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,13 @@
|
|||||||
{campaign.name}
|
{campaign.name}
|
||||||
</a>
|
</a>
|
||||||
</h6>
|
</h6>
|
||||||
<p>chapter 2, second battle.</p>
|
<p>
|
||||||
|
{#if campaign.battles}
|
||||||
|
chapter {currentChapter(campaign)}, battle of {currentCity(
|
||||||
|
campaign,
|
||||||
|
)}.
|
||||||
|
{/if}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button on:click={deleteCampaign(campaign)} class="none"
|
<button on:click={deleteCampaign(campaign)} class="none"
|
||||||
>Delete</button
|
>Delete</button
|
||||||
@ -42,6 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import * as R from 'remeda';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
@ -51,6 +58,10 @@
|
|||||||
let showNewCampaign = false;
|
let showNewCampaign = false;
|
||||||
let newCampaignName = '';
|
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 }) {
|
async function deleteCampaign({ name, id }) {
|
||||||
if (!window.confirm(`delete campaign ${name}?`)) return;
|
if (!window.confirm(`delete campaign ${name}?`)) return;
|
||||||
api.event.deleteCampaign(id);
|
api.event.deleteCampaign(id);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import * as R from 'remeda';
|
||||||
import Dexie, { liveQuery } from 'dexie';
|
import Dexie, { liveQuery } from 'dexie';
|
||||||
import { writable, derived } from 'svelte/store';
|
import { writable, derived } from 'svelte/store';
|
||||||
|
import { genNextBattle } from './genNextBattle.js';
|
||||||
|
|
||||||
const seedCampaign = {
|
const seedCampaign = {
|
||||||
battles: [],
|
battles: [],
|
||||||
@ -12,21 +14,18 @@ export function genApi(options = {}) {
|
|||||||
campaigns: '++id,name',
|
campaigns: '++id,name',
|
||||||
});
|
});
|
||||||
|
|
||||||
const campaigns = liveQuery(async () => {
|
const campaigns = writable([]);
|
||||||
const c = [];
|
storage.campaigns.toArray().then((c) => campaigns.set(c));
|
||||||
await storage.campaigns
|
|
||||||
.toCollection()
|
|
||||||
.each(({ id, name }) => c.push({ id, name }));
|
|
||||||
return c;
|
|
||||||
});
|
|
||||||
|
|
||||||
const activeCampaignId = writable();
|
const activeCampaignId = writable();
|
||||||
|
|
||||||
const activeCampaign = derived(activeCampaignId, async (id, set) => {
|
const activeCampaign = derived(
|
||||||
const x = await storage.campaigns.get({ id });
|
[activeCampaignId, campaigns],
|
||||||
console.log({ x });
|
async ([id, campaigns], set) => {
|
||||||
|
const x = campaigns.find((c) => c.id === id);
|
||||||
set(x);
|
set(x);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
campaigns,
|
campaigns,
|
||||||
@ -34,7 +33,11 @@ export function genApi(options = {}) {
|
|||||||
storage,
|
storage,
|
||||||
event: {
|
event: {
|
||||||
addCampaign: (name) =>
|
addCampaign: (name) =>
|
||||||
storage.campaigns.add({ name, ...seedCampaign }),
|
storage.campaigns.add({
|
||||||
|
name,
|
||||||
|
...seedCampaign,
|
||||||
|
battles: [genNextBattle()],
|
||||||
|
}),
|
||||||
deleteCampaign: (id) => storage.campaigns.delete(id),
|
deleteCampaign: (id) => storage.campaigns.delete(id),
|
||||||
setActiveCampaign: async (id) => {
|
setActiveCampaign: async (id) => {
|
||||||
activeCampaignId.set(id);
|
activeCampaignId.set(id);
|
||||||
|
40
src/lib/store/chapters.js
Normal file
40
src/lib/store/chapters.js
Normal 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'],
|
||||||
|
},
|
||||||
|
];
|
28
src/lib/store/genNextBattle.js
Normal file
28
src/lib/store/genNextBattle.js
Normal 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' };
|
||||||
|
}
|
||||||
|
}
|
9
src/lib/store/genNextBattle.test.js
Normal file
9
src/lib/store/genNextBattle.test.js
Normal 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
1
src/routes/+layout.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const ssr = false;
|
@ -1,12 +1,15 @@
|
|||||||
<article>
|
<article>
|
||||||
|
{#if $activeCampaign}
|
||||||
<h5>{$activeCampaign.name}</h5>
|
<h5>{$activeCampaign.name}</h5>
|
||||||
<h6>Chapter 1</h6>
|
<h6>Chapter 1</h6>
|
||||||
|
<ul>
|
||||||
|
<li>Battle of New York, ongoing</li>
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
|
|
||||||
const { activeCampaign } = getContext('api');
|
const { activeCampaign } = getContext('api');
|
||||||
|
|
||||||
$: console.log({ activeCampaign: $activeCampaign });
|
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user