diff --git a/src/data/layers/factory.tsx b/src/data/layers/factory.tsx index 15668cd..617a099 100644 --- a/src/data/layers/factory.tsx +++ b/src/data/layers/factory.tsx @@ -40,6 +40,40 @@ function getRelativeCoords(e: MouseEvent) { y: e.clientY - rect.top }; } +function iterateDirection(dir: FactoryDirection, func: (dir: FactoryDirection) => void) { + switch (dir) { + case FactoryDirections.None: + return; + case FactoryDirections.Any: + func(Direction.Up); + func(Direction.Right); + func(Direction.Down); + func(Direction.Left); + break; + default: + func(dir); + } +} +function directionToNum(dir: Direction) { + switch (dir) { + case Direction.Left: + case Direction.Up: + return -1; + case Direction.Right: + case Direction.Down: + return 1; + } +} +function getDirection(dir: Direction) { + switch (dir) { + case Direction.Left: + case Direction.Right: + return "h"; + case Direction.Up: + case Direction.Down: + return "v"; + } +} const factorySize = { width: 50, @@ -58,16 +92,12 @@ const factory = createLayer(id, () => { 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.", @@ -78,8 +108,6 @@ const factory = createLayer(id, () => { productionStock: {} }, square: { - directionIn: FactoryDirections.Any, - directionOut: FactoryDirections.None, imageSrc: square, name: "???", description: "Produces 1 square every 1 tick.", @@ -97,20 +125,22 @@ const factory = createLayer(id, () => { type FactoryCompNames = keyof typeof FACTORY_COMPONENTS; type BuildableCompName = Exclude<FactoryCompNames, "cursor">; - - interface FactoryComponent { - type: BuildableCompName; - ticksDone: number; - // current consumption stock + interface FactoryComponentProducers { + type: Exclude<BuildableCompName, "conveyor">; consumptionStock: Record<string, number>; // current production stock productionStock: Record<string, number>; + ticksDone: number; } + interface FactoryComponentConveyor { + type: "conveyor"; + directionOut: Direction; + directionIn: Direction; + } + type FactoryComponent = FactoryComponentConveyor | FactoryComponentProducers; interface FactoryComponentDeclaration { tick: number; - directionIn: FactoryDirection; - directionOut: FactoryDirection; imageSrc: string; name: string; description: string; @@ -130,10 +160,32 @@ const factory = createLayer(id, () => { canProduce?: ComputedRef<boolean>; } - interface FactoryInternal { + interface FactoryInternalBase { sprite: Sprite; canProduce: ComputedRef<boolean>; } + interface FactoryInternalConveyor extends FactoryInternalBase { + type: "conveyor"; + + // packages are sorted by last first, first last + // [componentMade5SecondsAgo, componentMade4SecondsAgo...] + packages: Block[]; + nextPackages: Block[]; + } + interface FactoryInternalProducer extends FactoryInternalBase { + type: Exclude<BuildableCompName, "conveyor">; + } + type FactoryInternal = FactoryInternalConveyor | FactoryInternalProducer; + + interface Block { + sprite: Sprite; + type: string; + // in block amts, not screen + x: number; + y: number; + lastX: number; + lastY: number; + } // mouse positions const mouseCoords = reactive({ @@ -161,16 +213,32 @@ const factory = createLayer(id, () => { backgroundAlpha: 0 }); const graphicContainer = new Graphics(); - const spriteContainer = new Container(); + let spriteContainer = new Container(); const movingBlocks = new Container(); graphicContainer.zIndex = 1; app.stage.addChild(graphicContainer, spriteContainer, movingBlocks); app.stage.sortableChildren = true; - globalBus.on("update", diff => { + globalBus.on("onLoad", async () => { + spriteContainer.destroy({ + children: true + }); + spriteContainer = new Container(); + app.stage.addChild(spriteContainer); + for (const y of components.value.keys()) { + for (const x of components.value[y].keys()) { + const data = components.value[y][x]; + if (data === null) continue; + await addFactoryComp(x, y, data.type); + } + } + }); + + globalBus.on("update", async diff => { // will change soon:tm: const tick = diff; + // make them produce for (const y of components.value.keys()) { for (const x of components.value[y].keys()) { const data = components.value[y][x]; @@ -178,53 +246,185 @@ const factory = createLayer(id, () => { //console.log(compData, data) if (data === null || compData === null) continue; const factoryData = FACTORY_COMPONENTS[data.type]; - if (data.ticksDone >= factoryData.tick) { - 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; + + if (data.type === "conveyor") { + if (compData.type !== "conveyor") throw new TypeError("this should not happen"); + // conveyor part + // use a copy + for (const [key, block] of [...compData.packages].entries()) { + const dirType = getDirection(data.directionOut); + const dirAmt = directionToNum(data.directionOut); + if (dirType === "h") { + if (block.x <= block.lastX + dirAmt) { + // hit border + if ( + (dirAmt === -1 && x === 0) || + (dirAmt === 1 && x === components.value[y].length - 1) + ) + continue; + const compBehind = compInternalData[y][x + dirAmt]; + const storedComp = components.value[y][x + dirAmt]; + + // empty spot + if (compBehind === null) continue; + if (compBehind.type === "conveyor") { + const val = storedComp as FactoryComponentConveyor; + if ( + !( + data.directionOut === Direction.Left && + val.directionIn === Direction.Right + ) && + !( + data.directionOut === Direction.Right && + val.directionIn === Direction.Left + ) + ) { + // component next does not accept this + continue; + } + // push it to the next conveyor, kill it from the + // curent conveyor + compBehind.nextPackages.push(block); + compData.packages.splice(key, 1); + } else { + // send it to the factory + // destory its sprite and data + (storedComp as FactoryComponentProducers).consumptionStock[ + block.type + ]++; + block.sprite.destroy(); + movingBlocks.removeChild(block.sprite); + compData.packages.splice(key, 1); + } + } else { + block.x += tick * dirAmt; + block.sprite.x = block.x * blockSize; + } + } else { + if (block.y <= block.lastY + dirAmt) { + // hit border + if ( + (dirAmt === -1 && y === 0) || + (dirAmt === 1 && y === components.value.length - 1) + ) + continue; + const compBehind = compInternalData[y + dirAmt][x]; + const storedComp = components.value[y + dirAmt][x]; + + // empty spot + if (compBehind === null) continue; + if (compBehind.type === "conveyor") { + const val = storedComp as FactoryComponentConveyor; + if ( + !( + data.directionOut === Direction.Up && + val.directionIn === Direction.Down + ) && + !( + data.directionOut === Direction.Down && + val.directionIn === Direction.Up + ) + ) { + // component next does not accept this + continue; + } + // push it to the next conveyor, kill it from the + // curent conveyor + compBehind.nextPackages.push(block); + compData.packages.splice(key, 1); + } else { + // send it to the factory + // destory its sprite and data + const factoryData = storedComp as FactoryComponentProducers; + factoryData.consumptionStock[block.type]++; + block.sprite.destroy(); + movingBlocks.removeChild(block.sprite); + compData.packages.splice(key, 1); + } + } else { + block.y += tick * dirAmt; + block.sprite.y = block.y * blockSize; + } + } } - for (const [key, val] of Object.entries(factoryData.production)) { - data.productionStock[key] -= val; - } - data.ticksDone -= cyclesDone * factoryData.tick; } else { - data.ticksDone += tick; + // 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; + } + for (const [key, val] of Object.entries(factoryData.production)) { + data.productionStock[key] -= val; + } + data.ticksDone -= cyclesDone * factoryData.tick; + } else { + data.ticksDone += tick; + } + // now look at each component direction and see if it accepts items coming in + // components are 1x1 so simple math for now + if ( + y < components.value.length - 1 && + components.value[y + 1][x]?.type === "conveyor" + ) { + const val = components.value[y + 1][x] as FactoryComponentConveyor; + // todo: give this a predefined order + } } } } }); - /*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, + async function addFactoryComp(x: number, y: number, type: BuildableCompName) { + const factoryBaseData = FACTORY_COMPONENTS[compSelected.value]; + const sheet = await Assets.load(factoryBaseData.imageSrc); + const sprite = new Sprite(sheet); + + sprite.x = x * blockSize; + sprite.y = y * blockSize; + sprite.width = blockSize; + sprite.height = blockSize; + components.value[y][x] = { + type, + ticksDone: 0, + directionIn: type === "conveyor" ? Direction.Right : undefined, + directionOut: type === "conveyor" ? Direction.Left : undefined, + consumptionStock: + type === "conveyor" ? undefined : structuredClone(factoryBaseData.consumptionStock), + productionStock: + type === "conveyor" ? undefined : structuredClone(factoryBaseData.productionStock) + } as FactoryComponent; + const isConveyor = compSelected.value === "conveyor"; + compInternalData[y][x] = { + type, + packages: isConveyor ? [] : undefined, + nextPackages: isConveyor ? [] : undefined, canProduce: computed(() => { - if (!(data.canProduce?.value ?? true)) return false; - for (const [key, res] of Object.entries(comp.productionStock)) { + if (type === "conveyor") return true; + if (!(factoryBaseData.canProduce?.value ?? true)) return false; + // this should NEVER be null + const compData = components.value[y][x] as FactoryComponentProducers; + for (const [key, res] of Object.entries(compData.productionStock)) { // if the current stock + production is more than you can handle - if (res + data.production[key] > data.productionStock[key]) return false; + if ( + res + factoryBaseData.production[key] > + factoryBaseData.productionStock[key] + ) + return false; } - for (const [key, res] of Object.entries(comp.consumptionStock)) { + for (const [key, res] of Object.entries(compData.consumptionStock)) { // make sure you have enough to produce - if (res < data.consumptionStock[key]) return false; + if (res < factoryBaseData.consumptionStock[key]) return false; } return true; - }) - }; + }), + sprite + } as FactoryInternal; spriteContainer.addChild(sprite); - }*/ + } // draw graphics function updateGraphics() { @@ -234,7 +434,7 @@ const factory = createLayer(id, () => { spriteContainer.x = mapOffset.x * blockSize + app.view.width / 2; spriteContainer.y = mapOffset.y * blockSize + app.view.height / 2; - if (isMouseHoverShown.value && compSelected.value === "cursor") { + if (isMouseHoverShown.value && compSelected.value !== "cursor") { const { tx, ty } = spriteContainer.localTransform; graphicContainer.beginFill(0x808080); graphicContainer.drawRect( @@ -272,49 +472,23 @@ const factory = createLayer(id, () => { async function onFactoryPointerUp(e: PointerEvent) { // make sure they're not dragging and that // they aren't trying to put down a cursor - if (!pointerDrag.value && compSelected.value !== "cursor") { + if (!pointerDrag.value) { const { tx, ty } = spriteContainer.localTransform; let { x, y } = getRelativeCoords(e); x = roundDownTo(x - tx, blockSize) / blockSize; y = roundDownTo(y - ty, blockSize) / blockSize; - const factoryBaseData = FACTORY_COMPONENTS[compSelected.value]; - const sheet = await Assets.load(factoryBaseData.imageSrc); - const sprite = new Sprite(sheet); - - console.log(x, y); - - sprite.x = x * blockSize; - sprite.y = y * blockSize; - sprite.width = blockSize; - sprite.height = blockSize; - components.value[y][x] = { - type: compSelected.value, - ticksDone: 0, - consumptionStock: structuredClone(factoryBaseData.consumptionStock), - productionStock: structuredClone(factoryBaseData.productionStock) - }; - compInternalData[y][x] = { - canProduce: computed(() => { - if (!(factoryBaseData.canProduce?.value ?? true)) return false; - // this should NEVER be null - const compData = components.value[y][x] as FactoryComponent; - 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; - } - 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 - }; - spriteContainer.addChild(sprite); + if (e.button === 0) { + if (compSelected.value !== "cursor") { + await addFactoryComp(x, y, compSelected.value); + } + } else if (e.button === 2) { + const data = compInternalData[y][x]; + if (data === null) return; + components.value[y][x] = null; + compInternalData[y][x] = null; + data.sprite.destroy(); + spriteContainer.removeChild(data.sprite); + } } window.removeEventListener("pointerup", onFactoryPointerUp); @@ -356,6 +530,7 @@ const factory = createLayer(id, () => { onPointerdown={onFactoryPointerDown} onPointerenter={onFactoryMouseEnter} onPointerleave={onFactoryMouseLeave} + onContextmenu={(e: MouseEvent) => e.preventDefault()} /> <div cellspacing="0" cellpadding="0" border="0" class="container"> <div style="line-height: 2.5em; min-height: 2.5em">