/** * BARBER SHOP SYSTEM - Character Customization & Styling * Part of: New Town Buildings * Created: January 4, 2026 * * Features: * - Hairstyle changes (dreadlocks, mohawk, long hair, ponytail, bald) * - Piercings & body modifications (ear gauges, nose ring, eyebrow, lip) * - Color customization (hair dye, clothing) * - Zombie makeover (cosmetic for workers) * - NPC customization (change other characters) * - Save/load favorite looks */ class BarberShopSystem { constructor(game) { this.game = game; this.player = game.player; // Barber shop status this.isUnlocked = false; this.isOpen = false; this.barber = null; // Hairstyle catalog this.hairstyles = this.initializeHairstyles(); // Piercing catalog this.piercings = this.initializePiercings(); // Hair dye colors this.dyeColors = this.initializeDyeColors(); // Player's current appearance this.playerAppearance = { hairstyle: 'default', hairColor: 'brown', piercings: [], clothing: { shirt: 'default', pants: 'default', colorShirt: 'blue', colorPants: 'brown' } }; // Saved looks (5 slots) this.savedLooks = [null, null, null, null, null]; // Visit counter (for discounts) this.visitCount = 0; this.lastVisitDate = null; } /** * Initialize hairstyle catalog */ initializeHairstyles() { return { default: { id: 'default', name: 'Default Hair', price: 0, unlocked: true, sprite: 'hair_default', description: 'Your natural hair.' }, dreadlocks_pink_green: { id: 'dreadlocks_pink_green', name: 'Pink & Green Dreadlocks', price: 500, unlocked: true, signature: 'kai', // Kai's signature style sprite: 'hair_dreadlocks_pg', description: 'Kai\'s iconic pink and green dreads!' }, mohawk_blue: { id: 'mohawk_blue', name: 'Blue Mohawk', price: 300, unlocked: true, sprite: 'hair_mohawk_blue', description: 'Stand tall with this punk mohawk.' }, mohawk_purple: { id: 'mohawk_purple', name: 'Purple Mohawk', price: 300, unlocked: true, sprite: 'hair_mohawk_purple', description: 'Purple power!' }, mohawk_red: { id: 'mohawk_red', name: 'Red Mohawk', price: 300, unlocked: true, sprite: 'hair_mohawk_red', description: 'Fiery red mohawk.' }, long_hair: { id: 'long_hair', name: 'Long Hair', price: 400, unlocked: true, dyeable: true, sprite: 'hair_long', description: 'Flowing long hair, can be dyed any color.' }, ponytail: { id: 'ponytail', name: 'Ponytail', price: 250, unlocked: true, dyeable: true, sprite: 'hair_ponytail', description: 'Practical and stylish.' }, bald: { id: 'bald', name: 'Bald', price: 100, unlocked: true, reversible: true, // Can revert for free sprite: 'hair_none', description: 'Clean shaven head. Can reverse for FREE!' } }; } /** * Initialize piercing catalog */ initializePiercings() { return { ear_gauges: { id: 'ear_gauges', name: 'Ear Gauges', price: 200, unlocked: true, signature: 'kai', // Kai's trademark sprite: 'piercing_gauges', description: 'Large ear gauges like Kai\'s!' }, nose_ring: { id: 'nose_ring', name: 'Nose Ring', price: 150, unlocked: true, sprite: 'piercing_nose', description: 'Simple nose ring.' }, eyebrow_piercing: { id: 'eyebrow_piercing', name: 'Eyebrow Piercing', price: 100, unlocked: true, sprite: 'piercing_eyebrow', description: 'Edgy eyebrow piercing.' }, lip_ring: { id: 'lip_ring', name: 'Lip Ring', price: 150, unlocked: true, sprite: 'piercing_lip', description: 'Lip ring for that punk look.' }, multiple_ear: { id: 'multiple_ear', name: 'Multiple Ear Piercings', price: 50, stackable: true, // Can have multiple sprite: 'piercing_ear_multiple', description: 'Each additional piercing costs 50g.' } }; } /** * Initialize hair dye colors */ initializeDyeColors() { return { brown: { name: 'Brown', price: 0, hex: '#654321' }, black: { name: 'Black', price: 100, hex: '#000000' }, blonde: { name: 'Blonde', price: 150, hex: '#FFD700' }, red: { name: 'Red', price: 200, hex: '#FF0000' }, blue: { name: 'Blue', price: 200, hex: '#0000FF' }, purple: { name: 'Purple', price: 200, hex: '#800080' }, pink: { name: 'Pink', price: 200, hex: '#FF69B4' }, green: { name: 'Green', price: 200, hex: '#00FF00' }, white: { name: 'White', price: 250, hex: '#FFFFFF' } }; } /** * Unlock barber shop */ unlockBarberShop() { // Check requirements const npcCount = this.game.npcs.getPopulationCount(); if (npcCount < 3) { return { success: false, message: 'Need at least 3 NPCs in town first!' }; } if (!this.player.hasCompletedQuest('style_matters')) { return { success: false, message: 'Complete "Style Matters" quest first!' }; } if (!this.player.hasMaterials({ wood: 75, iron: 25 })) { return { success: false, message: 'Need 75 Wood + 25 Iron to build barber shop!' }; } if (this.player.money < 6000) { return { success: false, message: 'Need 6,000g to build barber shop!' }; } // Build barber shop this.player.removeMaterials({ wood: 75, iron: 25 }); this.player.money -= 6000; this.isUnlocked = true; this.isOpen = true; // Spawn barber NPC this.barber = this.game.npcs.spawn('barber', { name: 'Razor', position: { x: 1400, y: 900 }, appearance: { hairstyle: 'mohawk_purple', piercings: ['ear_gauges', 'nose_ring', 'lip_ring'] } }); this.game.showMessage('💇 Barber Shop is now open!'); return { success: true }; } /** * Change hairstyle */ changeHairstyle(hairstyleId) { const hairstyle = this.hairstyles[hairstyleId]; if (!hairstyle) { return { success: false, message: 'Hairstyle not found!' }; } // Check if shop is open if (!this.isOpen) { return { success: false, message: 'Barber shop is closed!' }; } // Check price (with discount) const discount = this.getVisitDiscount(); const price = Math.floor(hairstyle.price * (1 - discount)); // Free reversal from bald if (hairstyle.reversible && this.playerAppearance.hairstyle === 'bald') { // Revert to previous hairstyle for free this.playerAppearance.hairstyle = this.previousHairstyle || 'default'; this.game.showMessage('Hair restored for FREE!'); return { success: true, price: 0 }; } // Check money if (this.player.money < price) { return { success: false, message: `Not enough money! Need ${price}g` }; } // Save previous hairstyle (for bald reversal) this.previousHairstyle = this.playerAppearance.hairstyle; // Change hairstyle this.player.money -= price; this.playerAppearance.hairstyle = hairstyleId; // Update sprite this.updatePlayerSprite(); // Track visit this.incrementVisitCount(); let message = `Changed to ${hairstyle.name}! ${price}g`; if (discount > 0) { message += ` (${Math.floor(discount * 100)}% repeat customer discount!)`; } this.game.showMessage(message); return { success: true, price: price, discount: discount }; } /** * Add piercing */ addPiercing(piercingId) { const piercing = this.piercings[piercingId]; if (!piercing) { return { success: false, message: 'Piercing not found!' }; } // Check if already have (unless stackable) if (!piercing.stackable && this.playerAppearance.piercings.includes(piercingId)) { return { success: false, message: 'You already have this piercing!' }; } // Check price const price = piercing.price; if (this.player.money < price) { return { success: false, message: `Not enough money! Need ${price}g` }; } // Add piercing this.player.money -= price; if (piercing.stackable) { // Count how many of this type const count = this.playerAppearance.piercings.filter(p => p === piercingId).length; this.playerAppearance.piercings.push(`${piercingId}_${count + 1}`); } else { this.playerAppearance.piercings.push(piercingId); } // Update sprite this.updatePlayerSprite(); // Track visit this.incrementVisitCount(); this.game.showMessage(`Added ${piercing.name}! ${price}g`); return { success: true, price: price }; } /** * Remove piercing */ removePiercing(piercingId) { const index = this.playerAppearance.piercings.indexOf(piercingId); if (index === -1) { return { success: false, message: 'You don\'t have this piercing!' }; } // Remove free of charge this.playerAppearance.piercings.splice(index, 1); // Update sprite this.updatePlayerSprite(); this.game.showMessage('Piercing removed (free).'); return { success: true }; } /** * Dye hair color */ dyeHair(colorId) { const color = this.dyeColors[colorId]; if (!color) { return { success: false, message: 'Color not found!' }; } // Check if current hairstyle is dyeable const currentHairstyle = this.hairstyles[this.playerAppearance.hairstyle]; if (!currentHairstyle.dyeable && currentHairstyle.id !== 'default') { return { success: false, message: 'This hairstyle cannot be dyed!' }; } // Check price if (this.player.money < color.price) { return { success: false, message: `Not enough money! Need ${color.price}g` }; } // Dye hair this.player.money -= color.price; this.playerAppearance.hairColor = colorId; // Update sprite this.updatePlayerSprite(); // Track visit this.incrementVisitCount(); this.game.showMessage(`Hair dyed ${color.name}! ${color.price}g`); return { success: true, price: color.price }; } /** * Dye clothing */ dyeClothing(clothingPart, colorId) { const color = this.dyeColors[colorId]; if (!color) { return { success: false, message: 'Color not found!' }; } // Clothing dye is cheaper (half price) const price = Math.floor(color.price / 2); if (this.player.money < price) { return { success: false, message: `Not enough money! Need ${price}g` }; } // Dye clothing this.player.money -= price; if (clothingPart === 'shirt') { this.playerAppearance.clothing.colorShirt = colorId; } else if (clothingPart === 'pants') { this.playerAppearance.clothing.colorPants = colorId; } // Update sprite this.updatePlayerSprite(); this.game.showMessage(`${clothingPart} dyed ${color.name}! ${price}g`); return { success: true, price: price }; } /** * Zombie makeover (cosmetic for workers) */ zombieMakeover(zombieId) { const zombie = this.game.zombieWorkers.get(zombieId); if (!zombie) { return { success: false, message: 'Zombie not found!' }; } const price = 1000; if (this.player.money < price) { return { success: false, message: 'Zombie makeover costs 1,000g!' }; } // Apply makeover this.player.money -= price; // Random fancy appearance for zombie const fancyStyles = ['mohawk_blue', 'mohawk_purple', 'dreadlocks_pink_green']; const style = Phaser.Utils.Array.GetRandom(fancyStyles); zombie.appearance = { hairstyle: style, accessories: ['fancy_bow_tie', 'top_hat'] }; // Update zombie sprite this.game.zombieWorkers.updateZombieSprite(zombieId); // Loyalty bonus (zombies appreciate looking good!) zombie.addLoyalty(20); this.game.showMessage(`${zombie.name} looks fabulous! +20 Loyalty! 1,000g`); return { success: true, price: price }; } /** * Customize NPC appearance */ customizeNPC(npcId, changes) { const npc = this.game.npcs.get(npcId); if (!npc) { return { success: false, message: 'NPC not found!' }; } // Check relationship (need 5+ hearts) if (this.player.getRelationshipLevel(npcId) < 5) { return { success: false, message: `Need 5+ hearts with ${npc.name} first!` }; } const price = 500; if (this.player.money < price) { return { success: false, message: 'NPC customization costs 500g!' }; } // Apply changes this.player.money -= price; if (changes.hairstyle) { npc.appearance.hairstyle = changes.hairstyle; } if (changes.hairColor) { npc.appearance.hairColor = changes.hairColor; } // Update NPC sprite this.game.npcs.updateNPCSprite(npcId); // NPC reaction npc.addRelationshipPoints(10); this.game.showDialogue(npc.name, "Wow, I love it! Thank you!"); this.game.showMessage(`Styled ${npc.name}! +10 ❤️ 500g`); return { success: true, price: price }; } /** * Save current look to slot */ saveLook(slotIndex) { if (slotIndex < 0 || slotIndex >= 5) { return { success: false, message: 'Invalid slot!' }; } this.savedLooks[slotIndex] = { hairstyle: this.playerAppearance.hairstyle, hairColor: this.playerAppearance.hairColor, piercings: [...this.playerAppearance.piercings], clothing: { ...this.playerAppearance.clothing }, name: `Look ${slotIndex + 1}` }; this.game.showMessage(`Saved look to slot ${slotIndex + 1}!`); return { success: true }; } /** * Load saved look from slot */ loadLook(slotIndex) { if (slotIndex < 0 || slotIndex >= 5) { return { success: false, message: 'Invalid slot!' }; } const savedLook = this.savedLooks[slotIndex]; if (!savedLook) { return { success: false, message: 'No look saved in this slot!' }; } // Apply saved look (free!) this.playerAppearance = { hairstyle: savedLook.hairstyle, hairColor: savedLook.hairColor, piercings: [...savedLook.piercings], clothing: { ...savedLook.clothing } }; // Update sprite this.updatePlayerSprite(); this.game.showMessage(`Loaded ${savedLook.name}!`); return { success: true }; } /** * Get visit discount (repeat customers) */ getVisitDiscount() { // 5+ visits = 10% off if (this.visitCount >= 5) { return 0.10; } return 0; } /** * Increment visit count */ incrementVisitCount() { const today = this.game.time.currentDate; // Only count once per day if (this.lastVisitDate !== today) { this.visitCount++; this.lastVisitDate = today; } } /** * Update player sprite with new appearance */ updatePlayerSprite() { // Emit event for sprite manager to update this.game.emit('playerAppearanceChanged', { appearance: this.playerAppearance }); // Rebuild player sprite this.player.rebuildSprite(this.playerAppearance); } /** * Get preview of appearance change */ getPreview(changes) { return { ...this.playerAppearance, ...changes }; } /** * Get shop UI data */ getShopUIData() { return { isUnlocked: this.isUnlocked, isOpen: this.isOpen, hairstyles: this.hairstyles, piercings: this.piercings, dyeColors: this.dyeColors, currentAppearance: this.playerAppearance, savedLooks: this.savedLooks, visitDiscount: this.getVisitDiscount(), barber: this.barber }; } }