diff --git a/src/data/layers/Factory.vue b/src/data/layers/Factory.vue index 476c243..3051f8e 100644 --- a/src/data/layers/Factory.vue +++ b/src/data/layers/Factory.vue @@ -4,7 +4,7 @@ diff --git a/src/data/layers/factory-components/square.jpg b/src/data/layers/factory-components/square.jpg new file mode 100644 index 0000000..f4d9a9d Binary files /dev/null and b/src/data/layers/factory-components/square.jpg differ diff --git a/src/data/layers/factory.tsx b/src/data/layers/factory.tsx index bb85b59..5e1a182 100644 --- a/src/data/layers/factory.tsx +++ b/src/data/layers/factory.tsx @@ -5,10 +5,10 @@ import { Sprite } from "@pixi/sprite"; import { Graphics } from "@pixi/graphics"; import { Assets } from "@pixi/assets"; import Factory from "./Factory.vue"; -import Modal from "components/Modal.vue"; import conveyor from "./factory-components/conveyor.png"; import cursor from "./factory-components/cursor.jpg"; -import { computed, reactive, Ref, ref, watchEffect } from "vue"; +import square from "./factory-components/square.jpg"; +import { computed, ComputedRef, reactive, Ref, ref, watchEffect } from "vue"; import { Direction } from "util/common"; import { persistent } from "game/persistence"; import player from "game/player"; @@ -23,11 +23,17 @@ const day = 20; // 20x20 block size // TODO: unhardcode stuff -const size = { + +enum FactoryDirections { + Any, + None +} +type FactoryDirection = FactoryDirections | Direction; +export const size = { width: 1000, - height: 340 + height: 345 }; -export const blockAmts = { +const blockAmts = { w: 50, h: 17 }; @@ -42,45 +48,110 @@ function getRelativeCoords(e: MouseEvent) { y: e.clientY - rect.top }; } - -interface FactoryComponent { - directionIn: Direction | undefined; - directionOut: Direction | undefined; - imageSrc: string; - name: string; - description: string; - type: string; - sprite: Sprite; +async function createSprite(name: string) { + const sheet = await Assets.load(name); + return new Sprite(sheet); +} + +async function positionSprite(name: string, y: number, x: number, width: number, height: number) { + const sprite = await createSprite(name); + sprite.width = width; + sprite.height = height; + sprite.y = y; + sprite.x = x; + return sprite; } -const FACTORY_COMPONENTS = { - cursor: { - directionIn: undefined, - directionOut: undefined, - imageSrc: cursor, - name: "Cursor", - description: "Use this to move." - }, - conveyor: { - directionIn: Direction, - directionOut: Direction, - imageSrc: conveyor, - name: "Conveyor", - description: "Moves 1 item per tick." - }, - someOtherComponent: { - directionIn: Direction.Down, - directionOut: undefined, - imageSrc: conveyor, - description: "Accepts anything and produces nothing." - } -}; -type FactoryCompNames = keyof typeof FACTORY_COMPONENTS; const factory = createLayer(id, () => { // layer display const name = "The Factory"; const color = "grey"; + const FACTORY_COMPONENTS = { + cursor: { + imageSrc: cursor, + name: "Cursor", + description: "Use this to move.", + tick: 0, + directionIn: FactoryDirections.None, + directionOut: FactoryDirections.None, + consumption: {}, + consumptionStock: {}, + production: {}, + productionStock: {} + }, + conveyor: { + directionIn: FactoryDirections.Any, + directionOut: FactoryDirections.Any, + imageSrc: conveyor, + name: "Conveyor", + description: "Moves 1 item per tick.", + tick: 1, + consumption: {}, + consumptionStock: {}, + production: {}, + productionStock: {} + }, + square: { + directionIn: FactoryDirections.Any, + directionOut: FactoryDirections.None, + imageSrc: square, + name: "???", + description: "Produces 1 square every 1 tick.", + tick: 1, + production: { + square: 1 + }, + productionStock: { + square: Infinity + }, + consumption: {}, + consumptionStock: {}, + onProduce(times) { + } + } + } as Record; + + type FactoryCompNames = keyof typeof FACTORY_COMPONENTS; + type BuildableCompName = Exclude; + + interface FactoryComponent { + type: BuildableCompName; + ticksDone: number; + // current consumption stock + consumptionStock: Record; + + // current production stock + productionStock: Record; + } + interface FactoryComponentDeclaration { + tick: number; + directionIn: FactoryDirection; + directionOut: FactoryDirection; + imageSrc: string; + name: string; + description: string; + + // amount it consumes + consumption: Record; + // maximum stock of consumption + consumptionStock: Record; + // amount it produces + production: Record; + // maximum stock of production + productionStock: Record; + + // on produce, do something + onProduce?: (times: number) => void; + // can it produce? (in addtion to the stock check) + canProduce?: ComputedRef; + } + + interface FactoryInternal { + sprite: Sprite; + canProduce: ComputedRef; + } + // mouse positions const mouseCoords = reactive({ x: 0, @@ -88,36 +159,124 @@ const factory = createLayer(id, () => { }); const isMouseHoverShown = ref(false); const whatIsHovered = ref(""); - const compSelected = ref(""); - const components: Ref = persistent( + const compSelected = ref("cursor"); + + const componentData: Ref<(FactoryComponent | null)[][]> = persistent( Array(blockAmts.h) .fill(undefined) - .map(() => Array(blockAmts.w).fill(undefined)) + .map(() => Array(blockAmts.w).fill(null)) ); + const components: (FactoryInternal | null)[][] = Array(blockAmts.h) + .fill(undefined) + .map(() => Array(blockAmts.w).fill(null)); + window.components = components; // pixi const app = new Application(size); const graphicContainer = new Graphics(); const spriteContainer = new Container(); - let blockWidth = 0; - let blockHeight = 0; - app.stage.addChild(graphicContainer, spriteContainer); + const movingBlocks = new Container(); + const blockWidth = ref(app.screen.width / blockAmts.w); + const blockHeight = ref(app.screen.height / blockAmts.h); - globalBus.on("update", () => { - blockWidth = app.screen.width / blockAmts.w; - blockHeight = app.screen.height / blockAmts.h; + graphicContainer.zIndex = 1; + app.stage.addChild(graphicContainer, spriteContainer, movingBlocks); + app.stage.sortableChildren = true; + + globalBus.on("update", diff => { + blockWidth.value = app.screen.width / blockAmts.w; + blockHeight.value = app.screen.height / blockAmts.h; + + // will change soon:tm: + const tick = diff; + for (const y of components.keys()) { + for (const x of components[y].keys()) { + const data = componentData.value[y][x]; + const compData = components[y][x]; + //console.log(compData, data) + if (data === null || compData === null) continue; + const factoryData = FACTORY_COMPONENTS[data.type]; + if (data.ticksDone >= factoryData.tick) { + console.log(compData.canProduce); + if (!compData.canProduce.value) continue; + const cyclesDone = Math.floor(data.ticksDone / factoryData.tick); + console.log("produce", data.ticksDone, factoryData.tick); + factoryData.onProduce?.(cyclesDone); + for (const [key, val] of Object.entries(factoryData.consumption)) { + data.consumptionStock[key] -= val; + } + for (const [key, val] of Object.entries(factoryData.production)) { + data.productionStock[key] -= val; + } + data.ticksDone -= cyclesDone * factoryData.tick; + } else { + data.ticksDone += tick; + } + } + } }); + globalBus.on("onLoad", async () => { + for (const y of componentData.value.keys()) { + for (const x of componentData.value[y].keys()) { + changeFactoryComponent(y, x); + } + } + }); + + async function changeFactoryComponent(y: number, x: number) { + const comp = componentData.value[y][x]; + if (comp === null) return; + const data = FACTORY_COMPONENTS[comp.type]; + const sprite = await positionSprite( + FACTORY_COMPONENTS[comp.type].imageSrc, + y * blockHeight.value, + x * blockWidth.value, + blockWidth.value, + blockHeight.value + ); + components[y][x] = { + sprite, + canProduce: computed(() => { + if (!(data.canProduce?.value ?? true)) return false; + for (const [key, res] of Object.entries(comp.productionStock)) { + // if the current stock + production is more than you can handle + if (res + data.production[key] > data.productionStock[key]) return false; + } + for (const [key, res] of Object.entries(comp.consumptionStock)) { + // make sure you have enough to produce + if (res < data.consumptionStock[key]) return false; + } + return true; + }) + }; + spriteContainer.addChild(sprite); + } + + function removeFactoryComponent(y: number, x: number) { + const comp = components[y][x]; + if (comp === null) return; + comp.sprite.destroy(); + componentData.value[y][x] = null; + components[y][x] = null; + spriteContainer.removeChild(comp.sprite); + } + // draw graphics function updateGraphics() { graphicContainer.clear(); - if (isMouseHoverShown.value) { - graphicContainer.beginFill(0x808080); + if (isMouseHoverShown.value && compSelected.value !== "cursor") { + const { x, y } = { + x: roundDownTo(mouseCoords.x, blockWidth.value) / blockWidth.value, + y: roundDownTo(mouseCoords.y, blockHeight.value) / blockHeight.value + }; + console.log(isMouseHoverShown.value, x, y); + graphicContainer.beginFill(components[y][x] !== null ? 0xff0000 : 0xffff00); graphicContainer.drawRect( - roundDownTo(mouseCoords.x, blockWidth), - roundDownTo(mouseCoords.y, blockHeight), - blockWidth, - blockHeight + roundDownTo(mouseCoords.x, blockWidth.value), + roundDownTo(mouseCoords.y, blockHeight.value), + blockWidth.value, + blockHeight.value ); } } @@ -131,24 +290,31 @@ const factory = createLayer(id, () => { mouseCoords.y = y; } async function onClick(e: MouseEvent) { - if (compSelected.value === "") { - console.warn("You haven't hovered over anything, trickster!"); - return; + const coords = getRelativeCoords(e); + const x = roundDownTo(coords.x, blockWidth.value) / blockWidth.value; + const y = roundDownTo(coords.y, blockHeight.value) / blockHeight.value; + if (e.button === 0) { + // you shouldn't be putting down a mouse + if (compSelected.value === "cursor") return; + // should not already be placed + if (components[y][x] !== null) return; + + const basicData = FACTORY_COMPONENTS[compSelected.value]; + componentData.value[y][x] = { + type: compSelected.value, + ticksDone: 0, + consumptionStock: Object.fromEntries( + Object.entries(basicData.consumptionStock).map(i => [i[0], 0]) + ), + productionStock: Object.fromEntries( + Object.entries(basicData.productionStock).map(i => [i[0], 0]) + ) + }; + await changeFactoryComponent(y, x); + } else if (e.button === 2) { + // right click + removeFactoryComponent(y, x); } - let { x, y } = getRelativeCoords(e); - x = roundDownTo(x, blockWidth) / blockWidth; - y = roundDownTo(y, blockHeight) / blockHeight; - const basicData = structuredClone( - FACTORY_COMPONENTS[compSelected.value] - ) as FactoryComponent; - basicData.type = compSelected.value; - const sheet = await Assets.load(basicData.imageSrc); - basicData.sprite = new Sprite(sheet); - basicData.sprite.x = x; - basicData.sprite.y = y; - basicData.sprite.width = blockWidth; - basicData.sprite.height = blockHeight; - spriteContainer.addChild(basicData.sprite); } function onMouseEnter() { isMouseHoverShown.value = true; @@ -160,6 +326,7 @@ const factory = createLayer(id, () => { player.tabs.splice(0, Infinity, "main"); } function onComponentHover(name: FactoryCompNames | "") { + if (compSelected.value !== "cursor") return; whatIsHovered.value = name; } function onCompClick(name: FactoryCompNames) { @@ -171,6 +338,7 @@ const factory = createLayer(id, () => { color, minWidth: 700, minimizable: false, + componentData, display: jsx(() => (
- + e.preventDefault()} /> - )), - components + )) }; }); export default factory; diff --git a/src/data/layers/styles/factory.css b/src/data/layers/styles/factory.css index a47a172..7300361 100644 --- a/src/data/layers/styles/factory.css +++ b/src/data/layers/styles/factory.css @@ -7,6 +7,7 @@ .factoryDisp { border-left: 1px solid white; border-bottom: 1px solid white; + border-right: 1px solid white; } .info { border-bottom: 1px solid white; diff --git a/src/util/save.ts b/src/util/save.ts index 8ddddad..2de5092 100644 --- a/src/util/save.ts +++ b/src/util/save.ts @@ -137,7 +137,8 @@ setInterval(() => { window.onbeforeunload = () => { if ( player.autosave && - (layers as any).main.days[(layers as any).main.day.value - 1].opened.value + ((layers as any).main.days[(layers as any).main.day.value - 1].opened.value || + import.meta.env.DEV) ) { save(); }