=============== LIBRARY RULES =============== From library maintainers: - Because the end goal is an Android APK built via Capacitor, all interactive elements must prioritize touch events over mouse clicks and scale responsively across different screen sizes. - Core logic modules, especially complex ones like GeneticsSystem or QuestSystem, require accompanying Jest unit tests for any new features or modifications before they are merged into the main branch. - Any newly introduced game mechanic must be cross-checked against previously patched vulnerabilities. Context 7 should flag code that might reopen old doors to quest bypasses, scaling exploits, or infinite interact loops. - Keep the game's core logic cleanly separated from the interface. MainScene and specific minigame scenes must handle the world and mechanics, while UIScene should strictly manage the UI overlays and menus. - Keep all source code organized as ES modules within the js/ directory (or its respective subfolders like systems/ and utils/). Avoid polluting the global scope and keep configurations like Config.js separate from runtime logic. - Absolutely no hardcoded pixel coordinates for UI elements (e.g., x: 300, y: 500). All positioning must be calculated dynamically using scene.cameras.main.width, scene.cameras.main.centerX, or percentage-based offsets to ensure nothing gets cut off on diff - All interactable UI elements must adhere to a strict 5% padding margin from the edges of the screen. This prevents buttons from being clipped by device bezels, camera cutouts, or system navigation bars. - To prevent overlapping menus, only one UI modal or popup can be active at a time. The system must automatically close or hide the currently active menu before sliding a new one onto the screen. - Every button must clearly explain its function. If an icon isn't universally obvious, it must be accompanied by a brief text label or feature a long-press tooltip system. Never assume the player knows how to launch a minigame. - All UI colors, stroke widths, and font styles must be referenced directly from a centralized theme object in Config.js. Jules is strictly forbidden from introducing "magic hex codes" directly into scene logic, ensuring high contrast and preventing ugly co - Every touchable element must provide immediate visual feedback. When a button is tapped, it must scale down slightly, change tint, or play a sound via the SoundSynthesizer. If an action fails, the UI must display a clear error toast, not fail silently. - No backend system or minigame can be considered "complete" or merged into the main branch unless its corresponding UI entry point is fully implemented, visible, and functional within the UIScene. - Never instantiate and destroy frequently used objects (like debris, floating text, or projectile sprites) on the fly. You must use Phaser's Group or Pool systems to recycle these objects, preventing massive garbage collection stutters during gameplay. - Every scene must have a shutdown or destroy event listener that explicitly removes custom event listeners, stops active tweens, and clears large temporary textures from memory before transitioning to a new scene. No ghost processes left behind. - Systems should not continuously "check" if a condition is met (polling) within the update loop. Instead, utilize Phaser's event emitter to trigger functions only when specific actions occur - When adding a new feature always verify the complete circuit before moving on. If a system is built but the player can't interact with it on screen, it shouldn't be merged yet. ### Install Project Dependencies Source: https://github.com/mnemonice/nadagotchi/blob/main/README.md Installs all necessary Node.js dependencies for the Nadagotchi project using npm. This command should be run after cloning the repository and navigating into the project directory. ```bash npm install ``` -------------------------------- ### JSDoc Example for Function Documentation Source: https://github.com/mnemonice/nadagotchi/blob/main/AGENTS.md This snippet demonstrates the mandatory JSDoc format for documenting new functions, methods, and classes. It includes essential tags like @param for input parameters and @returns for the output, along with a brief description of the function's purpose. This ensures code clarity and maintainability. ```javascript /** * Calculates the offspring's stats based on parents and environment. * @param {Genome} parentGenome - The source genome. * @param {object} environment - The current world state. * @returns {Stats} The calculated base stats. */ function calculateOffspringStats(parentGenome, environment) { // Function implementation here } ``` -------------------------------- ### Run Development Server Source: https://github.com/mnemonice/nadagotchi/blob/main/README.md Starts a local development server with hot-reloading capabilities using Vite. This allows for rapid development and testing of the game. The game can typically be accessed at http://localhost:5173. ```bash npm run dev ``` -------------------------------- ### Manage Quests with QuestSystem Source: https://context7.com/mnemonice/nadagotchi/llms.txt The QuestSystem class handles all aspects of quest management, including starting quests, checking requirements, advancing stages, and generating daily quests. It relies on the Nadagotchi class for context. Quest progression is tracked by stage. ```javascript import { Nadagotchi } from './js/Nadagotchi.js'; const pet = new Nadagotchi('Nurturer'); // Start a main quest pet.questSystem.startQuest('masterwork_crafting'); console.log(pet.quests); // { 'masterwork_crafting': { stage: 1, name: '...' } } // Get quest state const quest = pet.questSystem.getQuest('masterwork_crafting'); console.log(quest.stage); // 1 // Get current stage definition const stageDef = pet.questSystem.getStageDefinition('masterwork_crafting'); console.log(stageDef.description); // Stage description console.log(stageDef.requirements); // { items: {...}, flags: [...] } // Check if requirements are met if (pet.questSystem.checkRequirements('masterwork_crafting')) { pet.questSystem.advanceQuest('masterwork_crafting'); } // Set quest flags (for internal quest logic) pet.questSystem.setQuestFlag('masterwork_crafting', 'hasCraftedChair', true); // Generate daily quest based on season/weather const dailyQuest = pet.questSystem.generateDailyQuest('Spring', 'Sunny'); console.log(pet.dailyQuest); // { id: '...', npc: 'Grizzled Scout', type: 'FETCH', item: 'Berries', qty: 3, text: '...', completed: false } // Complete daily quest (when requirements met) if (pet.questSystem.completeDailyQuest()) { console.log('Daily quest completed!'); // Rewards: +20 career XP, +20 happiness, +1 NPC relationship } // Check if NPC has new quests available (for UI indicator) const hasQuest = pet.questSystem.hasNewQuest('Master Artisan'); ``` -------------------------------- ### Simulate Pet Lifecycle (JavaScript) Source: https://github.com/mnemonice/nadagotchi/blob/main/README.md Demonstrates how to instantiate and interact with the core Nadagotchi simulation logic independently of the Phaser game engine. It shows creating a pet, simulating a game tick with world state, and performing actions. ```javascript import { Nadagotchi } from './js/Nadagotchi.js'; // Create a new pet with the 'Intellectual' archetype const pet = new Nadagotchi('Intellectual'); // Simulate a game tick // Pass in the current world state (Weather, Time, etc.) pet.live({ weather: 'Rainy', time: 'Day', season: 'Autumn' }); // Perform an action pet.handleAction('STUDY'); console.log(`Current Mood: ${pet.mood}`); // e.g., 'happy' console.log(`Logic Skill: ${pet.skills.logic}`); ``` -------------------------------- ### Instantiate and Access Nadagotchi Pet Properties (JavaScript) Source: https://context7.com/mnemonice/nadagotchi/llms.txt Demonstrates how to create a new Nadagotchi instance with an initial archetype and access its core properties like name, archetype, stats, skills, mood, generation, and age. It also shows how to load pet data from persistence. ```javascript import { Nadagotchi } from './js/Nadagotchi.js'; // Create a new pet with an initial archetype const pet = new Nadagotchi('Intellectual'); // Access core properties console.log(pet.name); // "Nadagotchi" console.log(pet.dominantArchetype); // "Intellectual" console.log(pet.stats); // { hunger: 100, energy: 100, happiness: 70 } console.log(pet.skills); // { communication: 1, resilience: 1, navigation: 0, empathy: 0, logic: 0, focus: 0, crafting: 0, research: 0 } console.log(pet.mood); // "neutral" console.log(pet.generation); // 1 console.log(pet.age); // 0 // Load from saved data const savedData = persistence.loadPet(); if (savedData) { const loadedPet = new Nadagotchi(null, savedData); console.log(loadedPet.name); // Restored pet name } ``` -------------------------------- ### Track Seasons and Time with Calendar (JavaScript) Source: https://context7.com/mnemonice/nadagotchi/llms.txt The Calendar tracks in-game days, seasons, and years, providing the foundation for seasonal events and festivals. It starts at Day 1, Spring, Year 1 by default or can be loaded from saved data. The year consists of 112 in-game days, with each season lasting 28 days. ```javascript import { Calendar } from './js/Calendar.js'; // Create new calendar or load from save const calendar = new Calendar(); // Starts Day 1, Spring, Year 1 // Or load from saved data const savedCalendar = persistence.loadCalendar(); const calendar = new Calendar(savedCalendar); // Get current date const date = calendar.getDate(); console.log(date); // { day: 1, season: 'Spring', year: 1 } // Advance day (called when WorldClock triggers new day) calendar.advanceDay(); console.log(calendar.day); // 2 console.log(calendar.season); // 'Spring' // After 28 days, season advances // Spring -> Summer -> Autumn -> Winter -> Spring (increments year) // Season order and duration: // Spring: Days 1-28 // Summer: Days 1-28 // Autumn: Days 1-28 // Winter: Days 1-28 // Total year: 112 in-game days ``` -------------------------------- ### Build Project for Production Source: https://github.com/mnemonice/nadagotchi/blob/main/README.md Generates optimized static assets for deployment in the 'dist/' folder. This command is used to prepare the game for a production environment. ```bash npm run build ``` -------------------------------- ### Render Chart with Labels and Datasets Source: https://github.com/mnemonice/nadagotchi/blob/main/psagame.html Renders a chart using provided labels and datasets. It configures chart type, data, colors, and options including cutout percentage and legend position. Assumes Chart.js and color palette constants are available. ```javascript new Chart("myChart", { type: "doughnut", data: { labels: pLabels(['Adventurer Support', 'Nurturer Support', 'Mischievous Support', 'Intellectual Support', 'Recluse Support'], 16), datasets: [{ label: 'Conceptual Feature Focus', data: [22, 20, 18, 23, 17], backgroundColor: [PALETTE_CHART.terracotta, PALETTE_CHART.oliveGreen, PALETTE_CHART.softBlue, PALETTE_CHART.lightBeige, PALETTE_CHART.warmGray], borderColor: '#FFFFFF', borderWidth: 2, hoverOffset: 4 }] }, options: { ...commonChartOptions, cutout: '60%', plugins: { ...commonChartOptions.plugins, legend: { ...commonChartOptions.plugins.legend, position: 'bottom', } }, } }); ``` -------------------------------- ### Initialize Doughnut Chart with Chart.js Source: https://github.com/mnemonice/nadagotchi/blob/main/psagame.html This code initializes a doughnut chart using Chart.js. It configures the chart type, data, and options, including responsive settings and custom tooltip callbacks. ```javascript const archetypeFocusCtx = document.getElementById('archetypeFocusChart'); if (archetypeFocusCtx) { new Chart(archetypeFocusCtx.getContext('2d'), { type: 'doughnut', data: { labels: wrapLabels([ 'The Adventurer', 'The Nurturer', 'The Mischievous', 'The Intellectual', 'The Recluse' ], 15), // Example usage of wrapLabels datasets: [ { data: [15, 25, 20, 30, 10], backgroundColor: [ PALETTE_CHART.terracotta, PALETTE_CHART.oliveGreen, PALETTE_CHART.softBlue, PALETTE_CHART.lightBeige, PALETTE_CHART.warmGray ], hoverOffset: 4 } ] }, options: { ...commonChartOptions, cutout: '70%', // Example of a chart-specific option plugins: { ...commonChartOptions.plugins, legend: { ...commonChartOptions.plugins.legend, position: 'bottom' } } } }); } ``` -------------------------------- ### Initialize Phaser Game with Scenes Source: https://context7.com/mnemonice/nadagotchi/llms.txt Configures and initializes the Phaser game instance. It sets up game dimensions, rendering mode, parent container, scaling, and registers all necessary game scenes for the Nadagotchi simulation. ```javascript // js/game.js - Phaser game configuration import Phaser from 'phaser'; import { PreloaderScene } from './PreloaderScene.js'; import { StartScene } from './StartScene.js'; import { MainScene } from './MainScene.js'; import { UIScene } from './UIScene.js'; import { BreedingScene } from './BreedingScene.js'; // ... other scene imports const config = { type: Phaser.AUTO, width: 800, height: 600, backgroundColor: '#000000', parent: 'game-container', scale: { mode: Phaser.Scale.RESIZE, autoCenter: Phaser.Scale.CENTER_BOTH }, scene: [ PreloaderScene, // Asset loading StartScene, // Main menu MainScene, // Core gameplay UIScene, // Dashboard overlay BreedingScene, // Legacy/retirement ShowcaseScene, // Hall of fame GhostScene, // Ghost pet viewing // Career minigames: LogicPuzzleScene, ScoutMinigameScene, HealerMinigameScene, ArtisanMinigameScene, ExpeditionScene, DanceMinigameScene, StudyMinigameScene ], pixelArt: true, dom: { createContainer: true } }; const game = new Phaser.Game(config); ``` -------------------------------- ### Expedition System Unit Tests Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt Contains unit tests for the ExpeditionSystem class, verifying path generation, node filtering by season, and choice resolution based on pet skills. It uses a mock random number generator for predictable test outcomes. ```javascript const { ExpeditionSystem } = require('../js/systems/ExpeditionSystem.js'); const { SeededRandom } = require('../js/utils/SeededRandom.js'); describe('ExpeditionSystem', () => { let system; let mockRng; beforeEach(() => { mockRng = new SeededRandom(12345); system = new ExpeditionSystem(mockRng); }); test('should generate a path of specified length', () => { const path = system.generatePath('Spring', 'Sunny', 3); expect(path).toHaveLength(3); expect(path[0]).toHaveProperty('description'); expect(path[0]).toHaveProperty('choices'); }); test('should filter nodes by season', () => { // FROZEN_POND is Winter only const pathSpring = system.generatePath('Spring', 'Sunny', 20); const hasWinterNodeInSpring = pathSpring.some(n => n.id === 'FROZEN_POND'); expect(hasWinterNodeInSpring).toBe(false); }); test('should resolve choice success based on skill', () => { // Mock pet const pet = { skills: { navigation: 10 }, // High skill }; const choice = { skill: 'navigation', difficulty: 5, success: { text: "Win" }, failure: { text: "Lose" } }; // RNG range(0, 10) -> let's say it returns 0. 0 + 10 >= 5. Success. const result = system.resolveChoice(choice, pet); expect(result.outcome).toBe('success'); }); test('should resolve choice failure based on skill', () => { const pet = { skills: { navigation: 0 }, }; const choice = { skill: 'navigation', difficulty: 20, // Impossible success: { text: "Win" }, failure: { text: "Lose" } }; const result = system.resolveChoice(choice, pet); expect(result.outcome).toBe('failure'); }); }); ``` -------------------------------- ### Render Archetype Cards with JavaScript Source: https://github.com/mnemonice/nadagotchi/blob/main/psagame.html This script iterates through archetype data and dynamically creates HTML cards for each archetype. It appends these cards to a specified container and adds click event listeners for toggling an 'open' class. ```javascript const archetypesData = [ { name: "The Adventurer", icon: "🧭", description: "Craves exploration, novelty, challenges. Becomes bored with routine.", happy: "Discovering new areas, mastering new mini-games.", sad: "Stuck in a rut, repetitive tasks.", angry: "Exploration attempts blocked, repeated failures." }, { name: "The Nurturer", icon: "❤️", description: "Enjoys caring for others, building relationships, fostering growth.", happy: "Strong relationships, virtual pets/characters well-cared for.", sad: "Perceived neglect (even accidental), weakening social bonds.", angry: "Perceived injustice, mistreatment of a 'friend'." }, { name: "The Mischievous", icon: "😈", description: "Likes to bend rules, cause harmless trouble, seeks playful chaos.", happy: "Successfully pulling off a prank, surprising the player.", sad: "Strictly disciplined, unable to express playful side.", angry: "Thwarted by rigid rules/authority." }, { name: "The Intellectual", icon: "💡", description: "Driven by curiosity, problem-solving, learning.", happy: "Gaining new knowledge, solving puzzles.", sad: "Simple, repetitive tasks, no new stimuli.", angry: "Faced with illogical situations, blatant misinformation." }, { name: "The Recluse", icon: "🏠", description: "Prefers solitude, quiet activities, needs personal space.", happy: "Left alone for reasonable periods, engaging in quiet activities.", sad: "Constantly pestered, forced into crowded situations.", angry: "Repeated violation of personal boundaries." } ]; const archetypeContainer = document.getElementById('archetypeContainer'); archetypesData.forEach(arch => { const card = document.createElement('div'); card.className = 'archetype-card p-4 border-[#D8A373]/50 rounded-lg hover:shadow-md transition-shadow cursor-pointer bg-white'; card.innerHTML = `

