streamlining, store and edit

This commit is contained in:
Yanick Champoux 2023-03-24 11:01:04 -04:00
parent 19293501cb
commit 074249d566
12 changed files with 154 additions and 70 deletions

View File

@ -1,5 +1,5 @@
<Hst.Story> <Hst.Story>
<ShipEdit {ship} /> <ShipEdit {...ship} />
</Hst.Story> </Hst.Story>
<script> <script>
@ -14,8 +14,5 @@
let ship = api.getState(); let ship = api.getState();
api.subscribe(() => { api.subscribe(() => (ship = api.getState()));
console.log("update!");
ship = api.getState();
});
</script> </script>

View File

@ -1,14 +1,18 @@
<main> <main>
<Identification {...ship.identification} /> <Identification {...identification} />
<Propulsion {...ship.propulsion} /> <Propulsion {...propulsion} />
<Structure {...structure} />
</main> </main>
<script> <script>
import Identification from "./ShipEdit/Identification.svelte"; import Identification from "./ShipEdit/Identification.svelte";
import Propulsion from "./ShipEdit/Propulsion.svelte"; import Propulsion from "./ShipEdit/Propulsion.svelte";
import shipDux from "$lib/store/ship"; import shipDux from "$lib/store/ship";
import Structure from "./ShipEdit/Structure.svelte";
export let ship = shipDux.initial; export let identification = {};
export let propulsion = {};
export let structure = {};
</script> </script>
<style> <style>

View File

@ -0,0 +1,10 @@
<Section label="structure">
<Streamlining {...streamlining} />
</Section>
<script lang="ts">
import Section from "$lib/components/Section.svelte";
import Streamlining from "./Structure/Streamlining.svelte";
export let streamlining = {};
</script>

View File

@ -18,17 +18,17 @@
</ShipItem> </ShipItem>
<script> <script>
import ShipItem from "$lib/components/ShipItem/index.svelte"; import ShipItem from "$lib/components/ShipItem.svelte";
import Field from "$lib/components/Field/index.svelte"; import Field from "$lib/components/Field.svelte";
import { getContext } from "svelte"; import { getContext } from "svelte";
export let type = "none"; export let type = "none";
export let reqs = {}; export let reqs = {};
export let {dispatch, shipMass} = getContext("ship"); export let api = getContext("api");
$: dispatch.setStreamlining({type, shipMass: $shipMass}); $: api?.dispatch?.setStreamlining?.(type);
</script> </script>
<style> <style>

View File

@ -1,23 +1,32 @@
import { test, expect } from "vitest"; import { test, expect } from "vitest";
import ship from "./ship"; import ship from "./ship";
test("misc", () => { test("kicking the tires", () => {
const store = ship.createStore(); const store = ship.createStore();
store.dispatch.setFtlType("standard"); console.log(store.getState());
console.log(store.getState.getStreamlining());
store.dispatch.setFtlType("standard");
expect(store.getState().propulsion.ftl.reqs.mass).toEqual(1); expect(store.getState().propulsion.ftl.reqs.mass).toEqual(1);
expect(store.getState().identification.reqs.usedMass).toEqual(1); expect(store.getState().identification.reqs.usedMass).toEqual(1);
store.dispatch.setDrive({ rating: 3, advanced: true }); store.dispatch.setDrive({ rating: 3, advanced: true });
expect(store.getState().propulsion.drive.reqs).toEqual({ mass: 2, cost: 6 }); expect(store.getState().propulsion.drive.reqs).toEqual({ mass: 2, cost: 6 });
store.dispatch.setNbrCarrierBays(1); store.dispatch.setNbrCarrierBays(1);
expect(store.getState().carrier.nbrBays).toEqual(1); expect(store.getState().carrier.nbrBays).toEqual(1);
store.dispatch.setNbrCarrierBays(2); store.dispatch.setNbrCarrierBays(2);
expect(store.getState().carrier.nbrBays).toEqual(2); expect(store.getState().carrier.nbrBays).toEqual(2);
store.dispatch.setSquadronType(2, "fast"); store.dispatch.setSquadronType(2, "fast");
expect(store.getState().carrier.squadrons[1]).toHaveProperty("type", "fast"); expect(store.getState().carrier.squadrons[1]).toHaveProperty("type", "fast");
expect(store.getState.isCarrier()).toBe(true);
store.dispatch.setStreamlining("partial");
expect(store.getState.getStreamlining()).toBe("partial");
expect(store.selectors.getStreamlining(store.getState())).toBe("partial");
}); });

