Merge branch 'identification' into version-2

main
Yanick Champoux 2022-03-02 10:43:17 -05:00
commit 0a0b78336d
17 changed files with 281 additions and 131 deletions

View File

@ -27,6 +27,7 @@ module.exports = {
$app: path.resolve("./fake/app"),
"\\$lib": path.resolve(__dirname, "../src/lib/"),
$lib: path.resolve(__dirname, "../src/lib/"),
"\\$app/env": path.resolve(__dirname, "../fake/app/env.js"),
},
},
};

1
fake/app/env.js Normal file
View File

@ -0,0 +1 @@
export const browser = true;

View File

@ -35,14 +35,13 @@
"@storybook/addon-svelte-csf": "^1.1.0",
"@storybook/svelte": "^6.4.19",
"@sveltejs/adapter-node": "^1.0.0-next.0",
"@yanick/updeep": "link:/home/yanick/work/javascript/updeep",
"lodash": "^4.17.21",
"redux": "^4.1.2",
"reselect": "^4.1.5",
"rollup-plugin-analyzer": "^4.0.0",
"svelte-knobby": "^0.3.4",
"ts-action": "^11.0.0",
"updux": "link:/home/yanick/work/javascript/updux/",
"updux": "link:/home/yanick/work/javascript/updux-js/",
"webpack": "5"
},
"prettier": {

View File

@ -5,15 +5,15 @@ import { createSelector } from "reselect";
import ftl from "./ftl";
import engine, { calc_drive_reqs } from "./engine";
import weaponry from './weaponry';
import weaponry from "./weaponry";
import { calc_ftl_reqs } from "./ftl/rules";
import { calc_ship_req } from "./utils";
import { candidate_ship_types } from './ship_types';
import structure from './structure';
import cargo from './cargo';
import streamlining from './streamlining';
import carrier from './carrier';
import { ceil } from './utils';
import { candidate_ship_types } from "./ship_types";
import structure from "./structure";
import cargo from "./cargo";
import streamlining from "./streamlining";
import carrier from "./carrier";
import { ceil } from "./utils";
const set_ship_mass = action("set_ship_mass", payload());
const set_name = action("set_name", payload());
@ -21,31 +21,29 @@ const set_name = action("set_name", payload());
const set_ship_reqs = action("set_ship_reqs", payload());
const set_hull = action("set_hull", payload());
const set_ship_type = action('set_ship_type',payload());
const set_ship_type = action("set_ship_type", payload());
const reset = action('reset' );
const reset = action("reset");
const initial = {
general: {
ship_class: "",
name: "",
ship_type: "",
mass: 10,
used_mass: 0,
cost: 10,
},
};
console.log(Updux);
general: {
ship_class: "",
name: "",
ship_type: "",
mass: 10,
used_mass: 0,
cost: 10,
},
};
const dux = new Updux({
subduxes: { ftl, engine, weaponry, structure, cargo, streamlining, carrier },
initial
initial,
});
dux.addMutation( reset, () => () => initial );
dux.addMutation(reset, () => () => initial);
dux.addMutation(set_hull, ({rating}) => (state) => {
dux.addMutation(set_hull, ({ rating }) => (state) => {
return u.updateIn("structure.hull", {
cost: 2 * rating,
rating,
@ -55,8 +53,8 @@ dux.addMutation(set_hull, ({rating}) => (state) => {
dux.addMutation(set_ship_mass, (mass) => u.updateIn("general", { mass }));
dux.addMutation(set_name, (name) => u.updateIn("general", { name }));
dux.addMutation( action('set_ship_class',payload() ),
ship_class => u.updateIn('general',{ship_class})
dux.addMutation(action("set_ship_class", payload()), (ship_class) =>
u.updateIn("general", { ship_class })
);
dux.addMutation(set_ship_reqs, ({ cost, mass: used_mass }) =>
@ -70,71 +68,73 @@ dux.addSubscription((store) =>
dux.addSubscription((store) =>
createSelector(
store => store.general.mass,
store => store.streamlining.type,
(ship_mass, streamlining ) => {
const mass = ceil( ship_mass * (
streamlining === 'none' ? 0
: streamlining === 'partial' ? 5 : 10
) / 100 );
const cost = 2 * mass;
(store) => store.general.mass,
(store) => store.streamlining.type,
(ship_mass, streamlining) => {
const mass = ceil(
(ship_mass *
(streamlining === "none" ? 0 : streamlining === "partial" ? 5 : 10)) /
100
);
const cost = 2 * mass;
store.dispatch( dux.actions.set_streamlining_cost_mass({cost,mass}) );
}
store.dispatch(dux.actions.set_streamlining_cost_mass({ cost, mass }));
}
)
);
dux.addSubscription((store) =>
createSelector(
store => store.general.mass,
store => store.general.ship_type,
store => store.carrier.bays,
(mass,type,bays) => {
console.log({bays});
const candidates = candidate_ship_types(mass,bays > 0);
createSelector(
(store) => store.general.mass,
(store) => store.general.ship_type,
(store) => store.carrier.bays,
(mass, type, bays) => {
console.log({ bays });
const candidates = candidate_ship_types(mass, bays > 0);
console.log({candidates});
if( candidates.length === 0 ) return;
console.log({ candidates });
if (candidates.length === 0) return;
if( candidates.find( ({name}) => name === type ) ) return;
if (candidates.find(({ name }) => name === type)) return;
store.dispatch(
store.actions.set_ship_type(
candidates[0].name
)
)
}
)
store.dispatch(store.actions.set_ship_type(candidates[0].name));
}
)
);
dux.addMutation(set_ship_type, type => u.updateIn('general.ship_type',type) );
dux.addMutation(set_ship_type, (type) => u.updateIn("general.ship_type", type));
dux.addSubscription((store) =>
createSelector(
[(ship) => ship.general.mass, (ship) => ship.ftl.type],
(ship_mass, type) =>
store.dispatch(ftl.actions.set_ftl_reqs(calc_ftl_reqs(type,ship_mass)))
store.dispatch(ftl.actions.set_ftl_reqs(calc_ftl_reqs(type, ship_mass)))
)
);
dux.addSubscription( store => createSelector(
ship => ship.general.mass,
ship => ship.structure.screens.standard,
ship => ship.structure.screens.advanced,
(mass,standard,advanced) => {
console.log({
mass, standard, advanced
})
const standard_mass = standard * Math.max(3,ceil( 0.05 * mass ));
const advanced_mass = advanced * Math.max(4,ceil( 0.075 * mass ));
dux.addSubscription((store) =>
createSelector(
(ship) => ship.general.mass,
(ship) => ship.structure.screens.standard,
(ship) => ship.structure.screens.advanced,
(mass, standard, advanced) => {
console.log({
mass,
standard,
advanced,
});
const standard_mass = standard * Math.max(3, ceil(0.05 * mass));
const advanced_mass = advanced * Math.max(4, ceil(0.075 * mass));
store.dispatch( dux.actions.set_screens_reqs({
mass: standard_mass + advanced_mass,
cost: 3 * standard_mass + 4 * advanced_mass
}));
store.dispatch(
dux.actions.set_screens_reqs({
mass: standard_mass + advanced_mass,
cost: 3 * standard_mass + 4 * advanced_mass,
})
);
}
));
)
);
dux.addSubscription((store) =>
createSelector(

View File

@ -3,7 +3,7 @@
<label>{label}</label>
{/if}
<slot>
<input type="text" {placeholder} {value} on:change />
<input type="text" {placeholder} bind:value on:change />
</slot>
</div>

View File

@ -0,0 +1,22 @@
<Meta title="Identification" component={Identification} argTypes={{}} />
<Story name="Primary" args={{}} />
<Template let:args>
<div style="width: 50em">
<Identification {...args} />
</div>
</Template>
<script>
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
import { action } from "@storybook/addon-actions";
import { setContext } from "svelte";
import Identification from "./index.svelte";
setContext("ship", {
dispatch: (type, detail) => action(type)(detail),
});
</script>

View File

@ -0,0 +1,40 @@
<div>
<Field label="ship class" bind:value={shipClass} />
<Field label="ship type">
<select bind:value={shipType}>
{#each shipTypes as name (name)}
<option>{name}</option>
{/each}
</select>
</Field>
</div>
<script>
import { getContext } from "svelte";
import Field from "$lib/components/Field/index.svelte";
import { candidateShipTypes } from "./shipTypes.js";
export let shipClass = "";
export let shipType = "";
export let mass = 10;
export let isCarrier = false;
const ship = getContext("ship");
$: shipTypes = candidateShipTypes(mass, isCarrier).map(({ name }) => name);
$: if (shipTypes.length > 0 && !shipTypes.includes(shipType))
shipType = shipTypes[0];
$: ship.dispatch.setShipType(shipType);
$: ship.dispatch.setShipClass(shipClass);
</script>
<style>
div {
display: flex;
align-items: end;
gap: 2em;
}
</style>

View File

@ -20,7 +20,9 @@ const ship_types = [
{ name: "Attack Carrier", mass: [150, 300], abbrev: "CVA", carrier: true },
];
export function candidate_ship_types(mass = 0, carrier = false) {
console.log({carrier});
return ship_types.filter((c) => carrier == !!c.carrier).filter((c) => c.mass[0] <= mass).filter((c) => c.mass[1] >= mass);
export function candidateShipTypes(mass = 0, carrier = false) {
return ship_types
.filter((c) => carrier == !!c.carrier)
.filter((c) => c.mass[0] <= mass)
.filter((c) => c.mass[1] >= mass);
}

View File

@ -0,0 +1,21 @@
<Meta title="ShipEdit" component={ShipEdit} argTypes={{}} />
<Story name="Primary" args={{}} />
<Template let:args>
<div style="width: 50em">
<ShipEdit />
</div>
</Template>
<script>
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
import { action } from "@storybook/addon-actions";
import { setContext } from "svelte";
import ShipEdit from "./index.svelte";
import shipStore from "$lib/store/ship.js";
setContext("ship", shipStore());
</script>

View File

@ -0,0 +1,12 @@
<Identification {...$shipState.identification} {...$shipState.reqs} />
<script>
import { getContext } from "svelte";
import Identification from "./Identification/index.svelte";
const { state: shipState } = getContext("ship");
</script>
<style>
</style>

View File

@ -1,49 +0,0 @@
<div>
<Field
label="ship class"
value={general.ship_class}
on:change={change_class}
/>
<Field label="ship type">
<select value={ship_type} on:change={change_ship_type}>
{#each ship_types as type (type)}
<option>{type}</option>
{/each}
</select>
</Field>
</div>
<script>
import { getContext } from "svelte";
import Field from "$lib/components/Field/index.svelte";
import { candidate_ship_types } from "../../dux/ship_types";
export let ship = getContext("ship");
let general;
$: general = $ship.general;
const change_class = (event) =>
ship.dispatch(ship.actions.set_ship_class(event.target.value));
let ship_type;
$: ship_type = $ship.general.ship_type;
const change_ship_type = ({ target: { value } }) =>
ship.dispatch.set_ship_type(value);
let ship_types;
$: ship_types = candidate_ship_types(
$ship.general.mass,
$ship.carrier.bays > 0
).map(({ name }) => name);
</script>
<style>
div {
display: flex;
align-items: end;
gap: 2em;
}
</style>

View File

@ -6,9 +6,3 @@
import Identification from "./Identification.svelte";
import ShipCost from "./ShipCost.svelte";
</script>
<style>
div {
background-color: red;
}
</style>

28
src/lib/shipDux/engine.js Normal file
View File

@ -0,0 +1,28 @@
import { Updux } from "updux";
import u from "updeep";
import reqs from "./reqs.js";
const dux = new Updux({
subduxes: { reqs },
initial: {
rating: 1,
advanced: false,
},
actions: {
setEngine: null,
setEngineReqs: null,
},
});
dux.setMutation("setEngine", (changes) => u(changes));
dux.setMutation("setEngineReqs", (reqs) => u({ reqs }));
export function calcDriveReqs(shipMass, rating, advanced = false) {
const mass = Math.ceil(rating * 0.05 * shipMass);
const cost = mass * (advanced ? 3 : 2);
return { mass, cost };
}
export default dux;

View File

@ -0,0 +1,20 @@
import { Updux } from "updux";
import u from "updeep";
const dux = new Updux({
actions: {
setShipType: null,
setShipClass: null,
},
initial: {
shipType: "",
shipClass: "",
isCarrier: false,
mass: 10,
},
});
dux.setMutation("setShipType", (shipType) => u({ shipType }));
dux.setMutation("setShipClass", (shipClass) => u({ shipClass }));
export default dux;

17
src/lib/shipDux/index.js Normal file
View File

@ -0,0 +1,17 @@
import { Updux } from "updux";
import engine from "./engine.js";
import identification from "./identification.js";
import reqs from "./reqs.js";
const dux = new Updux({
subduxes: {
identification,
engine,
},
initial: {
reqs: { cost: 0, mass: 10 },
},
});
export default dux;

10
src/lib/shipDux/reqs.js Normal file
View File

@ -0,0 +1,10 @@
import { Updux } from "updux";
const dux = new Updux({
initial: {
cost: 0,
mass: 0,
},
});
export default dux;

32
src/lib/store/ship.js Normal file
View File

@ -0,0 +1,32 @@
import { browser } from "$app/env";
import { readable, get } from "svelte/store";
import { compose, applyMiddleware } from "redux";
import shipDux from "../shipDux/index.js";
let composeEnhancers = compose;
if (browser) {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
}
export default () => {
const duxStore = shipDux.createStore(undefined, (mw) =>
composeEnhancers(applyMiddleware(mw))
);
let previous;
const state = readable(duxStore.getState(), (set) => {
duxStore.subscribe(() => {
if (previous === duxStore.getState()) return;
previous = duxStore.getState();
console.log("Setting!", previous);
set(previous);
});
});
return {
dispatch: duxStore.dispatch,
state,
};
};