wip
This commit is contained in:
parent
0098e899c9
commit
3fb959d9f3
@ -1,4 +1,4 @@
|
||||
<div>
|
||||
<div class="field">
|
||||
{#if label}
|
||||
<label>{label}</label>
|
||||
{/if}
|
||||
|
17
src/lib/components/ShipEdit/Weaponry.story.svelte
Normal file
17
src/lib/components/ShipEdit/Weaponry.story.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<Hst.Story>
|
||||
<Weaponry {weapons} />
|
||||
</Hst.Story>
|
||||
|
||||
<script>
|
||||
export let Hst;
|
||||
import Weaponry from "./Weaponry.svelte";
|
||||
import u from "@yanick/updeep-remeda";
|
||||
import { weaponTypes } from "$lib/store/ship/weaponry/rules";
|
||||
import Changelog from "../Changelog.svelte";
|
||||
|
||||
const weapons = [
|
||||
weaponTypes.find(u.matches({ type: "beam" })).initial,
|
||||
weaponTypes.find(u.matches({ type: "submunition" })).initial,
|
||||
].map((specs, id) => ({ specs, id }));
|
||||
console.log(weapons);
|
||||
</script>
|
@ -2,14 +2,12 @@
|
||||
<Firecons {...firecons} />
|
||||
|
||||
<ADFC {...adfc} />
|
||||
<!--
|
||||
|
||||
<AddWeapon />
|
||||
|
||||
{#each weapons as weapon (weapon.id)}
|
||||
<Weapon {weapon} id={weapon.id} />
|
||||
<Weapon {...weapon} />
|
||||
{/each}
|
||||
-->
|
||||
</Section>
|
||||
|
||||
<script>
|
||||
@ -22,17 +20,14 @@
|
||||
|
||||
import Firecons from "./Weaponry/Firecons.svelte";
|
||||
import ADFC from "./Weaponry/ADFC.svelte";
|
||||
import AddWeapon from "./Weaponry/AddWeapon.svelte";
|
||||
|
||||
export let firecons = {};
|
||||
export let adfc = {};
|
||||
/*
|
||||
|
||||
import AddWeapon from './AddWeapon.svelte';
|
||||
import Weapon from './Weapon/index.svelte';
|
||||
|
||||
import Weapon from "./Weaponry/Weapon/index.svelte";
|
||||
|
||||
export let weapons = [];
|
||||
*/
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -1,24 +1,25 @@
|
||||
<Field label="weapon type">
|
||||
<div>
|
||||
<Field label="">
|
||||
<select bind:value={type}>
|
||||
{#each weaponTypes as weapon (weapon.type)}
|
||||
<option value={weapon.type}>{weapon.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
<button class="button small primary" on:click={addWeapon}>add weapon</button>
|
||||
</Field>
|
||||
<button class="button small primary" on:click={addWeapon}>add weapon</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { getContext } from "svelte";
|
||||
import Field from "../../Field.svelte";
|
||||
|
||||
import { weaponTypes } from "$lib/shipDux/weaponry/weapons";
|
||||
import { weaponTypes } from "$lib/store/ship/weaponry/rules";
|
||||
|
||||
export let ship = getContext("ship");
|
||||
export let api = getContext("api");
|
||||
|
||||
let type = weaponTypes[0].value;
|
||||
let type = weaponTypes[0].type;
|
||||
|
||||
const addWeapon = () => ship.dispatch.addWeapon(type);
|
||||
const addWeapon = () => api?.dispatch?.addWeapon?.(type);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@ -26,4 +27,17 @@
|
||||
width: inherit;
|
||||
display: inline-block;
|
||||
}
|
||||
button {
|
||||
width: inherit;
|
||||
display: inline-block;
|
||||
}
|
||||
div :global(.field) {
|
||||
display: flex;
|
||||
margin-right: 2em;
|
||||
}
|
||||
div {
|
||||
display: flex;
|
||||
margin-left: 5em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,8 @@
|
||||
<Hst.Story>
|
||||
<Arcs />
|
||||
</Hst.Story>
|
||||
|
||||
<script>
|
||||
export let Hst;
|
||||
import Arcs from "./Arcs.svelte";
|
||||
</script>
|
@ -1,10 +1,10 @@
|
||||
<svg width="{size}px" height="{size}px">
|
||||
{#each all_arcs as arc (arc)}
|
||||
{#each arcs as arc (arc)}
|
||||
<Arc
|
||||
{arc}
|
||||
radius={size / 2}
|
||||
active={selected.includes(arc)}
|
||||
on:click={() => click_arc(arc)}
|
||||
on:click={() => clickArc(arc)}
|
||||
/>
|
||||
{/each}
|
||||
<circle cx="50%" cy="50%" r={size / 3} />
|
||||
@ -12,17 +12,17 @@
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
import Arc from "./Arc.svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
const all_arcs = ["FS", "F", "FP", "AP", "A", "AS"];
|
||||
import { arcs } from "$lib/store/ship/weaponry/rules";
|
||||
import Arc from "./Arc.svelte";
|
||||
|
||||
export let selected = [];
|
||||
export let size = 60;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const click_arc = (arc) => dispatch("click_arc", arc);
|
||||
const clickArc = (arc) => dispatch("clickArc", arc);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 634 B |
@ -17,16 +17,18 @@
|
||||
</select>
|
||||
</Field>
|
||||
|
||||
<Arcs selected={arcs} on:click_arc={({ detail }) => setArcs(detail)} />
|
||||
<Arcs selected={arcs} on:clickArc={({ detail }) => setArcs(detail)} />
|
||||
|
||||
<script>
|
||||
import { getContext } from "svelte";
|
||||
import * as R from "remeda";
|
||||
|
||||
import Arcs from "../Arcs.svelte";
|
||||
import ShipItem from "$lib/components/ShipItem.svelte";
|
||||
import Field from "$lib/components/Field.svelte";
|
||||
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import memoize from "memoize-one";
|
||||
|
||||
const all_arcs = ["FS", "F", "FP", "AP", "A", "AS"];
|
||||
|
||||
@ -40,41 +42,52 @@
|
||||
4: [1, 2, 3, 4, 5, 6, "broadside"],
|
||||
};
|
||||
|
||||
$: arcsCaches = arcs.join(',');
|
||||
|
||||
let nbrArcs = arcs.length;
|
||||
|
||||
$: if (!arc_options[weaponClass].includes(nbrArcs)) {
|
||||
nbrArcs = arc_options[weaponClass][0];
|
||||
console.log({nbrArcs, label:"in if"})
|
||||
console.log({ nbrArcs, label: "in if" });
|
||||
}
|
||||
|
||||
const broadside = ["FS", "FP", "AP", "AS"];
|
||||
|
||||
|
||||
function setArcs(firstArc) {
|
||||
console.log(firstArc);
|
||||
let newArcs;
|
||||
if (nbrArcs === "broadside") {
|
||||
arcs = broadside;
|
||||
return;
|
||||
}
|
||||
newArcs = broadside;
|
||||
} else {
|
||||
let first_index = all_arcs.findIndex((arc) => arc === firstArc);
|
||||
if (first_index === -1) first_index = 0;
|
||||
|
||||
arcs = Array.from({length: nbrArcs}).map(
|
||||
newArcs = Array.from({ length: nbrArcs }).map(
|
||||
(_dummy, i) => all_arcs[(first_index + i) % all_arcs.length]
|
||||
);
|
||||
arcsCaches = arcs.join(',');
|
||||
}
|
||||
|
||||
$: console.log({ newArcs, arcs });
|
||||
if (
|
||||
arcs.length !== newArcs.length ||
|
||||
arcs.length !== R.intersection(arcs, newArcs).length
|
||||
) {
|
||||
arcs = newArcs;
|
||||
}
|
||||
}
|
||||
|
||||
$: if (arcs.length !== nbrArcs) setArcs(arcs[0]);
|
||||
|
||||
$: console.log("it changed!", arcs)
|
||||
$: console.log("it changed!", arcsCaches)
|
||||
$: console.log("it changed!", arcs);
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
$: dispatch("change", {
|
||||
let i = 5;
|
||||
|
||||
const memoChange = memoize((weaponClass, ...arcs) =>
|
||||
dispatch("change", {
|
||||
weaponClass,
|
||||
arcs: arcsCaches.split(','),
|
||||
});
|
||||
arcs,
|
||||
})
|
||||
);
|
||||
|
||||
$: memoChange(weaponClass, ...arcs);
|
||||
</script>
|
||||
|
@ -1,27 +1,14 @@
|
||||
<label>needle weapon</label>
|
||||
|
||||
<Arcs selected={[arc]} on:click_arc={({ detail }) => click_arc(detail)} />
|
||||
<Arcs selected={[arc]} on:clickArc={({ detail }) => clickArc(detail)} />
|
||||
|
||||
<script>
|
||||
import { getContext } from "svelte";
|
||||
<script lang="ts">
|
||||
import Arcs from "./Arcs.svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
const all_arcs = ["FS", "F", "FP", "AP", "A", "AS"];
|
||||
|
||||
export let arc = "F";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const click_arc = (arc) => {
|
||||
dispatch("change",{arc});
|
||||
};
|
||||
const clickArc = (arc) => dispatch("change", { arc });
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.arc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-right: 1em;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,19 +1,16 @@
|
||||
<label>submunition pack</label>
|
||||
|
||||
<Arcs selected={[arc]} on:click_arc={({ detail }) => click_arc(detail)} />
|
||||
<Arcs selected={[arc]} on:clickArc={({ detail }) => clickArc(detail)} />
|
||||
|
||||
<script>
|
||||
import { getContext } from "svelte";
|
||||
import Arcs from "./Arcs.svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
const all_arcs = ["FS", "F", "FP", "AP", "A", "AS"];
|
||||
|
||||
export let arc = "F";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const click_arc = (arc) => {
|
||||
const clickArc = (arc) => {
|
||||
dispatch("change", { arc });
|
||||
};
|
||||
</script>
|
||||
|
@ -1,15 +1,8 @@
|
||||
<ShipItem {...reqs}>
|
||||
<div class="weapon_row">
|
||||
<button
|
||||
class="button small red remove"
|
||||
on:click={remove}>remove
|
||||
</button>
|
||||
<button class="button small red remove" on:click={remove}>remove </button>
|
||||
|
||||
<svelte:component
|
||||
this={component[type]}
|
||||
{...weapon}
|
||||
on:change={update}
|
||||
/>
|
||||
<svelte:component this={component[type]} {...specs} on:change={update} />
|
||||
</div>
|
||||
</ShipItem>
|
||||
|
||||
@ -33,20 +26,19 @@
|
||||
needle: Needle,
|
||||
};
|
||||
|
||||
export let weapon = {};
|
||||
$: reqs = weapon.reqs;
|
||||
export let reqs = {};
|
||||
export let specs = {};
|
||||
export let id;
|
||||
|
||||
const ship = getContext("ship");
|
||||
const api = getContext("api");
|
||||
|
||||
$: type = weapon.type;
|
||||
$: type = specs.type;
|
||||
|
||||
const remove = () => ship.dispatch.removeWeapon(id);
|
||||
const remove = () => api?.dispatch?.removeWeapon?.(id);
|
||||
|
||||
const update = ({ detail }) => {
|
||||
console.log({id,type})
|
||||
ship.dispatch.setWeapon({
|
||||
id,
|
||||
console.log({ id, type });
|
||||
api?.dispatch?.setWeapon?.(id, {
|
||||
type,
|
||||
...detail,
|
||||
});
|
||||
@ -54,6 +46,9 @@
|
||||
</script>
|
||||
|
||||
<style>
|
||||
button {
|
||||
width: inherit;
|
||||
}
|
||||
.weapon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -47,4 +47,11 @@ test("kicking the tires", () => {
|
||||
mass: 6,
|
||||
},
|
||||
});
|
||||
|
||||
store.dispatch.addWeapon("beam");
|
||||
expect(store.getState().weaponry.weapons[0]).toEqual({
|
||||
id: 1,
|
||||
reqs: { cost: 3, mass: 1 },
|
||||
specs: { arcs: ["F"], type: "beam", weaponClass: 1 },
|
||||
});
|
||||
});
|
||||
|
@ -66,7 +66,12 @@ shipDux.addReaction((api) => {
|
||||
);
|
||||
});
|
||||
|
||||
shipDux.addReaction((api) => (state) => {
|
||||
shipDux.addReaction((api) => {
|
||||
const setShipReqs = memoize((cost, usedMass) =>
|
||||
api.dispatch.setShipReqs({ cost, usedMass })
|
||||
);
|
||||
|
||||
return (state) => {
|
||||
let cost = 0;
|
||||
let mass = 0;
|
||||
|
||||
@ -77,17 +82,24 @@ shipDux.addReaction((api) => (state) => {
|
||||
if (typeof subsystem !== "object") continue;
|
||||
|
||||
if (subsystem.reqs) {
|
||||
cost += subsystem.reqs.cost;
|
||||
mass += subsystem.reqs.mass;
|
||||
cost += subsystem.reqs.cost ?? 0;
|
||||
mass += subsystem.reqs.mass ?? 0;
|
||||
}
|
||||
|
||||
subsystems.push(...Object.values(subsystem));
|
||||
}
|
||||
|
||||
api.dispatch.setShipReqs({ cost, usedMass: mass });
|
||||
if (Number.isNaN(cost)) {
|
||||
console.log(state.weaponry.weapons);
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
setShipReqs(cost, mass);
|
||||
};
|
||||
});
|
||||
|
||||
shipDux.addEffect((api) => (next) => (action) => {
|
||||
console.log(action);
|
||||
next(action);
|
||||
});
|
||||
|
||||
|
@ -1,58 +1,94 @@
|
||||
import type { Reqs } from "$lib/shipDux/reqs";
|
||||
|
||||
export const arcs = ["FS", "F", "FP", "AP", "A", "AS"] as const;
|
||||
|
||||
export type Arc = (typeof arcs)[number];
|
||||
|
||||
export type WeaponType = "beam";
|
||||
|
||||
type Beam = {
|
||||
type: "beam";
|
||||
weaponClass: 1 | 2 | 3 | 4;
|
||||
arcs: Arc[];
|
||||
};
|
||||
|
||||
type Submunition = {
|
||||
type: "submunition";
|
||||
arc: Arc;
|
||||
};
|
||||
|
||||
type PDS = {
|
||||
type: "pds";
|
||||
};
|
||||
|
||||
type Scattergun = { type: "scattergun" };
|
||||
|
||||
type Needle = { type: "needle"; arc: Arc };
|
||||
|
||||
export type Weapon = Beam | Submunition | PDS | Scattergun | Needle;
|
||||
|
||||
export const weaponTypes = [
|
||||
{
|
||||
name: "beam",
|
||||
type: "beam",
|
||||
name: "beam",
|
||||
reqs: beamReqs,
|
||||
initial: {
|
||||
type: "beam",
|
||||
weaponClass: 1,
|
||||
},
|
||||
arcs,
|
||||
} as any as Beam,
|
||||
},
|
||||
{
|
||||
name: "submunition pack",
|
||||
type: "submunition",
|
||||
name: "submunition pack",
|
||||
reqs: { mass: 1, cost: 3 },
|
||||
initial: { arc: "F" },
|
||||
initial: { type: "submunition", arc: "F" } as Submunition,
|
||||
},
|
||||
{
|
||||
name: "point defence system",
|
||||
type: "pds",
|
||||
reqs: { mass: 1, cost: 3 },
|
||||
initial: {},
|
||||
initial: {
|
||||
type: "pds",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "scattergun",
|
||||
type: "scattergun",
|
||||
reqs: { mass: 1, cost: 4 },
|
||||
initial: {},
|
||||
initial: { type: "scattergun" },
|
||||
},
|
||||
{
|
||||
name: "needle weapon",
|
||||
type: "needle",
|
||||
reqs: { mass: 2, cost: 6 },
|
||||
initial: { arc: "F" },
|
||||
initial: { arc: "F", type: "needle" },
|
||||
},
|
||||
];
|
||||
|
||||
export function weaponReqs(weapon): Reqs {
|
||||
const { reqs } = weaponTypes.find((wt) => wt.type === weapon.type) || {};
|
||||
|
||||
if (!reqs) return {};
|
||||
if (!reqs)
|
||||
return {
|
||||
cost: 0,
|
||||
mass: 0,
|
||||
};
|
||||
|
||||
if (typeof reqs === "function") return reqs(weapon);
|
||||
|
||||
return reqs;
|
||||
}
|
||||
|
||||
const isBroadside = (arcs) => {
|
||||
const isBroadside = (arcs: Arc[]) => {
|
||||
if (arcs.length !== 4) return false;
|
||||
|
||||
// that'd be A or F
|
||||
return !arcs.some((a) => a.length === 1);
|
||||
};
|
||||
|
||||
function beamReqs({ weaponClass, arcs }) {
|
||||
function beamReqs({ weaponClass, arcs }: Beam) {
|
||||
console.log(weaponClass, arcs);
|
||||
let mass;
|
||||
|
||||
if (weaponClass === 1) {
|
||||
|
39
src/lib/store/ship/weaponry/weapons.test.ts
Normal file
39
src/lib/store/ship/weaponry/weapons.test.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { weaponsDux } from "./weapons";
|
||||
import Debug from "debug";
|
||||
const debug = Debug("aotds:weapons");
|
||||
import u from "@yanick/updeep-remeda";
|
||||
process.env.UPDEEP_MODE = "dangerously_never_freeze";
|
||||
|
||||
test("setWeapon", () => {
|
||||
const store = weaponsDux.createStore();
|
||||
|
||||
store.dispatch.addWeapon("beam");
|
||||
store.dispatch.addWeapon("submunition");
|
||||
|
||||
expect(store.getState()).toMatchObject([
|
||||
{
|
||||
specs: {
|
||||
type: "beam",
|
||||
},
|
||||
},
|
||||
{
|
||||
specs: {
|
||||
type: "submunition",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
store.dispatch.setWeapon(1, {
|
||||
type: "beam",
|
||||
weaponClass: 2,
|
||||
arcs: ["F", "FP", "FS"],
|
||||
});
|
||||
debug(store.getState());
|
||||
expect(store.getState().find(u.matches({ id: 1 }))).toMatchObject({
|
||||
specs: {
|
||||
type: "beam",
|
||||
weaponClass: 2,
|
||||
arcs: ["FS", "F", "FP"],
|
||||
},
|
||||
});
|
||||
});
|
@ -2,23 +2,16 @@ import type { Reqs } from "$lib/shipDux/reqs";
|
||||
import Updux from "updux";
|
||||
import u from "@yanick/updeep-remeda";
|
||||
import * as R from "remeda";
|
||||
import { weaponReqs } from "./rules";
|
||||
import { nanoid } from "@reduxjs/toolkit";
|
||||
import { weaponReqs, weaponTypes, type WeaponType, type Weapon } from "./rules";
|
||||
|
||||
type Weapon = {
|
||||
weaponClass: string;
|
||||
arcs?: unknown[];
|
||||
type: string;
|
||||
};
|
||||
|
||||
type IndexedWeapon = { id: string; reqs: Reqs; specs: Weapon };
|
||||
type IndexedWeapon = { id: number; reqs: Reqs; specs: Weapon };
|
||||
|
||||
export const weaponsDux = new Updux({
|
||||
initialState: [] as IndexedWeapon[],
|
||||
actions: {
|
||||
removeWeapon: (id: string) => id,
|
||||
setWeapon: (id: string, specs: Weapon) => ({ id, specs }),
|
||||
addWeapon: (specs: Weapon) => specs,
|
||||
addWeapon: (type: WeaponType) => type,
|
||||
},
|
||||
});
|
||||
|
||||
@ -26,20 +19,35 @@ weaponsDux.addMutation(weaponsDux.actions.removeWeapon, (id) =>
|
||||
R.reject(u.matches({ id }))
|
||||
);
|
||||
|
||||
weaponsDux.addMutation(
|
||||
weaponsDux.actions.setWeapon,
|
||||
({ id, specs }) =>
|
||||
(state) => {
|
||||
const weapon = state.find(u.matches({ id }));
|
||||
if (!weapon) return;
|
||||
weapon.specs = specs;
|
||||
weapon.reqs = weaponReqs(specs);
|
||||
}
|
||||
// TODO not needed anymore
|
||||
const mergeArcs = (newArcs) => (original) => {
|
||||
if (original === undefined) return undefined;
|
||||
|
||||
let merged = u.filter(original, (a) => newArcs.includes(a));
|
||||
|
||||
let toAdd = newArcs.filter((a) => !merged.includes(a));
|
||||
if (toAdd.length) return [...merged, ...toAdd];
|
||||
|
||||
return merged;
|
||||
};
|
||||
|
||||
weaponsDux.addMutation(weaponsDux.actions.setWeapon, ({ id, specs }) =>
|
||||
u.map(
|
||||
u.if(u.matches({ id }), {
|
||||
specs: {
|
||||
...specs,
|
||||
arcs: mergeArcs((specs as any).arcs),
|
||||
},
|
||||
reqs: weaponReqs(specs),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
weaponsDux.addMutation(weaponsDux.actions.addWeapon, (specs) => (state) => {
|
||||
weaponsDux.addMutation(weaponsDux.actions.addWeapon, (type) => (state) => {
|
||||
const specs = weaponTypes.find(u.matches({ type }))?.initial ?? {};
|
||||
const id = 1 + Math.max(0, ...state.map(R.prop("id")));
|
||||
state.push({
|
||||
id: nanoid(),
|
||||
id,
|
||||
specs,
|
||||
reqs: weaponReqs(specs),
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user