View File

@ -7,58 +7,78 @@ import ftl, { calcFtlReqs } from "./ship/propulsion/ftl";
import drive from "./ship/propulsion/drive"; import drive from "./ship/propulsion/drive";
import { calcDriveReqs } from "$lib/shipDux/engine"; import { calcDriveReqs } from "$lib/shipDux/engine";
import { carrierDux } from "./ship/carrier"; import { carrierDux } from "./ship/carrier";
import { streamliningDux as streamlining } from "./ship/structure/streamlining";
import { calcStreamliningReqs } from "./ship/structure/rules";
const shipDux = new Updux({ const shipDux = new Updux({
subduxes: { subduxes: {
identification, identification,
propulsion: new Updux({ structure: new Updux({
initial: {}, initialState: {},
subduxes: { subduxes: {
ftl, streamlining,
drive, },
}, }),
}), propulsion: new Updux({
carrier: carrierDux, initialState: {},
}, subduxes: {
ftl,
drive,
},
}),
carrier: carrierDux,
},
}); });
shipDux.addReaction((api) => shipDux.addReaction((api) =>
createSelector( createSelector(
api.selectors.getFtlType, api.selectors.getFtlType,
api.selectors.getShipMass, api.selectors.getShipMass,
(type, mass) => api.dispatch.setFtlReqs(calcFtlReqs(type, mass)) (type, mass) => api.dispatch.setFtlReqs(calcFtlReqs(type, mass))
) )
); );
shipDux.addReaction((api) => (state) => { shipDux.addReaction((api) => (state) => {
let cost = 0; let cost = 0;
let mass = 0; let mass = 0;
let subsystems = R.values(R.omit(state, ["identification"])); let subsystems = R.values(R.omit(state, ["identification"]));
while (subsystems.length > 0) { while (subsystems.length > 0) {
const subsystem = subsystems.shift(); const subsystem = subsystems.shift();
if (typeof subsystem !== "object") continue; if (typeof subsystem !== "object") continue;
if (subsystem.reqs) { if (subsystem.reqs) {
cost += subsystem.reqs.cost; cost += subsystem.reqs.cost;
mass += subsystem.reqs.mass; mass += subsystem.reqs.mass;
}
subsystems.push(...Object.values(subsystem));
} }
api.dispatch.setShipReqs({ cost, usedMass: mass }); subsystems.push(...Object.values(subsystem));
}
api.dispatch.setShipReqs({ cost, usedMass: mass });
}); });
shipDux.addReaction((api) => shipDux.addReaction((api) =>
createSelector( createSelector(
api.selectors.getShipMass, api.selectors.getShipMass,
(state) => state.propulsion.drive.rating, (state) => state.propulsion.drive.rating,
(state) => state.propulsion.drive.advanced, (state) => state.propulsion.drive.advanced,
(mass, rating, advanced) => (mass, rating, advanced) =>
api.dispatch.setDriveReqs(calcDriveReqs(mass, rating, advanced)) api.dispatch.setDriveReqs(calcDriveReqs(mass, rating, advanced))
) )
);
shipDux.addReaction((api) =>
createSelector(
// (state) => state,
api.selectors.getShipMass,
api.selectors.getStreamlining,
(mass, type) => {
console.log("AH!", mass, type);
api.dispatch.setStreamliningReqs(calcStreamliningReqs(type, mass));
}
)
); );
export default shipDux; export default shipDux;

View File

