/** * BAKERY SHOP SYSTEM - Food & Gift Purchasing * Part of: New Town Buildings * Created: January 4, 2026 * * Features: * - Food shop with fresh baked goods * - Gift system (best gifts for NPCs) * - Bulk purchase discounts * - Time-of-day inventory changes * - Special events (baking competition, birthday cakes) */ class BakeryShopSystem { constructor(game) { this.game = game; this.player = game.player; // Bakery status this.isUnlocked = false; this.isOpen = false; this.baker = null; // Shop inventory this.inventory = this.initializeInventory(); // Special events this.currentEvent = null; this.lastBakingCompetition = null; // Birthday cake orders this.birthdayCakeOrders = []; } /** * Initialize bakery inventory */ initializeInventory() { return { fresh_bread: { id: 'fresh_bread', name: 'Fresh Bread', price: 50, energyRestore: 20, giftValue: 1, // +1 heart stock: 20, restockTime: 'morning', // Restocks at 6 AM description: 'Warm, freshly baked bread.', favoredBy: ['all'] // Everyone likes bread! }, cake: { id: 'cake', name: 'Cake', price: 200, energyRestore: 50, giftValue: 5, // +5 hearts stock: 5, restockTime: 'afternoon', // Restocks at 2 PM description: 'A beautiful layered cake.', favoredBy: ['ana', 'kai', 'gronk', 'children'] }, pie: { id: 'pie', name: 'Fruit Pie', price: 150, energyRestore: 40, giftValue: 3, // +3 hearts stock: 8, restockTime: 'morning', description: 'Sweet fruit pie with flaky crust.', favoredBy: ['ana', 'elderly_npcs'] }, cookies: { id: 'cookies', name: 'Cookies', price: 25, energyRestore: 10, giftValue: 1, // +1 heart stock: 30, restockTime: 'always', // Always available description: 'Crunchy homemade cookies.', favoredBy: ['children', 'kai'] }, croissants: { id: 'croissants', name: 'Croissants', price: 75, energyRestore: 25, giftValue: 2, // +2 hearts stock: 15, restockTime: 'morning', description: 'Buttery, flaky croissants. Fancy!', favoredBy: ['ana', 'lawyer', 'wealthy_npcs'] }, // SPECIAL SEASONAL ITEMS pumpkin_pie: { id: 'pumpkin_pie', name: 'Pumpkin Pie', price: 180, energyRestore: 45, giftValue: 4, stock: 6, seasonal: 'autumn', description: 'Spiced pumpkin pie for autumn.', favoredBy: ['gronk', 'farmer_npcs'] }, gingerbread: { id: 'gingerbread', name: 'Gingerbread', price: 100, energyRestore: 30, giftValue: 3, stock: 12, seasonal: 'winter', description: 'Festive gingerbread cookies.', favoredBy: ['children', 'kai', 'festive_npcs'] } }; } /** * Unlock bakery (requires town restoration) */ unlockBakery() { // Check requirements if (!this.player.hasCompletedQuest('first_bread')) { return { success: false, message: 'Complete "First Bread" quest first!' }; } if (!this.player.hasMaterials({ wood: 100, wheat: 50 })) { return { success: false, message: 'Need 100 Wood + 50 Wheat to build bakery!' }; } if (this.player.money < 8000) { return { success: false, message: 'Need 8,000g to build bakery!' }; } // Build bakery this.player.removeMaterials({ wood: 100, wheat: 50 }); this.player.money -= 8000; this.isUnlocked = true; // Spawn baker NPC this.baker = this.game.npcs.spawn('baker', { name: 'Maria', position: { x: 1200, y: 800 }, // Bakery location dialogue: this.getBakerDialogue() }); // Open immediately this.isOpen = true; this.game.showMessage('🥖 Bakery is now open!'); return { success: true }; } /** * Get baker NPC dialogue */ getBakerDialogue() { return { greeting: [ "Welcome to the bakery! Fresh bread daily!", "Hello dear! What can I bake for you today?", "Mmm, smell that fresh bread!" ], buying: [ "Excellent choice!", "Fresh from the oven!", "Enjoy, dear!" ], gift_suggestion: [ "Cakes make wonderful gifts!", "Everyone loves fresh bread.", "Looking for a special gift? Try the pie!" ], competition: [ "Weekly baking competition this Sunday!", "Show me your best recipe!", "The winner gets a special prize!" ], birthday: [ "Need a birthday cake? I can make one!", "Tell me who it's for, I'll personalize it!", "Birthday cakes are my specialty!" ] }; } /** * Purchase item from bakery */ buyItem(itemId, quantity = 1) { const item = this.inventory[itemId]; if (!item) { return { success: false, message: 'Item not found!' }; } // Check if bakery is open if (!this.isOpen) { return { success: false, message: 'Bakery is closed!' }; } // Check seasonal availability if (item.seasonal && !this.isCurrentSeason(item.seasonal)) { return { success: false, message: `${item.name} is only available in ${item.seasonal}!` }; } // Check stock if (item.stock < quantity) { return { success: false, message: `Only ${item.stock} ${item.name} in stock!` }; } // Calculate price (with bulk discount) const discount = this.getBulkDiscount(quantity); const totalPrice = Math.floor(item.price * quantity * (1 - discount)); // Check money if (this.player.money < totalPrice) { return { success: false, message: `Not enough money! Need ${totalPrice}g` }; } // Purchase this.player.money -= totalPrice; item.stock -= quantity; // Add to inventory this.player.inventory.addItem(itemId, quantity); // Show message let message = `Purchased ${quantity}x ${item.name} for ${totalPrice}g!`; if (discount > 0) { message += ` (${Math.floor(discount * 100)}% bulk discount!)`; } this.game.showMessage(message); return { success: true, totalPrice: totalPrice, discount: discount }; } /** * Calculate bulk discount */ getBulkDiscount(quantity) { // 10+ items = 20% off if (quantity >= 10) { return 0.20; } // 5-9 items = 10% off if (quantity >= 5) { return 0.10; } return 0; } /** * Gift baked good to NPC */ giftItem(itemId, npcId) { const item = this.inventory[itemId]; const npc = this.game.npcs.get(npcId); if (!item || !npc) { return { success: false }; } // Check if player has item if (!this.player.inventory.hasItem(itemId)) { return { success: false, message: 'You don\'t have this item!' }; } // Calculate gift value (bonus if NPC favors this item) let giftValue = item.giftValue; if (item.favoredBy.includes(npc.id) || item.favoredBy.includes('all')) { giftValue *= 2; // Double hearts if favored! } // Remove from inventory this.player.inventory.removeItem(itemId, 1); // Add relationship points npc.addRelationshipPoints(giftValue); // NPC reaction const reaction = this.getNPCGiftReaction(npc, item, giftValue); this.game.showMessage( `${npc.name}: "${reaction}" +${giftValue} ❤️` ); return { success: true, heartsAdded: giftValue, reaction: reaction }; } /** * Get NPC reaction to gift */ getNPCGiftReaction(npc, item, heartsAdded) { if (heartsAdded >= 5) { return "Oh wow! This is amazing! Thank you so much!"; } if (heartsAdded >= 3) { return "This is wonderful! You're so thoughtful!"; } if (heartsAdded >= 1) { return "Thank you! I love fresh baked goods!"; } return "Thanks."; } /** * Order birthday cake */ orderBirthdayCake(npcId) { const npc = this.game.npcs.get(npcId); if (!npc) { return { success: false, message: 'NPC not found!' }; } // Check cost const cakePrice = 500; // Special birthday cake if (this.player.money < cakePrice) { return { success: false, message: `Birthday cakes cost ${cakePrice}g!` }; } // Order cake this.player.money -= cakePrice; const order = { npc: npc, orderDate: this.game.time.currentDate, deliveryDate: npc.birthday, delivered: false }; this.birthdayCakeOrders.push(order); this.game.showMessage( `Ordered birthday cake for ${npc.name}! Will be delivered on their birthday.` ); return { success: true, order: order }; } /** * Start weekly baking competition */ startBakingCompetition() { this.currentEvent = { type: 'baking_competition', startDate: this.game.time.currentDate, endDate: this.game.time.currentDate + 7, // Lasts 1 week participants: [], playerScore: 0, prize: { money: 1000, item: 'golden_whisk', hearts: 5 // +5 hearts with baker } }; this.game.showMessage( '🥖 Weekly Baking Competition started! Bring your best recipe!' ); return this.currentEvent; } /** * Submit recipe to competition */ submitCompetitionRecipe(recipeId) { if (!this.currentEvent || this.currentEvent.type !== 'baking_competition') { return { success: false, message: 'No baking competition active!' }; } // Check if player has baked this recipe const recipe = this.game.crafting.recipes[recipeId]; if (!recipe || !this.player.inventory.hasItem(recipeId)) { return { success: false, message: 'You need to bake this recipe first!' }; } // Calculate score based on recipe complexity const score = this.calculateRecipeScore(recipe); this.currentEvent.playerScore = Math.max(this.currentEvent.playerScore, score); this.game.showMessage( `Recipe submitted! Score: ${score}/100` ); return { success: true, score: score }; } /** * Calculate recipe score for competition */ calculateRecipeScore(recipe) { let score = 0; // Base score from ingredients count score += Object.keys(recipe.ingredients).length * 10; // Bonus for craft time (complexity) score += Math.min(recipe.craftTime, 50); // Bonus for energy restore (if food) if (recipe.energy_restore) { score += recipe.energy_restore / 2; } // Random factor (luck) score += Math.random() * 20; return Math.min(Math.floor(score), 100); } /** * Check seasonal availability */ isCurrentSeason(season) { const currentSeason = this.game.time.getSeason(); return currentSeason === season; } /** * Restock inventory (called at specific times) */ restockInventory() { const hour = this.game.time.getHour(); Object.values(this.inventory).forEach(item => { // Morning restock (6 AM) if (hour === 6 && item.restockTime === 'morning') { item.stock = this.getMaxStock(item.id); } // Afternoon restock (2 PM) if (hour === 14 && item.restockTime === 'afternoon') { item.stock = this.getMaxStock(item.id); } // Always available items restock every hour if (item.restockTime === 'always') { item.stock = this.getMaxStock(item.id); } }); } /** * Get max stock for item */ getMaxStock(itemId) { const defaults = { fresh_bread: 20, cake: 5, pie: 8, cookies: 30, croissants: 15, pumpkin_pie: 6, gingerbread: 12 }; return defaults[itemId] || 10; } /** * Update shop (called every hour) */ update() { const hour = this.game.time.getHour(); // Open/close shop this.isOpen = (hour >= 6 && hour <= 20); // Open 6 AM - 8 PM // Restock this.restockInventory(); // Check birthday cake deliveries this.checkBirthdayCakeDeliveries(); } /** * Check and deliver birthday cakes */ checkBirthdayCakeDeliveries() { const today = this.game.time.currentDate; this.birthdayCakeOrders.forEach(order => { if (!order.delivered && order.deliveryDate === today) { // Deliver cake this.player.inventory.addItem('birthday_cake_' + order.npc.id, 1); order.delivered = true; this.game.showMessage( `🎂 Birthday cake for ${order.npc.name} is ready!` ); } }); } /** * Get shop UI data */ getShopUIData() { return { isUnlocked: this.isUnlocked, isOpen: this.isOpen, inventory: this.inventory, currentEvent: this.currentEvent, baker: this.baker, openingHours: '6 AM - 8 PM' }; } }