${arch.icon}${arch.name}

${arch.description}

Happy: ${arch.happy}

Sad: ${arch.sad}

Angry: ${arch.angry}

`; card.addEventListener('click', () => { card.classList.toggle('open'); }); archetypeContainer.appendChild(card); }); ``` -------------------------------- ### Run Project Tests Source: https://github.com/mnemonice/nadagotchi/blob/main/README.md Executes the test suite for the Nadagotchi project using Jest. This command is used to ensure the core logic and systems are functioning as expected. ```bash npm test ``` -------------------------------- ### Handling Web Audio API Not Supported in JavaScript Source: https://github.com/mnemonice/nadagotchi/blob/main/test_output.txt This JavaScript code demonstrates how to handle cases where the Web Audio API is not supported or blocked. It includes a try-catch block to log a warning and set the audio context to null if an error occurs. This is often seen in preloader scenes. ```javascript try { this.setVolume(Config.SETTINGS.DEFAULT_VOLUME); } catch (e) { console.warn('Web Audio API not supported or blocked.', e); this.ctx = null; } ``` -------------------------------- ### Simulate Nadagotchi's Daily Life Cycle (JavaScript) Source: https://context7.com/mnemonice/nadagotchi/llms.txt Illustrates the usage of the `live()` method to simulate the passage of time for a Nadagotchi. This method updates stats, mood, and age based on provided world state parameters like weather, time, season, and active events. It supports both explicit delta time and legacy object-based updates. ```javascript import { Nadagotchi } from './js/Nadagotchi.js'; const pet = new Nadagotchi('Adventurer'); // Simulate a game tick with world state const worldState = { weather: 'Sunny', // Sunny, Cloudy, Rainy, Stormy time: 'Day', // Night, Dawn, Day, Dusk season: 'Spring', // Spring, Summer, Autumn, Winter activeEvent: null // null or { name: 'SpringEquinoxFestival', description: '...' } }; // Call with delta time (ms since last update) and world state pet.live(16, worldState); // 16ms for 60fps // Check state changes console.log(pet.stats.hunger); // Decayed based on metabolism console.log(pet.stats.energy); // Affected by weather/time console.log(pet.mood); // Calculated from stats console.log(pet.age); // Incremented slightly // Legacy mode (object only, defaults dt) pet.live({ weather: 'Rainy', time: 'Night', season: 'Autumn' }); // Mood calculation thresholds: // - angry: hunger < 10 // - sad: hunger < 30 OR energy < 20 // - happy: hunger > 80 AND energy > 80 // - neutral: otherwise ``` -------------------------------- ### Add ExpeditionScene to Game Initialization (JavaScript) Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt Integrates the new `ExpeditionScene` into the Phaser game configuration. This makes the scene available for launching during gameplay. ```javascript --- js/game.js +++ js/game.js @@ -13,6 +13,7 @@ import { ScoutMinigameScene } from './ScoutMinigameScene.js'; import { HealerMinigameScene } from './HealerMinigameScene.js'; import { ArtisanMinigameScene } from './ArtisanMinigameScene.js'; +import { ExpeditionScene } from './ExpeditionScene.js'; /** * Phaser Game Configuration. @@ -38,7 +39,8 @@ LogicPuzzleScene, ScoutMinigameScene, HealerMinigameScene, - ArtisanMinigameScene + ArtisanMinigameScene, + ExpeditionScene ] }; ``` -------------------------------- ### Integrate Expedition Action Handling (JavaScript) Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt Adds event listeners and logic to the `MainScene` to handle the `EventKeys.EXPLORE` action, launching the `ExpeditionScene` if the Nadagotchi has sufficient energy. It also updates the notification message for low energy. ```javascript --- js/MainScene.js +++ js/MainScene.js @@ -142,6 +142,7 @@ this.game.events.on(EventKeys.UI_ACTION, this.handleUIAction, this); this.game.events.on(EventKeys.UPDATE_SETTINGS, this.handleUpdateSettings, this); this.game.events.on(EventKeys.WORK_RESULT, this.handleWorkResult, this); + this.game.events.on(EventKeys.SCENE_COMPLETE, this.handleSceneComplete, this); this.scale.on('resize', this.resize, this); // --- Final Setup --- @@ -268,14 +269,14 @@ this.nadagotchi.handleAction(actionType, data); break; case EventKeys.EXPLORE: - if (this.nadagotchi.stats.energy >= Config.ACTIONS.EXPLORE.ENERGY_COST) { + if (this.nadagotchi.stats.energy >= Config.ACTIONS.EXPEDITION.ENERGY_COST) { this.scene.pause(); this.scene.launch('ExpeditionScene', { nadagotchi: this.nadagotchi, weather: this.worldState.weather }); } else { - this.showNotification("Too Tired to Explore", '#FF0000'); + this.showNotification("Too Tired for Expedition", '#FF0000'); } break; default: @@ -291,6 +292,20 @@ this.gameSettings = { ...this.gameSettings, ...newSettings }; this.persistence.saveSettings(this.gameSettings); } + + /** + * Handles the results from a completed work mini-game. + * @param {object} data - The result data from the mini-game scene. + * @param {boolean} data.success - Whether the mini-game was completed successfully. + * @param {string} data.career - The career associated with the mini-game. + * @param {string} [data.craftedItem] - The item that was crafted, if any. + */ + handleSceneComplete(data) { + if (data.type === 'EXPEDITION') { + // Expedition logic is handled within the scene/system, we just need to ensure UI update + this.game.events.emit(EventKeys.UPDATE_STATS, { nadagotchi: this.nadagotchi, settings: this.gameSettings }); + } + } /** * Handles the results from a completed work mini-game. ``` -------------------------------- ### Manage Inventory and Crafting with InventorySystem Source: https://context7.com/mnemonice/nadagotchi/llms.txt The InventorySystem class manages the pet's inventory, including adding, removing, and consuming items. It also handles crafting recipes, foraging for new items, and applying home decorations. Dependencies include the Nadagotchi class. ```javascript import { Nadagotchi } from './js/Nadagotchi.js'; const pet = new Nadagotchi('Recluse'); // Add items to inventory pet.inventorySystem.addItem('Sticks', 5); pet.inventorySystem.addItem('Shiny Stone', 2); console.log(pet.inventory); // { 'Sticks': 5, 'Shiny Stone': 2 } // Remove items pet.inventorySystem.removeItem('Sticks', 2); console.log(pet.inventory['Sticks']); // 3 // Craft an item (requires discovered recipe and materials) pet.inventorySystem.craftItem('Fancy Bookshelf'); // Requires: materials defined in recipe, energy, discovered recipe // Consume items (applies effects) const result = pet.inventorySystem.consumeItem('Berries'); // Berries: +10 hunger, +2 energy // Logic-Boosting Snack: +10 energy, +5 happiness, +0.5 logic // Hot Cocoa: +15 energy, +15 happiness // Stamina-Up Tea: +30 energy // Clear Water: +5 energy, +2 happiness // Metabolism-Slowing Tonic: Permanently reduces metabolism gene // Forage for items pet.inventorySystem.forage(); // Changes location to 'Forest', costs 10 energy // Can find: Berries, Sticks, Shiny Stone // Season-specific: Frostbloom (Winter), Muse Flower (Autumn) // 2% rare artifact drop: Ancient Tome, Heart Amulet, Genetic Scanner // Discover recipes pet.inventorySystem.discoverRecipe('Masterwork Chair'); console.log(pet.discoveredRecipes); // ['Fancy Bookshelf', 'Masterwork Chair'] // Apply home decor const decorResult = pet.inventorySystem.applyHomeDecor('Blue Wallpaper', 'Entryway'); console.log(decorResult); // { success: true, assetKey: '...', type: 'WALLPAPER', message: '...' } ``` -------------------------------- ### Create Game UI Elements with Phaser Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt This snippet demonstrates creating and adding various UI elements to a Phaser game scene, including background rectangles, text for step counters and descriptions, and interactive buttons for choices. It utilizes the `add.rectangle` and `add.text` methods for visual elements and a `ButtonFactory` for interactive components. ```javascript const bg = this.add.rectangle(0, 0, w, h, 0x2e3b2e).setStrokeStyle(2, 0x88DDAA); this.contentContainer.add(bg); // Step Counter const counter = this.add.text(0, -h/2 + 30, `Step ${this.currentIndex + 1} / ${this.path.length}`, { fontFamily: 'VT323, fontSize: '24px', color: '#AAAAAA' }).setOrigin(0.5); this.contentContainer.add(counter); // Description const desc = this.add.text(0, -50, node.description, { fontFamily: 'VT323', fontSize: '32px', color: '#FFFFFF', align: 'center', wordWrap: { width: w - 40 } }).setOrigin(0.5); this.contentContainer.add(desc); // Choices let yPos = 80; node.choices.forEach(choice => { let label = choice.text; if (choice.skill) { const chance = this.pet.skills[choice.skill] || 0; // Optional: Show hint about chance? " (Logic: 3)" label += ` [${choice.skill}: ${Math.floor(chance)}]`; } const btn = ButtonFactory.createButton(this, 0, yPos, label, () => { this.handleChoice(choice); }, { width: 400, height: 50, color: 0x446644, fontSize: '24px' }); this.contentContainer.add(btn); yPos += 70; }); ``` -------------------------------- ### Display Game Summary Screen with Phaser Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt This JavaScript code snippet illustrates the creation of a summary screen at the end of a game session. It displays completion messages, accumulated loot, and experience points, updating the pet's inventory and stats accordingly. It uses Phaser's `add.rectangle` and `add.text` for UI elements. ```javascript showSummary() { this.contentContainer.removeAll(true); const w = 600; const h = 400; const bg = this.add.rectangle(0, 0, w, h, 0x2e3b2e).setStrokeStyle(2, 0xFFD700); this.contentContainer.add(bg); this.add.text(0, -h/2 + 40, "EXPEDITION COMPLETE", { fontFamily: 'VT323', fontSize: '40px', color: '#FFD700' }).setOrigin(0.5).setScrollFactor(0).setDepth(1).addToDisplayList(this.contentContainer); // Helper to add to container? No, just add const title = this.add.text(0, -h/2 + 40, "EXPEDITION COMPLETE", { fontFamily: 'VT323', fontSize: '40px', color: '#FFD700' }).setOrigin(0.5); this.contentContainer.add(title); let summaryText = "You returned home.\n\nLoot Gained:\n"; const items = Object.entries(this.loot); if (items.length === 0) summaryText += "- Nothing...\n"; items.forEach(([item, qty]) => { summaryText += `- ${item} x${qty}\n`; // Actually add to pet inventory this.pet.inventorySystem.addItem(item, qty); }); // XP? Assuming general skill gain or just mechanic fun. // Let's add the XP to Navigation skill for now as a catch-all if (this.xpGained > 0) { ``` -------------------------------- ### Implement Tabbed Interface Functionality with JavaScript Source: https://github.com/mnemonice/nadagotchi/blob/main/psagame.html This script handles the functionality for a tabbed interface. It adds click event listeners to tab buttons to switch between different content sections, managing active states and visibility. ```javascript const skillTabsContainer = document.getElementById('skillTabsContainer'); if (skillTabsContainer) { const tabButtons = skillTabsContainer.querySelectorAll('.tab-button'); const tabContents = skillTabsContainer.querySelectorAll('.tab-content'); tabButtons.forEach(button => { button.addEventListener('click', () => { tabButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); tabContents.forEach(content => content.classList.add('hidden')); const activeTabContent = document.getElementById(button.dataset.tab); if (activeTabContent) { activeTabContent.classList.remove('hidden'); } }); }); } ``` -------------------------------- ### Genetics System Performance Benchmark Source: https://github.com/mnemonice/nadagotchi/blob/main/test_output.txt This console log indicates the performance of the 'GeneticsSystem.breed' function. It was executed 50,000 times with 200 items, completing in 1210ms. This benchmark helps in understanding the efficiency of the breeding algorithm. ```javascript console.log(`[Benchmark] GeneticsSystem.breed x 50000 with 200 items: 1210ms`); ``` -------------------------------- ### Configure Chart.js Defaults and Helper Functions Source: https://github.com/mnemonice/nadagotchi/blob/main/psagame.html This code sets global defaults for Chart.js, including font colors, grid colors, and a color palette. It also includes helper functions for wrapping long labels and formatting tooltip titles. ```javascript const FONT_COLOR_CHART = '#4A4A4A'; const GRID_COLOR_CHART = '#E0E0E0'; const PALETTE_CHART = { terracotta: '#D8A373', oliveGreen: '#A3B8A2', softBlue: '#9DB4C0', lightBeige: '#F3EADA', warmGray: '#BFBDBB' }; Chart.defaults.font.family = 'Inter'; Chart.defaults.color = FONT_COLOR_CHART; Chart.defaults.borderColor = GRID_COLOR_CHART; function wrapLabels(labels, maxLength) { return labels.map(label => { if (typeof label === 'string' && label.length > maxLength) { const words = label.split(' '); let currentLine = ''; const lines = []; for (const word of words) { if ((currentLine + word).length > maxLength && currentLine.length > 0) { lines.push(currentLine.trim()); currentLine = ''; } currentLine += word + ' '; } if (currentLine.trim().length > 0) { lines.push(currentLine.trim()); } return lines.length > 0 ? lines : [label]; // Ensure it returns an array even if one line } return label; }); } const tooltipTitleCallback = (tooltipItems) => { const item = tooltipItems[0]; if (!item || !item.chart || !item.chart.data || !item.chart.data.labels || typeof item.dataIndex === 'undefined') { return ''; } let label = item.chart.data.labels[item.dataIndex]; if (Array.isArray(label)) { return label.join(' '); } return label; }; const commonChartOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: FONT_COLOR_CHART, font: { size: 11 }, boxWidth: 15, padding: 15 } }, tooltip: { callbacks: { title: tooltipTitleCallback }, backgroundColor: 'rgba(74, 74, 74, 0.9)', titleColor: '#FFFFFF', bodyColor: '#FFFFFF', padding: 10, cornerRadius: 4 } }, scales: { x: { display: false, ticks: { color: FONT_COLOR_CHART, font: {size: 10} }, grid: { display: false } }, y: { display: false, ticks: { color: FONT_COLOR_CHART, font: {size: 10} }, grid: { display: false } } } }; ``` -------------------------------- ### Expedition Scene Logic Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt Handles the logic for the expedition scene, including updating pet skills, displaying summary text, and managing navigation buttons. It emits an event upon scene completion. ```javascript this.pet.skills.navigation += (this.xpGained * 0.01); summaryText += `\nNavigation Skill +${(this.xpGained * 0.01).toFixed(2)}`; const text = this.add.text(0, 0, summaryText, { fontFamily: 'VT323', fontSize: '24px', color: '#FFFFFF', align: 'center' }).setOrigin(0.5); this.contentContainer.add(text); const homeBtn = ButtonFactory.createButton(this, 0, 150, "Return Home", () => { this.game.events.emit(EventKeys.SCENE_COMPLETE, { type: 'EXPEDITION' }); this.scene.stop(); this.scene.resume('MainScene'); }, { width: 200, height: 50, color: 0x4CAF50 }); this.contentContainer.add(homeBtn); ``` -------------------------------- ### ExpeditionScene: Manage Expedition Minigame UI (JavaScript) Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt The ExpeditionScene class handles the visual presentation and user interaction for the expedition minigame. It initializes the ExpeditionSystem, generates an expedition path, and displays nodes and choices to the player. It manages the game state, including the current node index and collected loot. ```javascript import { ButtonFactory } from './ButtonFactory.js'; import { ExpeditionSystem } from './systems/ExpeditionSystem.js'; import { EventKeys } from './EventKeys.js'; /** * @class ExpeditionScene * @extends Phaser.Scene * @classdesc * Handles the visual presentation and interaction of the "Expedition" minigame. * Displays nodes, handles choices, and shows results. */ export class ExpeditionScene extends Phaser.Scene { constructor() { super({ key: 'ExpeditionScene' }); } init(data) { this.pet = data.nadagotchi; // Reference to the pet this.season = this.pet.currentSeason || 'Spring'; this.weather = data.weather || 'Sunny'; // Initialize System this.system = new ExpeditionSystem(this.pet.rng); // Generate Path this.path = this.system.generatePath(this.season, this.weather, 3); this.currentIndex = 0; this.loot = {}; this.xpGained = 0; } create() { const width = this.cameras.main.width; const height = this.cameras.main.height; // Background (Darker overlay) this.add.rectangle(0, 0, width, height, 0x1a2b1a).setOrigin(0); // Header this.add.text(width / 2, 50, "WILDERNESS EXPEDITION", { fontFamily: 'VT323, monospace', fontSize: '48px', color: '#88DDAA' }).setOrigin(0.5); // Content Area Container this.contentContainer = this.add.container(width / 2, height / 2); // Start Logic if (this.path.length === 0) { this.showSummary(); // Should not happen usually } else { this.showNode(this.path[this.currentIndex]); } } showNode(node) { this.contentContainer.removeAll(true); const w = 600; const h = 400; // Panel Background ``` -------------------------------- ### Display Game Result Screen with Phaser Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt This snippet shows how to render a result screen after a player makes a choice. It dynamically displays success or failure messages, detailed text, and applies rewards such as items, experience points, and stat changes to the pet. It also includes a 'Continue' button to proceed in the game. ```javascript showResult(details, outcome) { this.contentContainer.removeAll(true); const w = 600; const h = 400; const bg = this.add.rectangle(0, 0, w, h, 0x2e3b2e).setStrokeStyle(2, outcome === 'success' ? 0x00FF00 : 0xFF0000); this.contentContainer.add(bg); const title = this.add.text(0, -h/2 + 40, outcome === 'success' ? "SUCCESS!" : "FAILURE...", { fontFamily: 'VT323', fontSize: '40px', color: outcome === 'success' ? '#00FF00' : '#FF0000' }).setOrigin(0.5); this.contentContainer.add(title); const text = this.add.text(0, -20, details.text, { fontFamily: 'VT323', fontSize: '28px', color: '#FFFFFF', align: 'center', wordWrap: { width: w - 40 } }).setOrigin(0.5); this.contentContainer.add(text); // Apply Rewards Logic Temporary (Accumulate) if (details.items) { for (const [item, qty] of Object.entries(details.items)) { this.loot[item] = (this.loot[item] || 0) + qty; } } if (details.xp) { this.xpGained += details.xp; } // Direct Stat Application (Instant for now) if (details.stats) { for (const [stat, val] of Object.entries(details.stats)) { if (stat === 'happiness') this.pet.stats.happiness += val; if (stat === 'energy') this.pet.stats.energy += val; if (stat === 'cleanliness') { /* No cleanliness stat yet, ignore */ } } // Clamp stats this.pet.stats.happiness = Math.max(0, Math.min(this.pet.maxStats.happiness, this.pet.stats.happiness)); this.pet.stats.energy = Math.max(0, Math.min(this.pet.maxStats.energy, this.pet.stats.energy)); } const nextBtn = ButtonFactory.createButton(this, 0, 100, "Continue", () => { this.currentIndex++; if (this.currentIndex < this.path.length) { this.showNode(this.path[this.currentIndex]); } else { this.showSummary(); } }, { width: 200, height: 50, color: 0xD8A373 }); this.contentContainer.add(nextBtn); } ``` -------------------------------- ### Update Expedition Configuration (JavaScript) Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt Modifies the configuration file to include the ENERGY_COST for the new Expedition action. This ensures the game correctly tracks energy expenditure for expeditions. ```javascript --- js/Config.js +++ js/Config.js @@ -125,7 +125,8 @@ SKILL_GAIN: 0.2 }, EXPEDITION: { - LENGTH: 3 + LENGTH: 3, + ENERGY_COST: 15 }, INTERACT_NPC: { ENERGY_COST: 5, ``` -------------------------------- ### PersistenceManager: Save and Load Game State (JavaScript) Source: https://context7.com/mnemonice/nadagotchi/llms.txt Handles game state persistence to localStorage, including integrity checks and legacy migration. It provides methods to save and load various game data like pet information, calendar, journal, recipes, furniture, settings, achievements, and a hall of fame. It also includes functions to clear active pet data or all game data. ```javascript import { PersistenceManager } from './js/PersistenceManager.js'; import { Nadagotchi } from './js/Nadagotchi.js'; const persistence = new PersistenceManager(); // Save pet data (non-blocking, scheduled during idle time) const pet = new Nadagotchi('Adventurer'); persistence.savePet(pet); // Load pet data (returns null if no save or corrupted) const savedPet = persistence.loadPet(); if (savedPet) { const loadedPet = new Nadagotchi(null, savedPet); } // Save/load other game data persistence.saveCalendar({ day: 5, season: 'Summer', year: 1 }); const calendar = persistence.loadCalendar(); persistence.saveJournal([{ date: '...', text: '...' }]); const journal = persistence.loadJournal(); persistence.saveRecipes(['Fancy Bookshelf', 'Hot Cocoa']); const recipes = persistence.loadRecipes(); persistence.saveFurniture({ 'Entryway': [{ name: 'Plant', x: 100, y: 200 }] }); const furniture = persistence.loadFurniture(); persistence.saveSettings({ volume: 0.5, speed: 1.0 }); const settings = persistence.loadSettings(); persistence.saveAchievements({ unlocked: ['first_steps'], progress: {} }); const achievements = persistence.loadAchievements(); // Hall of Fame (retired pets) persistence.saveToHallOfFame(retiredPetData); const hallOfFame = persistence.loadHallOfFame(); // Clear data persistence.clearActivePet(); // Clear current pet save persistence.clearAllData(); // Clear all game data (except settings/hall of fame) ``` -------------------------------- ### ExpeditionSystem: Generate Procedural Expedition Paths (JavaScript) Source: https://github.com/mnemonice/nadagotchi/blob/main/handover/expedition_diffs.txt The ExpeditionSystem class generates procedural expedition paths. It filters available nodes based on season and weather, then randomly selects nodes to form a path. The selection logic is currently a simple random choice, but can be extended for weighted or unique node selection. It requires a seeded random number generator. ```javascript import { ExpeditionNodes } from '../ExpeditionDefinitions.js'; import { Config } from '../Config.js'; /** * @fileoverview System for generating procedural expeditions. * Selects nodes based on environment (season, weather) and randomness. */ export class ExpeditionSystem { /** * @param {object} rng - The seeded random number generator. */ constructor(rng) { this.rng = rng; } /** * Generates a path of encounter nodes for an expedition. * @param {string} season - The current season (Spring, Summer, Autumn, Winter). * @param {string} weather - The current weather (Sunny, Rainy, etc). * @param {number} length - Number of nodes in the path (default 3). * @returns {Array} An array of node objects. */ generatePath(season, weather, length = 3) { const validNodes = []; // Filter nodes based on criteria for (const key in ExpeditionNodes) { const node = ExpeditionNodes[key]; let isValid = true; // Check Season if (node.season && !node.season.includes(season)) { isValid = false; } // Check Weather if (node.weather && !node.weather.includes(weather)) { isValid = false; } if (isValid) { validNodes.push(node); } } // Select nodes const path = []; for (let i = 0; i < length; i++) { if (validNodes.length === 0) break; // Weighted selection could go here, for now simple random // If we want unique nodes per path, we should splice them out // But repeats might be okay for generic ones. Let's allow repeats for now. const selected = this.rng.choice(validNodes); path.push(selected); } return path; } /** * Resolves an action choice against the pet's stats. * @param {object} choice - The choice object from the node definition. * @param {import('../Nadagotchi.js').Nadagotchi} pet - The pet instance. * @returns {object} The result object (success or failure definition + actual roll). */ resolveChoice(choice, pet) { if (!choice.skill) { // No skill check, auto success return { outcome: 'success', details: choice.success }; } const skillLevel = pet.skills[choice.skill] || 0; // Base chance 50%, +10% per skill level vs difficulty? // Let's do a simple roll: Roll(0-10) + Skill >= Difficulty const roll = this.rng.range(0, 10); const total = roll + skillLevel; if (total >= choice.difficulty) { return { outcome: 'success', details: choice.success, roll: total }; } else { return { outcome: 'failure', details: choice.failure, roll: total }; } } } ``` -------------------------------- ### Handle UI Actions via Event Bus (JavaScript) Source: https://github.com/mnemonice/nadagotchi/blob/main/README.md Illustrates how the Nadagotchi game uses a centralized event bus for communication between different game components, specifically handling UI actions within a Phaser Scene. It shows listening for and emitting events. ```javascript import { EventKeys } from './js/EventKeys.js'; // In a Scene (e.g., MainScene.js) // Listen for UI actions this.game.events.on(EventKeys.UI_ACTION, (actionType, data) => { if (actionType === EventKeys.FEED) { this.nadagotchi.handleAction('FEED'); } }); // Emit an event (e.g., from a button click in UIScene.js) this.game.events.emit(EventKeys.UI_ACTION, EventKeys.FEED); ```