ShipEdit with propulsion
This commit is contained in:
parent
cdb7e8ee35
commit
a415278b6a
@ -116,7 +116,7 @@
|
|||||||
border: 1px solid var(--indigo-dye);
|
border: 1px solid var(--indigo-dye);
|
||||||
}
|
}
|
||||||
|
|
||||||
input:not([type="checkbox"]) {
|
input:not([type="checkbox"]):not([type="radio"]) {
|
||||||
border: 0px;
|
border: 0px;
|
||||||
border-bottom: 1px solid var(--indigo-dye);
|
border-bottom: 1px solid var(--indigo-dye);
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
<main>
|
<main>
|
||||||
<Identification {...ship.identification} />
|
<Identification {...ship.identification} />
|
||||||
|
<Propulsion {...ship.propulsion} />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Identification from "./ShipEdit/Identification.svelte";
|
import Identification from "./ShipEdit/Identification.svelte";
|
||||||
|
import Propulsion from "./ShipEdit/Propulsion.svelte";
|
||||||
|
import shipDux from "$lib/store/ship";
|
||||||
|
|
||||||
export let ship = {
|
export let ship = shipDux.initial;
|
||||||
identification: {},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
export let rating = 0;
|
export let rating = 0;
|
||||||
export let api = getContext("api");
|
export let api = getContext("api");
|
||||||
|
|
||||||
$: api?.dispatch?.setEngine({ rating, advanced });
|
$: api?.dispatch?.setEngine?.({ rating, advanced });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<ShipItem {...reqs}>
|
<ShipItem {...reqs}>
|
||||||
<Field label="FTL drive">
|
<Field label="FTL drive">
|
||||||
{#each types as t (t)}
|
{#each ftlTypes as t (t)}
|
||||||
<label
|
<label
|
||||||
><input type="radio" bind:group={type} value={t} />
|
><input type="radio" bind:group={type} value={t} />
|
||||||
{t}
|
{t}
|
||||||
@ -15,13 +15,13 @@
|
|||||||
import ShipItem from "$lib/components/ShipItem.svelte";
|
import ShipItem from "$lib/components/ShipItem.svelte";
|
||||||
import Field from "$lib/components/Field.svelte";
|
import Field from "$lib/components/Field.svelte";
|
||||||
|
|
||||||
|
import { ftlTypes } from "$lib/store/ship/propulsion/ftl";
|
||||||
|
|
||||||
export let type = "none";
|
export let type = "none";
|
||||||
export let reqs = { mass: 0, cost: 0 };
|
export let reqs = { mass: 0, cost: 0 };
|
||||||
export let api = getContext("api");
|
export let api = getContext("api");
|
||||||
|
|
||||||
const types = ["none", "standard", "advanced"];
|
$: api?.dispatch.setFtlType?.(type);
|
||||||
|
|
||||||
$: api?.dispatch.setFtl(type);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -5,43 +5,17 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|||||||
|
|
||||||
import { reqs, Reqs } from "../reqs.js";
|
import { reqs, Reqs } from "../reqs.js";
|
||||||
|
|
||||||
export const ftlTypes = ["none", "standard", "advanced"] as const;
|
|
||||||
type FtlType = typeof ftlTypes[number];
|
|
||||||
|
|
||||||
export const initialState = {
|
|
||||||
reqs,
|
|
||||||
type: "none" as FtlType,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ftl = createSlice({
|
const ftl = createSlice({
|
||||||
name: "ftl",
|
name: "ftl",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
setFtl: (state, { payload }: PayloadAction<FtlType>) => {
|
setFtl: (state, { payload }: PayloadAction<FtlType>) => {
|
||||||
state.type = payload;
|
state.type = payload;
|
||||||
|
},
|
||||||
|
setFtlReqs: (state, action: PayloadAction<Reqs>) => {
|
||||||
|
state.reqs = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setFtlReqs: (state, action: PayloadAction<Reqs>) => {
|
|
||||||
state.reqs = action.payload;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export function calcFtlReqs(type: FtlType, shipMass: number): Reqs {
|
|
||||||
if (type === "none") return { cost: 0, mass: 0 };
|
|
||||||
|
|
||||||
const mass = Math.ceil(shipMass / 10);
|
|
||||||
|
|
||||||
return {
|
|
||||||
mass,
|
|
||||||
cost: mass * (type === "advanced" ? 3 : 2),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const { actions, reducer } = ftl;
|
export const { actions, reducer } = ftl;
|
||||||
|
|
||||||
// needs to be at the top level
|
|
||||||
export const ftlReqsReaction = (store) =>
|
|
||||||
createSelector(
|
|
||||||
[(ship) => ship.propulsion.ftl.type, (ship) => ship.reqs.mass],
|
|
||||||
(type, shipMass) => store.dispatch.setFtlReqs(calcFtlReqs(type, shipMass))
|
|
||||||
);
|
|
||||||
|
10
src/lib/store/ship.test.ts
Normal file
10
src/lib/store/ship.test.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { test, expect } from "vitest";
|
||||||
|
import ship from "./ship";
|
||||||
|
|
||||||
|
test("ftlReqs reaction", () => {
|
||||||
|
const store = ship.createStore();
|
||||||
|
store.dispatch.setFtlType("standard");
|
||||||
|
|
||||||
|
expect(store.getState().propulsion.ftl.reqs.mass).toEqual(1);
|
||||||
|
expect(store.getState().identification.reqs.usedMass).toEqual(1);
|
||||||
|
});
|
@ -1,11 +1,48 @@
|
|||||||
|
import { createSelector } from "@reduxjs/toolkit";
|
||||||
import Updux from "updux";
|
import Updux from "updux";
|
||||||
|
import * as R from "remeda";
|
||||||
|
|
||||||
import identification from "./ship/identification";
|
import identification from "./ship/identification";
|
||||||
|
import ftl, { calcFtlReqs } from "./ship/propulsion/ftl";
|
||||||
|
|
||||||
const shipDux = new Updux({
|
const shipDux = new Updux({
|
||||||
subduxes: {
|
subduxes: {
|
||||||
identification,
|
identification,
|
||||||
|
propulsion: new Updux({
|
||||||
|
subduxes: {
|
||||||
|
ftl,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
shipDux.addReaction((api) =>
|
||||||
|
createSelector(
|
||||||
|
api.selectors.getFtlType,
|
||||||
|
api.selectors.getShipMass,
|
||||||
|
(type, mass) => api.dispatch.setFtlReqs(calcFtlReqs(type, mass))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
shipDux.addReaction((api) => (state) => {
|
||||||
|
let cost = 0;
|
||||||
|
let mass = 0;
|
||||||
|
|
||||||
|
let subsystems = R.values(R.omit(state, ["identification"]));
|
||||||
|
|
||||||
|
while (subsystems.length > 0) {
|
||||||
|
const subsystem = subsystems.shift();
|
||||||
|
if (typeof subsystem !== "object") continue;
|
||||||
|
|
||||||
|
if (subsystem.reqs) {
|
||||||
|
cost += subsystem.reqs.cost;
|
||||||
|
mass += subsystem.reqs.mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
subsystems.push(...Object.values(subsystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
api.dispatch.setShipReqs({ cost, usedMass: mass });
|
||||||
|
});
|
||||||
|
|
||||||
export default shipDux;
|
export default shipDux;
|
||||||
|
@ -14,16 +14,22 @@ const initial = {
|
|||||||
|
|
||||||
const setShipClass = createAction("setShipClass", withPayload<string>());
|
const setShipClass = createAction("setShipClass", withPayload<string>());
|
||||||
const updateIdentification = createAction("updateIdentification");
|
const updateIdentification = createAction("updateIdentification");
|
||||||
|
const setShipReqs = createAction("setShipReqs", withPayload());
|
||||||
|
|
||||||
export const dux = new Updux({
|
export const dux = new Updux({
|
||||||
initial,
|
initial,
|
||||||
actions: {
|
actions: {
|
||||||
setShipClass,
|
setShipClass,
|
||||||
updateIdentification,
|
updateIdentification,
|
||||||
|
setShipReqs,
|
||||||
|
},
|
||||||
|
selectors: {
|
||||||
|
getShipMass: (state) => state.reqs.mass,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
dux.addMutation(setShipClass, (shipClass) => u({ shipClass }));
|
dux.addMutation(setShipClass, (shipClass) => u({ shipClass }));
|
||||||
dux.addMutation(updateIdentification, (update) => u(update));
|
dux.addMutation(updateIdentification, (update) => u(update));
|
||||||
|
dux.addMutation(setShipReqs, (reqs) => u({ reqs }));
|
||||||
|
|
||||||
export default dux;
|
export default dux;
|
||||||
|
40
src/lib/store/ship/propulsion/ftl.ts
Normal file
40
src/lib/store/ship/propulsion/ftl.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { reqs, type Reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux, { createAction, withPayload } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
import * as R from "remeda";
|
||||||
|
|
||||||
|
export const ftlTypes = ["none", "standard", "advanced"] as const;
|
||||||
|
|
||||||
|
type FtlType = typeof ftlTypes[number];
|
||||||
|
|
||||||
|
export const initial = {
|
||||||
|
reqs,
|
||||||
|
type: "none" as FtlType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const setFtlType = createAction("setFtlType", withPayload<FtlType>());
|
||||||
|
const setFtlReqs = createAction("setFtlReqs", withPayload<Reqs>());
|
||||||
|
|
||||||
|
const dux = new Updux({
|
||||||
|
initial,
|
||||||
|
actions: { setFtlType, setFtlReqs },
|
||||||
|
selectors: {
|
||||||
|
getFtlType: R.prop<any, any>("type"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
dux.addMutation(setFtlType, (type) => u({ type }));
|
||||||
|
dux.addMutation(setFtlReqs, (reqs) => u({ reqs }));
|
||||||
|
|
||||||
|
export default dux;
|
||||||
|
|
||||||
|
export function calcFtlReqs(type: FtlType, shipMass: number): Reqs {
|
||||||
|
if (type === "none") return { cost: 0, mass: 0 };
|
||||||
|
|
||||||
|
const mass = Math.ceil(shipMass / 10);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mass,
|
||||||
|
cost: mass * (type === "advanced" ? 3 : 2),
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user