diff --git a/src/data/layers/factory.tsx b/src/data/layers/factory.tsx index b20c6c7..96054b3 100644 --- a/src/data/layers/factory.tsx +++ b/src/data/layers/factory.tsx @@ -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 + outputs: { + square: { + amount: 1 + } + } + }, + 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 + } }, - productionStock: { - square: Infinity - }, - consumption: {}, - consumptionStock: {} + outputs: { + square: { + amount: 1, + capacity: 10 + } + } } - } as Record; + } as Record; const RESOURCES = { square: square } as Record; - type FactoryCompNames = keyof typeof FACTORY_COMPONENTS; + type FactoryCompNames = "cursor" | "rotate" | "conveyor" | "square" | "receiver" | "shrinker"; type BuildableCompName = Exclude; interface FactoryComponentBase extends Record { @@ -165,10 +181,10 @@ const factory = createLayer(id, () => { interface FactoryComponentProducer extends FactoryComponentBase { type: Exclude; - consumptionStock: Record; + inputStock?: Record; // current production stock - productionStock: Record; + outputStock?: Record; ticksDone: number; } @@ -186,13 +202,21 @@ const factory = createLayer(id, () => { description: string; /** amount it consumes */ - consumption: Record; - /** maximum stock of consumption */ - consumptionStock: Record; + inputs?: Record< + string, + { + amount: number; + capacity?: number; + } + >; /** amount it produces */ - production: Record; - /** maximum stock of production */ - productionStock: Record; + 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]++; + 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); } + + 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,55 +443,67 @@ const factory = createLayer(id, () => { // factory part // PRODUCTION if (data.ticksDone >= factoryData.tick) { - if (!compData.canProduce.value) continue; - 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 (compData.canProduce.value) { + const cyclesDone = Math.floor(data.ticksDone / factoryData.tick); + factoryData.onProduce?.(cyclesDone); + 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; + } + } + data.ticksDone -= cyclesDone * factoryData.tick; } - 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 (amt >= 1) { - itemToMove = [name, amt]; - data.productionStock[name]--; - break; + if (data.outputStock !== undefined) { + for (const [name, amt] of Object.entries(data.outputStock)) { + if (amt >= 1) { + itemToMove = [name, amt]; + data.outputStock[name]--; + break; + } } } // there is nothing to move @@ -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,17 +599,17 @@ 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 ( - res + factoryBaseData.production[key] > - factoryBaseData.productionStock[key] - ) - return false; + if (factoryBaseData.inputs !== undefined) { + for (const [res, val] of Object.entries(factoryBaseData.inputs)) + if ((compData.inputStock?.[res] ?? 0) < val.amount) 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; + if (factoryBaseData.outputs !== undefined) { + for (const [res, val] of Object.entries(factoryBaseData.outputs)) + if ( + (compData.outputStock?.[res] ?? 0) + val.amount > + (val.capacity ?? Infinity) + ) + return false; } return true; }), @@ -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, () => {
{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 ? ( + <> +
+
Inputs:
+ {Object.entries(compHovered.value.inputStock).map(x => ( +
+ {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 + ) + : ""} +
+ ))} + + ) : undefined} + {compHovered.value.outputStock !== undefined ? ( + <> +
+
Outputs:
+ {Object.entries(compHovered.value.outputStock).map(x => ( +
+ {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 + ) + : ""} +
+ ))} + + ) : undefined} ) : undefined} diff --git a/src/game/persistence.ts b/src/game/persistence.ts index 893d435..efb43c0 100644 --- a/src/game/persistence.ts +++ b/src/game/persistence.ts @@ -48,6 +48,7 @@ export type State = | string | number | boolean + | undefined | DecimalSource | { [key: string]: State } | { [key: number]: State };