Merge branch 'day-20-factory' of https://github.com/thepaperpilot/Advent-Incremental into day-20-factory

This commit is contained in:
circle-gon 2022-12-21 14:15:43 +00:00
commit 6f3f1f1985
2 changed files with 208 additions and 122 deletions

View file

@ -10,6 +10,7 @@ import { globalBus } from "game/events";
import { createLayer } from "game/layers";
import { Persistent, persistent, State } from "game/persistence";
import player from "game/player";
import { format, formatWhole } from "util/bignum";
import { Direction } from "util/common";
import { computed, ComputedRef, reactive, ref, watchEffect } from "vue";
import conveyor from "./factory-components/conveyor.png";
@ -103,31 +104,19 @@ const factory = createLayer(id, () => {
imageSrc: cursor,
name: "Cursor",
description: "Use this to move.",
tick: 0,
consumption: {},
consumptionStock: {},
production: {},
productionStock: {}
tick: 0
},
rotate: {
imageSrc: rotate,
name: "Rotate",
description: "Use this to rotate components.",
tick: 0,
consumption: {},
consumptionStock: {},
production: {},
productionStock: {}
tick: 0
},
conveyor: {
imageSrc: conveyor,
name: "Conveyor",
description: "Moves 1 item per tick.",
tick: 1,
consumption: {},
consumptionStock: {},
production: {},
productionStock: {},
ports: {
[Direction.Left]: {
type: "input"
@ -139,24 +128,51 @@ const factory = createLayer(id, () => {
},
square: {
imageSrc: square,
name: "???",
name: "Producer",
description: "Produces 1 square every 1 tick.",
tick: 1,
production: {
square: 1
},
productionStock: {
square: Infinity
},
consumption: {},
consumptionStock: {}
outputs: {
square: {
amount: 1
}
} as Record<string, FactoryComponentDeclaration>;
}
},
receiver: {
imageSrc: square,
name: "Receiver",
description: "Obtains squares. Pretty much does nothing else.",
tick: 0,
inputs: {
square: {
amount: Infinity
}
}
},
shrinker: {
imageSrc: square,
name: "Shrinker",
description:
"Converts 100 squares to 1 square. I don't know why you would want to do this but here you go anyways.",
tick: 1,
inputs: {
square: {
amount: 100,
capacity: 10000
}
},
outputs: {
square: {
amount: 1,
capacity: 10
}
}
}
} as Record<FactoryCompNames, FactoryComponentDeclaration>;
const RESOURCES = {
square: square
} as Record<string, string>;
type FactoryCompNames = keyof typeof FACTORY_COMPONENTS;
type FactoryCompNames = "cursor" | "rotate" | "conveyor" | "square" | "receiver" | "shrinker";
type BuildableCompName = Exclude<FactoryCompNames, "cursor">;
interface FactoryComponentBase extends Record<string, State> {
@ -165,10 +181,10 @@ const factory = createLayer(id, () => {
interface FactoryComponentProducer extends FactoryComponentBase {
type: Exclude<BuildableCompName, "conveyor">;
consumptionStock: Record<string, number>;
inputStock?: Record<string, number>;
// current production stock
productionStock: Record<string, number>;
outputStock?: Record<string, number>;
ticksDone: number;
}
@ -186,13 +202,21 @@ const factory = createLayer(id, () => {
description: string;
/** amount it consumes */
consumption: Record<string, number>;
/** maximum stock of consumption */
consumptionStock: Record<string, number>;
inputs?: Record<
string,
{
amount: number;
capacity?: number;
}
>;
/** amount it produces */
production: Record<string, number>;
/** maximum stock of production */
productionStock: Record<string, number>;
outputs?: Record<
string,
{
amount: number;
capacity?: number;
}
>;
/** on produce, do something */
onProduce?: (times: number) => void;
@ -223,8 +247,8 @@ const factory = createLayer(id, () => {
// in block amts, not screen
x: number;
y: number;
lastX: number;
lastY: number;
// make blocks turn in random amounts;
turbulance: number;
}
// mouse positions
@ -321,8 +345,6 @@ const factory = createLayer(id, () => {
globalBus.on("update", diff => {
if (taskIsRunning || !loaded) return;
//debugger
// will change soon:tm:
const tick = diff;
// make them produce
for (const id in components.value) {
const [x, y] = id.split("x").map(p => +p);
@ -339,12 +361,13 @@ const factory = createLayer(id, () => {
// use a copy
compData.packages = compData.packages.concat(compData.nextPackages);
compData.nextPackages = [];
for (const [key, block] of [...compData.packages].entries()) {
const inputDirection = rotateDir(data.direction, Direction.Left);
for (let key = 0; key < compData.packages.length; key++) {
const block = compData.packages[key];
const inputDirection = data.direction;
const dirType = getDirection(inputDirection);
const dirAmt = directionToNum(inputDirection);
if (dirType === "h") {
if (block.x <= block.lastX + dirAmt) {
if ((block.x - x) * dirAmt >= 1 + block.turbulance) {
const compBehind = compInternalData[x + dirAmt + "x" + y];
const storedComp = components.value[x + dirAmt + "x" + y];
@ -352,29 +375,34 @@ const factory = createLayer(id, () => {
if (compBehind === undefined) {
// just delete it
movingBlocks.removeChild(block.sprite);
compData.packages.splice(key, 1);
} else if (compBehind.type === "conveyor") {
// push it to the next conveyor, kill it from the
// curent conveyor
block.lastX += dirAmt;
block.turbulance = Math.random() * 0.4 - 0.2;
(compBehind as FactoryInternalConveyor).nextPackages.push(block);
compData.packages.splice(key, 1);
} else {
// send it to the factory
// destory its sprite and data
const factoryData = storedComp as FactoryComponentProducer;
factoryData.consumptionStock[block.type]++;
if (factoryData.inputStock !== undefined)
factoryData.inputStock[block.type] = Math.min(
(factoryData.inputStock[block.type] ?? 0) + 1,
FACTORY_COMPONENTS[compBehind.type].inputs?.[block.type]
?.capacity ?? Infinity
);
movingBlocks.removeChild(block.sprite);
compData.packages.splice(key, 1);
}
compData.packages.splice(key, 1);
key--;
} else {
const change =
dirAmt * Math.min(Math.abs(block.x + 1 - block.lastX), tick);
dirAmt * Math.min(Math.abs(x + 1.3 * dirAmt - block.x), diff);
block.x += change;
block.sprite.x += change * blockSize;
}
} else {
if (block.y <= block.lastY + dirAmt) {
if ((block.y - y) * dirAmt >= 1 + block.turbulance) {
const compBehind = compInternalData[x + "x" + (y + dirAmt)];
const storedComp = components.value[x + "x" + (y + dirAmt)];
@ -382,23 +410,28 @@ const factory = createLayer(id, () => {
if (compBehind === undefined) {
// just delete it
movingBlocks.removeChild(block.sprite);
compData.packages.splice(key, 1);
} else if (compBehind.type === "conveyor") {
// push it to the next conveyor, kill it from the
// curent conveyor
block.lastY += dirAmt;
block.turbulance = Math.random() * 0.4 - 0.2;
(compBehind as FactoryInternalConveyor).nextPackages.push(block);
compData.packages.splice(key, 1);
} else {
// send it to the factory
// destory its sprite and data
const factoryData = storedComp as FactoryComponentProducer;
factoryData.consumptionStock[block.type]++;
movingBlocks.removeChild(block.sprite);
compData.packages.splice(key, 1);
const data = storedComp as FactoryComponentProducer;
if (factoryData.inputs?.[block.type] !== undefined) {
if (data.inputStock === undefined) data.inputStock = {};
data.inputStock[block.type] =
(data.inputStock[block.type] ?? 0) + 1;
}
movingBlocks.removeChild(block.sprite);
}
compData.packages.splice(key, 1);
key--;
} else {
const change = dirAmt * Math.min(Math.abs(block.y - block.lastY), tick);
const change =
dirAmt * Math.min(Math.abs(y + 1.3 * dirAmt - block.y), diff);
block.y += change;
block.sprite.y += change * blockSize;
}
@ -410,57 +443,69 @@ const factory = createLayer(id, () => {
// factory part
// PRODUCTION
if (data.ticksDone >= factoryData.tick) {
if (!compData.canProduce.value) continue;
if (compData.canProduce.value) {
const cyclesDone = Math.floor(data.ticksDone / factoryData.tick);
factoryData.onProduce?.(cyclesDone);
for (const [key, val] of Object.entries(factoryData.consumption)) {
data.consumptionStock[key] -= val;
if (factoryData.inputs !== undefined) {
if (data.inputStock === undefined) data.inputStock = {};
for (const [key, val] of Object.entries(factoryData.inputs)) {
data.inputStock[key] = (data.inputStock[key] ?? 0) - val.amount;
}
}
if (factoryData.outputs !== undefined) {
if (data.outputStock === undefined) data.outputStock = {};
for (const [key, val] of Object.entries(factoryData.outputs)) {
data.outputStock[key] = (data.outputStock[key] ?? 0) + val.amount;
}
for (const [key, val] of Object.entries(factoryData.production)) {
data.productionStock[key] += val;
}
data.ticksDone -= cyclesDone * factoryData.tick;
}
} else {
data.ticksDone += tick;
data.ticksDone += diff;
}
// now look at each component direction and see if it accepts items coming in
// components are 1x1 so simple math for now
let yInc = 0;
let xInc = 0;
const incs: [number, number][] = [];
if (
components.value[x + "x" + (y + 1)]?.type === "conveyor" &&
components.value[x + "x" + (y + 1)].direction === Direction.Up
components.value[x + "x" + (y + 1)].direction === Direction.Down
) {
yInc = 1;
} else if (
incs.push([0, 1]);
}
if (
components.value[x + "x" + (y - 1)]?.type === "conveyor" &&
components.value[x + "x" + (y - 1)].direction === Direction.Down
components.value[x + "x" + (y - 1)].direction === Direction.Up
) {
yInc = -1;
} else if (
incs.push([0, -1]);
}
if (
components.value[x + 1 + "x" + y]?.type === "conveyor" &&
components.value[x + 1 + "x" + y].direction === Direction.Right
) {
xInc = 1;
} else if (
incs.push([1, 0]);
}
if (
components.value[x - 1 + "x" + y]?.type === "conveyor" &&
components.value[x - 1 + "x" + y].direction === Direction.Left
) {
xInc = -1;
incs.push([-1, 0]);
}
// no suitable location to dump stuff in
// console.log(x, y);
// debugger;
if (xInc === 0 && yInc === 0) continue;
if (incs.length <= 0) continue;
const [xInc, yInc] = incs[Math.floor(Math.random() * incs.length)];
let itemToMove: [string, number] | undefined = undefined;
for (const [name, amt] of Object.entries(data.productionStock)) {
if (data.outputStock !== undefined) {
for (const [name, amt] of Object.entries(data.outputStock)) {
if (amt >= 1) {
itemToMove = [name, amt];
data.productionStock[name]--;
data.outputStock[name]--;
break;
}
}
}
// there is nothing to move
if (itemToMove === undefined) continue;
const texture = Assets.get(RESOURCES[itemToMove[0]]);
@ -479,20 +524,17 @@ const factory = createLayer(id, () => {
// if X is being moved, then we don't need to adjust x
// however it needs to be aligned if Y is being moved
// vice-versa
const spriteDiffX = xInc !== 0 ? 0 : 0.5;
const spriteDiffY = yInc !== 0 ? 0 : 0.5;
sprite.x = (x + spriteDiffX) * blockSize;
sprite.y = (y + spriteDiffY) * blockSize;
sprite.x = (x + xInc * 0.3) * blockSize;
sprite.y = (y + yInc * 0.3) * blockSize;
sprite.anchor.set(0.5);
sprite.width = blockSize / 2.5;
sprite.height = blockSize / 5;
//console.log(sprite);
const block: Block = {
sprite,
x: x,
y: y,
lastX: x,
lastY: y,
x: x + xInc * 0.3,
y: y + yInc * 0.3,
turbulance: Math.random() * 0.4 - 0.2,
type: itemToMove[0]
};
@ -533,17 +575,17 @@ const factory = createLayer(id, () => {
components.value[x + "x" + y] = {
ticksDone: 0,
direction: Direction.Right,
consumptionStock:
data.type === "conveyor"
inputStock:
factoryBaseData.inputs === undefined
? undefined
: Object.fromEntries(
Object.keys(factoryBaseData.consumptionStock).map(i => [i, 0])
Object.entries(factoryBaseData.inputs).map(x => [x[0], 0])
),
productionStock:
data.type === "conveyor"
outputStock:
factoryBaseData.outputs === undefined
? undefined
: Object.fromEntries(
Object.keys(factoryBaseData.productionStock).map(i => [i, 0])
Object.entries(factoryBaseData.outputs).map(x => [x[0], 0])
),
...data
} as FactoryComponent;
@ -557,18 +599,18 @@ const factory = createLayer(id, () => {
if (!(factoryBaseData.canProduce?.value ?? true)) return false;
// this should NEVER be null
const compData = components.value[x + "x" + y] as FactoryComponentProducer;
for (const [key, res] of Object.entries(compData.productionStock)) {
// if the current stock + production is more than you can handle
if (factoryBaseData.inputs !== undefined) {
for (const [res, val] of Object.entries(factoryBaseData.inputs))
if ((compData.inputStock?.[res] ?? 0) < val.amount) return false;
}
if (factoryBaseData.outputs !== undefined) {
for (const [res, val] of Object.entries(factoryBaseData.outputs))
if (
res + factoryBaseData.production[key] >
factoryBaseData.productionStock[key]
(compData.outputStock?.[res] ?? 0) + val.amount >
(val.capacity ?? Infinity)
)
return false;
}
for (const [key, res] of Object.entries(compData.consumptionStock)) {
// make sure you have enough to produce
if (res < factoryBaseData.consumptionStock[key]) return false;
}
return true;
}),
sprite
@ -681,7 +723,16 @@ const factory = createLayer(id, () => {
} else if (e.button === 2) {
const data = compInternalData[x + "x" + y];
if (data === undefined) return;
if (data.type === "conveyor") {
const cData = data as FactoryInternalConveyor;
for (const p of cData.packages) {
p.sprite.destroy();
}
}
delete components.value[x + "x" + y];
delete compInternalData[x + "x" + y];
spriteContainer.removeChild(data.sprite);
}
}
@ -746,24 +797,58 @@ const factory = createLayer(id, () => {
<br />
{compHovered.value.type !== "conveyor" ? (
<>
Stock:{" "}
{Object.entries({
...(compHovered.value.productionStock as Record<
string,
number
>),
...(compHovered.value.consumptionStock as Record<
string,
number
>)
}).map(i => {
return `${i[0]}: ${i[1]}/${
FACTORY_COMPONENTS[compHovered.value?.type ?? "cursor"]
.consumptionStock[i[0]] ??
FACTORY_COMPONENTS[compHovered.value?.type ?? "cursor"]
.productionStock[i[0]]
}`;
})}
{compHovered.value.inputStock !== undefined ? (
<>
<br />
<h5>Inputs:</h5>
{Object.entries(compHovered.value.inputStock).map(x => (
<div>
{x[0]}: {formatWhole(x[1])}
{FACTORY_COMPONENTS[
compHovered.value?.type ?? "cursor"
].inputs?.[x[0]].amount !== undefined
? " / " +
formatWhole(
FACTORY_COMPONENTS[
compHovered.value?.type ?? "cursor"
].inputs?.[x[0]].amount ?? 0
)
: ""}
{FACTORY_COMPONENTS[
compHovered.value?.type ?? "cursor"
].inputs?.[x[0]].capacity !== undefined
? " / " +
formatWhole(
FACTORY_COMPONENTS[
compHovered.value?.type ?? "cursor"
].inputs?.[x[0]].capacity ?? 0
)
: ""}
</div>
))}
</>
) : undefined}
{compHovered.value.outputStock !== undefined ? (
<>
<br />
<h5>Outputs:</h5>
{Object.entries(compHovered.value.outputStock).map(x => (
<div>
{x[0]}: {formatWhole(x[1])}
{FACTORY_COMPONENTS[
compHovered.value?.type ?? "cursor"
].outputs?.[x[0]].capacity !== undefined
? " / " +
formatWhole(
FACTORY_COMPONENTS[
compHovered.value?.type ?? "cursor"
].outputs?.[x[0]].capacity ?? 0
)
: ""}
</div>
))}
</>
) : undefined}
</>
) : undefined}
</div>

View file

@ -48,6 +48,7 @@ export type State =
| string
| number
| boolean
| undefined
| DecimalSource
| { [key: string]: State }
| { [key: number]: State };