@ -7,7 +7,7 @@ type Squadron = {
reqs: Reqs; reqs: Reqs;
}; };
const initial = { const initialState = {
nbrBays: 0, nbrBays: 0,
squadrons: [] as Squadron[], squadrons: [] as Squadron[],
reqs, reqs,
@ -30,7 +30,7 @@ const setSquadronType = createPayloadAction(
); );
export const carrierDux = new Updux({ export const carrierDux = new Updux({
initial, initialState,
actions: { setNbrCarrierBays, setSquadronType }, actions: { setNbrCarrierBays, setSquadronType },
}); });
@ -93,7 +93,7 @@ function squadronReqs(type: string) {
/* /*
export const { actions, reducer } = createSlice({ export const { actions, reducer } = createSlice({
name: "carrier", name: "carrier",
initialState, initialStateState,
reducers: { reducers: {
setCarrierBays: (state, action: PayloadAction<number>) => { setCarrierBays: (state, action: PayloadAction<number>) => {
state.bays = action.payload; state.bays = action.payload;

View File

@ -1,7 +1,9 @@
import Updux, { createAction, withPayload } from "updux"; import Updux, { createAction, withPayload } from "updux";
import u from "@yanick/updeep-remeda"; import u from "@yanick/updeep-remeda";
import * as R from "remeda";
import { carrierDux } from "./carrier";
const initial = { const initialState = {
shipType: "", shipType: "",
shipClass: "", shipClass: "",
isCarrier: false, isCarrier: false,
@ -17,7 +19,7 @@ const updateIdentification = createAction("updateIdentification");
const setShipReqs = createAction("setShipReqs", withPayload()); const setShipReqs = createAction("setShipReqs", withPayload());
export const dux = new Updux({ export const dux = new Updux({
initial, initialState,
actions: { actions: {
setShipClass, setShipClass,
updateIdentification, updateIdentification,
@ -25,6 +27,7 @@ export const dux = new Updux({
}, },
selectors: { selectors: {
getShipMass: (state) => state.reqs.mass, getShipMass: (state) => state.reqs.mass,
isCarrier: ({ isCarrier }) => isCarrier,
}, },
}); });
@ -32,4 +35,10 @@ dux.addMutation(setShipClass, (shipClass) => u({ shipClass }));
dux.addMutation(updateIdentification, (update) => u(update)); dux.addMutation(updateIdentification, (update) => u(update));
dux.addMutation(setShipReqs, (reqs) => u({ reqs })); dux.addMutation(setShipReqs, (reqs) => u({ reqs }));
dux.addMutation(carrierDux.actions.setNbrCarrierBays, (nbrBays) =>
u({
isCarrier: nbrBays > 0,
})
);
export default dux; export default dux;

View File

@ -7,7 +7,7 @@ type DriveProps = {
advanced: boolean; advanced: boolean;
}; };
const initial: DriveProps & { reqs: Reqs } = { const initialState: DriveProps & { reqs: Reqs } = {
rating: 0, rating: 0,
advanced: false, advanced: false,
reqs, reqs,
@ -17,7 +17,7 @@ const setDrive = createPayloadAction<DriveProps>("setDrive");
const setDriveReqs = createPayloadAction<Reqs>("setDriveReqs"); const setDriveReqs = createPayloadAction<Reqs>("setDriveReqs");
const dux = new Updux({ const dux = new Updux({
initial, initialState,
actions: { setDrive, setDriveReqs }, actions: { setDrive, setDriveReqs },
}); });

View File

@ -7,7 +7,7 @@ export const ftlTypes = ["none", "standard", "advanced"] as const;
type FtlType = typeof ftlTypes[number]; type FtlType = typeof ftlTypes[number];
export const initial = { export const initialState = {
reqs, reqs,
type: "none" as FtlType, type: "none" as FtlType,
}; };
@ -16,7 +16,7 @@ const setFtlType = createAction("setFtlType", withPayload<FtlType>());
const setFtlReqs = createAction("setFtlReqs", withPayload<Reqs>()); const setFtlReqs = createAction("setFtlReqs", withPayload<Reqs>());
const dux = new Updux({ const dux = new Updux({
initial, initialState,
actions: { setFtlType, setFtlReqs }, actions: { setFtlType, setFtlReqs },
selectors: { selectors: {
getFtlType: R.prop<any, any>("type"), getFtlType: R.prop<any, any>("type"),

View File

@ -0,0 +1,9 @@
export type Streamlining = "none" | "partial" | "full";
export function calcStreamliningReqs(type: Streamlining, shipMass: number) {
const mass = Math.ceil(
(shipMass * (type === "none" ? 0 : type === "partial" ? 5 : 10)) / 100
);
return { mass, cost: 2 * mass };
}

View File

@ -0,0 +1,26 @@
import { reqs } from "$lib/shipDux/reqs";
import Updux, { createPayloadAction } from "updux";
import type { Streamlining } from "./rules";
import u from "@yanick/updeep-remeda";
const initialState = {
type: "none" as Streamlining,
reqs,
};
const setStreamlining = createPayloadAction<Streamlining>("setStreamlining");
const setStreamliningReqs = createPayloadAction("setStreamliningReqs");
export const streamliningDux = new Updux({
initialState,
actions: { setStreamlining, setStreamliningReqs },
selectors: {
getStreamlining: (state) => {
return state?.type;
},
},
});
streamliningDux.addMutation(setStreamlining, (type) => u({ type }));
streamliningDux.addMutation(setStreamliningReqs, (reqs) => u({ reqs }));