From 25cdd5493e9b2ad51f5c9e388c6a2d3510ff64ae Mon Sep 17 00:00:00 2001 From: Majid-Shahani Date: Thu, 28 May 2026 17:43:15 +0300 Subject: [PATCH 1/7] Change difficulty to be based on essence --- src/audio/audioManager.js | 2 - src/data/gameData.js | 84 +++++++++++++++++++-------------------- src/entities/station.js | 17 +------- 3 files changed, 44 insertions(+), 59 deletions(-) diff --git a/src/audio/audioManager.js b/src/audio/audioManager.js index 9733192..0d1fca7 100644 --- a/src/audio/audioManager.js +++ b/src/audio/audioManager.js @@ -37,8 +37,6 @@ export function playMusic(name) { activeMusic.loop = true; activeMusic.play().catch(() => {}); - - console.log("Music Playing!"); } export function stopMusic() { diff --git a/src/data/gameData.js b/src/data/gameData.js index 61844f4..10e990b 100644 --- a/src/data/gameData.js +++ b/src/data/gameData.js @@ -2,48 +2,53 @@ import { resetGameplayMusic, updateGameplayMusic, } from "../audio/audioManager.js"; -import { emit } from "../core/gameEvents.js"; +import { on, emit } from "../core/gameEvents.js"; const gameData = { essence: 0, heat: 1, }; -let heatListeners = []; -function attachHeatListener(observer) { - if (heatListeners.includes(observer)) return false; - - heatListeners.push(observer); - return true; -} -function detachHeatListener(observer) { - const index = heatListeners.indexOf(observer); - if (index === -1) return false; - - heatListeners.splice(index, 1); - return true; -} - -function callHeatListeners() { - heatListeners.forEach((observer) => observer(gameData.heat)); -} +const difficulty = [ + { + requiredEssence: 0, + }, + { + requiredEssence: 100, + }, + { + requiredEssence: 300, + }, + { + requiredEssence: 600, + }, + { + requiredEssence: 900, + }, + { + requiredEssence: 1200, + }, +]; function increaseHeat() { - if (gameData.heat >= defaultState.maxHeat) return; + if (gameData.heat >= difficulty.length) return; gameData.heat++; updateGameplayMusic(gameData.heat); - callHeatListeners(); + emit("heatUp", gameData.heat); } const activeOrders = []; -function makeDelivery() { - gameData.essence += 25; +on("delivered", (orderIndex) => { currentState.ordersFullfilled++; - if (currentState.ordersFullfilled >= currentState.nextHeat) { - increaseHeat(); - } -} + + const order = activeOrders[orderIndex]; + gameData.essence += + 15 + Math.ceil(100 * (order.timeRemaining / order.maxTime)); + + if (gameData.essence >= currentState.nextHeat) increaseHeat(); + activeOrders.splice(orderIndex, 1); +}); function addOrder(recipe) { if (activeOrders.length > 2) return; @@ -60,9 +65,8 @@ function addOrder(recipe) { const defaultState = Object.freeze({ baseTime: 15000, // in ms - maxHeat: 6, - orderAdditionRatio: 12, - orderDurationRatio: 6, + orderAdditionRatio: 10, + orderDurationRatio: 8, cookRatio: 3, stationRatio: 2 / 3, }); @@ -80,26 +84,22 @@ function resetState() { gameData.heat = 1; currentState.ordersFullfilled = 0; resetGameplayMusic(); - - heatListeners.length = 0; - attachHeatListener((heatLevel) => { - currentState.nextHeat += heatLevel + 1; - currentState.baseTime = defaultState.baseTime / (2 + heatLevel); - currentState.timeToNextOrder = - defaultState.orderAdditionRatio * currentState.baseTime; - }); - callHeatListeners(); + emit("heatUp", 1); } +on("heatUp", (heatLevel) => { + currentState.nextHeat = difficulty[heatLevel].requiredEssence; + currentState.baseTime = defaultState.baseTime / (2 + heatLevel); + currentState.timeToNextOrder = + defaultState.orderAdditionRatio * currentState.baseTime; +}); + export { gameData, activeOrders, addOrder, - makeDelivery, defaultState, currentState, resetState, - attachHeatListener, - detachHeatListener, increaseHeat, }; diff --git a/src/entities/station.js b/src/entities/station.js index 568a0d3..b9e12fd 100644 --- a/src/entities/station.js +++ b/src/entities/station.js @@ -3,16 +3,9 @@ import { VARIATION_COUNT, BREW, OVERBREWED, - getRandomRecipe, hasRecipe, } from "../data/items.js"; -import { - gameData, - defaultState, - activeOrders, - addOrder, - makeDelivery, -} from "../data/gameData.js"; +import { gameData, defaultState, activeOrders } from "../data/gameData.js"; import { emit } from "../core/gameEvents.js"; import { CUT } from "../data/items.js"; @@ -103,16 +96,10 @@ class DeliveryStation { ); if (orderIndex !== -1) { - emit("delivered"); - activeOrders.splice(orderIndex, 1); - makeDelivery(); + emit("delivered", orderIndex); } else { gameData.essence++; } - if (activeOrders.length === 0) { - addOrder(getRandomRecipe()); - } - playerInv.glass = 0; }; From 6d94068c604742a5f695fb3c329c4c2bef104d34 Mon Sep 17 00:00:00 2001 From: Majid-Shahani Date: Thu, 28 May 2026 17:52:38 +0300 Subject: [PATCH 2/7] Add time bonus to orders on delivery --- src/data/gameData.js | 35 ++++++++++++++++++++++++++++++++--- src/logic/update.js | 22 +++++----------------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/data/gameData.js b/src/data/gameData.js index 10e990b..ecd6002 100644 --- a/src/data/gameData.js +++ b/src/data/gameData.js @@ -42,12 +42,25 @@ const activeOrders = []; on("delivered", (orderIndex) => { currentState.ordersFullfilled++; - const order = activeOrders[orderIndex]; - gameData.essence += - 15 + Math.ceil(100 * (order.timeRemaining / order.maxTime)); + const ratio = + activeOrders[orderIndex].timeRemaining / activeOrders[orderIndex].maxTime; + if (ratio >= 0.23) { + gameData.essence += 15 + Math.ceil(100 * ratio); + } else { + gameData.essence += 25; + } if (gameData.essence >= currentState.nextHeat) increaseHeat(); activeOrders.splice(orderIndex, 1); + + if (ratio >= 0.5) { + for (const order of activeOrders) { + Math.min( + order.maxTime, + order.timeRemaining + (ratio / 2) * order.maxTime + ); + } + } }); function addOrder(recipe) { @@ -63,6 +76,21 @@ function addOrder(recipe) { emit("new_order"); } +function progressOrders(timeStep) { + let timedOutPots = 0; + for (let i = activeOrders.length - 1; i >= 0; i--) { + const order = activeOrders[i]; + + order.timeRemaining -= timeStep; + if (order.timeRemaining <= 0) { + timedOutPots++; + activeOrders.splice(i, 1); + } + } + + return timedOutPots; +} + const defaultState = Object.freeze({ baseTime: 15000, // in ms orderAdditionRatio: 10, @@ -98,6 +126,7 @@ export { gameData, activeOrders, addOrder, + progressOrders, defaultState, currentState, resetState, diff --git a/src/logic/update.js b/src/logic/update.js index b7b4c5f..47cae11 100644 --- a/src/logic/update.js +++ b/src/logic/update.js @@ -14,6 +14,7 @@ import { takePlace, work } from "./actions.js"; import { GAME_STATES, setGameState } from "../core/gameState.js"; import { activeOrders, + progressOrders, defaultState, currentState, resetState, @@ -120,22 +121,6 @@ function calculatePosition(timeStep) { } } -function progressOrders(timeStep) { - for (let i = activeOrders.length - 1; i >= 0; i--) { - const order = activeOrders[i]; - - order.timeRemaining -= timeStep; - if (order.timeRemaining <= 0) { - activeOrders.splice(i, 1); - - player.lives--; - if (player.lives <= 0) { - setGameState(GAME_STATES.GAME_OVER); - } - } - } -} - function update(timeStep) { // UPDATE STATIONS for (let st of stations) { @@ -143,7 +128,10 @@ function update(timeStep) { } // UPDATE ORDERS - progressOrders(timeStep); + player.lives -= progressOrders(timeStep); + if (player.lives <= 0) { + setGameState(GAME_STATES.GAME_OVER); + } currentState.timeToNextOrder -= timeStep; if (currentState.timeToNextOrder < 0) { From a1d7bdb2d131ce1c13314dd78e25c696294a0164 Mon Sep 17 00:00:00 2001 From: Majid-Shahani Date: Thu, 28 May 2026 19:03:02 +0300 Subject: [PATCH 3/7] Change audio manager callback to use events --- src/audio/audioManager.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/audio/audioManager.js b/src/audio/audioManager.js index 0d1fca7..f7217e1 100644 --- a/src/audio/audioManager.js +++ b/src/audio/audioManager.js @@ -1,6 +1,7 @@ import sounds from "./sound.js"; import music from "./music.js"; import settings from "../data/settings.js"; +import { on } from "../core/gameEvents.js"; let activeMusic = null; @@ -53,13 +54,13 @@ export function stopMusic() { let currentPhase = "low"; -export function updateGameplayMusic(heat) { +on("heatUp", (heat) => { if (heat >= 2 && currentPhase === "low") { currentPhase = "high"; playMusic("high"); } -} +}); export function isGameplayMusicPlaying() { return activeMusicName === "low" || activeMusicName === "high"; From 083e4b82caf5b301df19a2f18b37be0800cfd3de Mon Sep 17 00:00:00 2001 From: Majid-Shahani Date: Thu, 28 May 2026 19:58:33 +0300 Subject: [PATCH 4/7] Change intense music to play at heat 4 --- src/audio/audioManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/audioManager.js b/src/audio/audioManager.js index f7217e1..758df6e 100644 --- a/src/audio/audioManager.js +++ b/src/audio/audioManager.js @@ -55,7 +55,7 @@ export function stopMusic() { let currentPhase = "low"; on("heatUp", (heat) => { - if (heat >= 2 && currentPhase === "low") { + if (heat >= 4 && currentPhase === "low") { currentPhase = "high"; playMusic("high"); From 9cc4489d6dd0eec3b12cdf3c8865e86c95bf60e2 Mon Sep 17 00:00:00 2001 From: Majid-Shahani Date: Thu, 28 May 2026 20:00:39 +0300 Subject: [PATCH 5/7] Add dynamic difficulty, Refactor order reset time, Adjust Heat --- src/data/gameData.js | 114 ++++++++++++++++++++++++++++++++++--------- src/logic/update.js | 3 -- 2 files changed, 91 insertions(+), 26 deletions(-) diff --git a/src/data/gameData.js b/src/data/gameData.js index ecd6002..23ce83e 100644 --- a/src/data/gameData.js +++ b/src/data/gameData.js @@ -1,15 +1,13 @@ -import { - resetGameplayMusic, - updateGameplayMusic, -} from "../audio/audioManager.js"; +import { resetGameplayMusic } from "../audio/audioManager.js"; import { on, emit } from "../core/gameEvents.js"; +import { getRandomRecipe } from "./items.js"; const gameData = { essence: 0, heat: 1, }; -const difficulty = [ +const difficultyLevels = [ { requiredEssence: 0, }, @@ -30,10 +28,59 @@ const difficulty = [ }, ]; +const dynamicDifficulty = { + scale: 1, + performance: 0, +}; + +let lastDelivery = performance.now(); +function adjustDynamicDifficulty(orderIndex, ratio) { + if (currentState.ordersFullfilled === 1) { + lastDelivery = performance.now(); + activeOrders.splice(orderIndex, 1); + return; + } + const now = performance.now(); + const sinceLastRatio = + (now - lastDelivery) / + (currentState.baseTime * currentState.timeToNextOrder); + lastDelivery = now; + + let performanceDelta = 0; + + // consistency + if (sinceLastRatio < 0.4) performanceDelta += 14; + else if (sinceLastRatio < 0.8) performanceDelta += 8; + else if (sinceLastRatio < 1.2) performanceDelta += 2; + else if (sinceLastRatio < 1.6) performanceDelta -= 5; + else performanceDelta -= 12; + + // delivery quality + if (ratio > 0.7) performanceDelta += 10; + else if (ratio > 0.45) performanceDelta += 5; + else if (ratio > 0.3) performanceDelta += 0; + else if (ratio > 0.1) performanceDelta -= 6; + else performanceDelta -= 12; + + if (activeOrders.length <= 2) performanceDelta *= 1.1; + else if (activeOrders.length <= 1) performanceDelta *= 1.2; + + dynamicDifficulty.performance *= 0.9; + dynamicDifficulty.performance += performanceDelta; + dynamicDifficulty.performance = Math.max( + -100, + Math.min(100, dynamicDifficulty.performance) + ); + dynamicDifficulty.scale = 1 + dynamicDifficulty.performance * 0.0025; + dynamicDifficulty.scale = Math.max( + 0.85, + Math.min(1.25, dynamicDifficulty.scale) + ); +} + function increaseHeat() { - if (gameData.heat >= difficulty.length) return; + if (gameData.heat >= difficultyLevels.length) return; gameData.heat++; - updateGameplayMusic(gameData.heat); emit("heatUp", gameData.heat); } @@ -44,22 +91,25 @@ on("delivered", (orderIndex) => { const ratio = activeOrders[orderIndex].timeRemaining / activeOrders[orderIndex].maxTime; - if (ratio >= 0.23) { + if (ratio >= 0.48) { gameData.essence += 15 + Math.ceil(100 * ratio); } else { - gameData.essence += 25; + gameData.essence += 25 + Math.ceil(50 * ratio); } if (gameData.essence >= currentState.nextHeat) increaseHeat(); + + adjustDynamicDifficulty(orderIndex, ratio); activeOrders.splice(orderIndex, 1); + for (const order of activeOrders) { + order.timeRemaining = Math.min( + order.maxTime, + order.timeRemaining + (ratio / 3) * order.maxTime + ); + } - if (ratio >= 0.5) { - for (const order of activeOrders) { - Math.min( - order.maxTime, - order.timeRemaining + (ratio / 2) * order.maxTime - ); - } + if (activeOrders.length === 0 && ratio > 0.6) { + addOrder(getRandomRecipe()); } }); @@ -69,11 +119,17 @@ function addOrder(recipe) { activeOrders.push({ recipe: recipe.recipe, timeRemaining: - currentState.baseTime * defaultState.orderDurationRatio * recipe.count, + (currentState.baseTime * defaultState.orderDurationRatio * recipe.count) / + dynamicDifficulty.scale, maxTime: - currentState.baseTime * defaultState.orderDurationRatio * recipe.count, + (currentState.baseTime * defaultState.orderDurationRatio * recipe.count) / + dynamicDifficulty.scale, }); emit("new_order"); + + currentState.timeToNextOrder = + (defaultState.orderAdditionRatio * currentState.baseTime) / + dynamicDifficulty.scale; } function progressOrders(timeStep) { @@ -84,15 +140,21 @@ function progressOrders(timeStep) { order.timeRemaining -= timeStep; if (order.timeRemaining <= 0) { timedOutPots++; + dynamicDifficulty.performance -= 10; activeOrders.splice(i, 1); } } + dynamicDifficulty.scale = 1 + dynamicDifficulty.performance * 0.0025; + dynamicDifficulty.scale = Math.max( + 0.85, + Math.min(1.25, dynamicDifficulty.scale) + ); return timedOutPots; } const defaultState = Object.freeze({ - baseTime: 15000, // in ms + baseTime: 10000, // in ms orderAdditionRatio: 10, orderDurationRatio: 8, cookRatio: 3, @@ -108,18 +170,25 @@ const currentState = { }; function resetState() { + lastDelivery = performance.now(); + gameData.essence = 0; gameData.heat = 1; + currentState.ordersFullfilled = 0; + dynamicDifficulty.scale = 1; + dynamicDifficulty.performance = 0; + resetGameplayMusic(); emit("heatUp", 1); } on("heatUp", (heatLevel) => { - currentState.nextHeat = difficulty[heatLevel].requiredEssence; - currentState.baseTime = defaultState.baseTime / (2 + heatLevel); + currentState.nextHeat = difficultyLevels[heatLevel].requiredEssence; + currentState.baseTime = defaultState.baseTime / (1 + heatLevel * 0.55); currentState.timeToNextOrder = - defaultState.orderAdditionRatio * currentState.baseTime; + (defaultState.orderAdditionRatio * currentState.baseTime) / + dynamicDifficulty.scale; }); export { @@ -130,5 +199,4 @@ export { defaultState, currentState, resetState, - increaseHeat, }; diff --git a/src/logic/update.js b/src/logic/update.js index 47cae11..14bd1f7 100644 --- a/src/logic/update.js +++ b/src/logic/update.js @@ -15,7 +15,6 @@ import { GAME_STATES, setGameState } from "../core/gameState.js"; import { activeOrders, progressOrders, - defaultState, currentState, resetState, addOrder, @@ -135,8 +134,6 @@ function update(timeStep) { currentState.timeToNextOrder -= timeStep; if (currentState.timeToNextOrder < 0) { - currentState.timeToNextOrder = - currentState.baseTime * defaultState.orderAdditionRatio; addOrder(getRandomRecipe()); } From 0e1005a8bf42b094653cc74288d32c82a0635902 Mon Sep 17 00:00:00 2001 From: Mohammadmahdi Mohammadinia Date: Thu, 28 May 2026 20:16:18 +0300 Subject: [PATCH 6/7] Play Idle animation when working --- src/logic/update.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/logic/update.js b/src/logic/update.js index 14bd1f7..1862a82 100644 --- a/src/logic/update.js +++ b/src/logic/update.js @@ -151,6 +151,10 @@ function update(timeStep) { if (justPressed["f"]) { const active = getActiveInteractable(stations); if (active) currentInteraction = work(active, currentState.baseTime); + if (currentInteraction) { + player.velocityX = 0; + player.velocityY = 0; + } } } else { if (!currentInteraction._work_lock) currentInteraction = null; From c722b0bea410f99ddff26dd0d15ac0d1dd668f3f Mon Sep 17 00:00:00 2001 From: Mohammadmahdi Mohammadinia Date: Thu, 28 May 2026 20:17:51 +0300 Subject: [PATCH 7/7] Reduce base time --- src/data/gameData.js | 2 +- src/data/settings.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/gameData.js b/src/data/gameData.js index 23ce83e..e7d89a4 100644 --- a/src/data/gameData.js +++ b/src/data/gameData.js @@ -154,7 +154,7 @@ function progressOrders(timeStep) { } const defaultState = Object.freeze({ - baseTime: 10000, // in ms + baseTime: 9000, // in ms orderAdditionRatio: 10, orderDurationRatio: 8, cookRatio: 3, diff --git a/src/data/settings.js b/src/data/settings.js index 2a279e9..77ae4c6 100644 --- a/src/data/settings.js +++ b/src/data/settings.js @@ -1,5 +1,5 @@ const settings = { - musicVolume: 0.4, + musicVolume: 0.2, sfxVolume: 0.5, };