From a5cd6cd8a575eb078d6ae7e9f8a51f6df42ec92f Mon Sep 17 00:00:00 2001 From: Stephanie Gredell Date: Tue, 23 Dec 2025 18:33:29 -0800 Subject: [PATCH] add cost per cup --- game.js | 30 +++++++++++++++++++++++++++++- index.html | 22 ++++++++++++++++++++++ index.js | 34 ++++++++++++++++++++++++++++++++-- style.css | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 3 deletions(-) diff --git a/game.js b/game.js index a7f63a2..62f7967 100644 --- a/game.js +++ b/game.js @@ -170,6 +170,7 @@ const WeatherChance = [ * cups: PriceTable * }} supplies_prices * @property {number} cups_sold + * @property {number} cost_per_cup */ /** @@ -217,7 +218,8 @@ export function init_game() { 400: 3.75 } }, - cups_sold: 0 + cups_sold: 0, + cost_per_cup: 0 } } @@ -412,3 +414,29 @@ export function make_lemonade(game_state) { cups_sold } } + +/** + * Calculate the cost to produce one cup of lemonade based on the recipe. + * Uses the base tier pricing for each ingredient. + * @param {Object} recipe - The recipe with lemons, sugar, ice amounts + * @returns {number} The cost to make one cup + */ +export function calculate_cost_per_cup(game_state, recipe) { + const basePrices = { + lemons: SupplyPricing.lemons[0].price, + sugar: SupplyPricing.sugar[0].price, + ice: SupplyPricing.ice[0].price, + cup: SupplyPricing.cups[0].price + }; + + const cost = + (recipe.lemons * basePrices.lemons) + + (recipe.sugar * basePrices.sugar) + + (recipe.ice * basePrices.ice) + + basePrices.cup; + + return { + ...game_state, + cost_per_cup: Math.round(cost * 100) / 100 + } +} diff --git a/index.html b/index.html index 90d1c3e..065cd8f 100644 --- a/index.html +++ b/index.html @@ -166,6 +166,28 @@ +
+
+ Lemons + $0.00 +
+
+ Sugar + $0.00 +
+
+ Ice + $0.00 +
+
+ Cup + $0.01 +
+
+ Total per cup + $0.00 +
+
diff --git a/index.js b/index.js index f02a5d0..673fbcf 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,7 @@ * Initializes game state, wires up UI events, and coordinates modules. */ -import { init_game, set_price_per_cup, calculate_supply_cost } from './game.js'; +import { init_game, set_price_per_cup, calculate_supply_cost, calculate_cost_per_cup } from './game.js'; import { sprites, cups, render, whenSpritesReady } from './canvasController.js'; import { createReactiveState, updateBindings } from './binding.js'; @@ -130,12 +130,40 @@ if (changePriceBtn) { } // Recipe modal handlers +const recipeInputs = document.querySelectorAll('.recipe_input'); +const recipeCostValue = document.querySelector('.recipe_cost_value'); + +// Base prices for cost breakdown (matches SupplyPricing tier 1 in game.js) +const basePrices = { lemons: 0.02, sugar: 0.01, ice: 0.01, cup: 0.01 }; + +function updateRecipeCost() { + const lemons = parseInt(document.querySelector('.recipe_input[data-recipe="lemons"]').value) || 0; + const sugar = parseInt(document.querySelector('.recipe_input[data-recipe="sugar"]').value) || 0; + const ice = parseInt(document.querySelector('.recipe_input[data-recipe="ice"]').value) || 0; + + // Update breakdown rows + document.querySelector('.recipe_cost_item[data-cost="lemons"]').textContent = '$' + (lemons * basePrices.lemons).toFixed(2); + document.querySelector('.recipe_cost_item[data-cost="sugar"]').textContent = '$' + (sugar * basePrices.sugar).toFixed(2); + document.querySelector('.recipe_cost_item[data-cost="ice"]').textContent = '$' + (ice * basePrices.ice).toFixed(2); + document.querySelector('.recipe_cost_item[data-cost="cup"]').textContent = '$' + basePrices.cup.toFixed(2); + + // Update total + const result = calculate_cost_per_cup(gameState, { lemons, sugar, ice }); + recipeCostValue.textContent = '$' + result.cost_per_cup.toFixed(2); +} + +// Update cost when recipe inputs change +recipeInputs.forEach(input => { + input.addEventListener('input', updateRecipeCost); +}); + if (changeRecipeBtn) { changeRecipeBtn.addEventListener('click', () => { // Set inputs to current recipe values document.querySelector('.recipe_input[data-recipe="lemons"]').value = gameState.recipe.lemons; document.querySelector('.recipe_input[data-recipe="sugar"]').value = gameState.recipe.sugar; document.querySelector('.recipe_input[data-recipe="ice"]').value = gameState.recipe.ice; + updateRecipeCost(); recipeModal.classList.add('open'); }); @@ -148,8 +176,10 @@ if (changeRecipeBtn) { const sugar = parseInt(document.querySelector('.recipe_input[data-recipe="sugar"]').value) || 0; const ice = parseInt(document.querySelector('.recipe_input[data-recipe="ice"]').value) || 0; + const result = calculate_cost_per_cup(gameState, { lemons, sugar, ice }); setState({ - recipe: { lemons, sugar, ice } + recipe: { lemons, sugar, ice }, + cost_per_cup: result.cost_per_cup }); recipeModal.classList.remove('open'); }); diff --git a/style.css b/style.css index 4da1f2a..afa4509 100644 --- a/style.css +++ b/style.css @@ -674,6 +674,45 @@ canvas { text-align: center; } +.recipe_cost_breakdown { + background: rgba(255, 255, 255, 0.6); + padding: 12px 16px; + border-radius: 10px; + margin: 16px 0; +} + +.recipe_cost_row { + display: flex; + justify-content: space-between; + align-items: center; + font-family: 'Inter', sans-serif; + font-size: 13px; + color: #7A6146; + padding: 4px 0; +} + +.recipe_cost_row.total { + border-top: 1px solid #d4c9b8; + margin-top: 8px; + padding-top: 10px; + font-family: 'Fredoka', sans-serif; + font-size: 15px; + font-weight: 600; + color: #5C4632; +} + +.recipe_cost_item { + font-family: 'Inter', sans-serif; + font-weight: 500; +} + +.recipe_cost_value { + font-family: 'Fredoka', sans-serif; + font-size: 18px; + font-weight: 600; + color: #3f7a33; +} + .recipe_save_btn { font-family: 'Fredoka', sans-serif; font-size: 16px;