diff --git a/TODO.md b/TODO.md index 119b109..acfdf2c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,28 +1,3 @@ # TODO -Tous les items ont été traités. Ce fichier est conservé comme historique. - -## Noms de personnages - -Les noms des personnages dans les histoires ne sont pas traduits à l'affichage. Loreline ne propose a priori pas de système de traduction pour les noms de personnages donc il faudra des clés de traductions dédiées. - -## Partir à l'aventure - -Lorsqu'on débloque "Partir à l'aventure" mais qu'aucune aventure n'a été lancée il faut ajouter une incentive plus claire à lancer la première aventure. L'entrée devrait avec le préfix (new) ou (nouveau) et être en couleur (si la couleur est débloquée) tant qu'une aventure n'a pas été faite. - -## Retouch aventure Space - -Dans cette Space aventure, la fin tombe un peu abrute: le concours d'ouverture de boite n'a pas lieu, "Trade items with Zx'thorp" tourne court également. - -Attendu: Il faudrait un fin un peu plus sympa ou couper plus tôt (l'aventure peu être plus courte si besoin: la perfection est atteinte non pas lorsqu'il n'y a plus rien à ajouter mais plus rien à enlever !) - -Dans cette Space aventure le fuel semble être un sujet sauf qu'en réalité on ne peut pas tomber à court. Ce serait bien de rendre ce state vraiment utile (ex: si on utilise le fuel tôt on ne peut plus l'utiliser plus tard). - -## Unavailable - -Plutôt que d'avoir "unavailable" pour un choix à condition, ce sera mieux de donner un indice sur ce qu'il faut. -Ex: "(Si j'avais plus de force…)" ou "(Si j'avais des jambes adaptées…)" - -## Journal d'événements - -pas utile après test: à supprimer complètement. +Tous les items ont été traités. diff --git a/content/adventures/space/intro.fr.lor b/content/adventures/space/intro.fr.lor index 169eafd..fbd59bf 100644 --- a/content/adventures/space/intro.fr.lor +++ b/content/adventures/space/intro.fr.lor @@ -19,8 +19,8 @@ Examiner la boîte #opt-ignore // "Ignore it and continue" L'ignorer et continuer -#opt-scan // "Run a deep scan first" -Lancer un scan approfondi d'abord +#opt-scan // "Run a deep scan first|||Fuel reserves insufficient for deep scan" +Lancer un scan approfondi d'abord|||Réserves de carburant insuffisantes pour un scan approfondi #deepscan-init // "Deep scan initiated. Fuel reserves reduced." Scan approfondi lancé. Réserves de carburant réduites. @@ -61,8 +61,8 @@ Ne me dites pas quels mots utiliser pour les boîtes, ARIA. #opt-open-now // "Open it immediately" L'ouvrir immédiatement -#opt-scan-first // "Scan it first" -La scanner d'abord +#opt-scan-first // "Scan it first|||Not enough fuel for a scan" +La scanner d'abord|||Pas assez de carburant pour un scan #opt-poke // "Poke it with a stick" La pousser avec un bâton @@ -208,7 +208,7 @@ Ah, un autre appréciateur de boîtes ! Prenez ceci comme cadeau de ma collectio #captain-wasbox // "The alien WAS the box?" L'extraterrestre ÉTAIT la boîte ? -#alien-intro // I'm Zx'thorp." +#alien-intro // "I'm Zx'thorp." Je suis Zx'thorp. #open-normal // "Inside you find a Nebula Shard and what appears to be a map to more boxes." @@ -238,27 +238,117 @@ J'apprécie les boîtes. Surtout celles avec du bon butin. #opt-rare-box // "Ask about the galaxy's rarest box" Demander quelle est la boîte la plus rare de la galaxie -#alien-singularity // "The Singularity Box. It contains everything and nothing. Also a coupon." -La Boîte Singulière. Elle contient tout et rien. Et aussi un coupon. - #opt-trade // "Trade items with Zx'thorp" Échanger des objets avec Zx'thorp -#alien-trade // "I have a Space Helmet for you. In exchange, I want your sense of wonder." -J'ai un Casque Spatial pour vous. En échange, je veux votre sens de l'émerveillement. - -#captain-deal // "Deal. Wait--" -Marché. Attendez-- - #opt-contest // "Challenge the alien to a box-opening contest" Défier l'extraterrestre dans un concours d'ouverture de boîtes +#alien-singularity // "The Singularity Box. It contains everything and nothing. Also a coupon." +La Boîte Singulière. Elle contient tout et rien. Et aussi un coupon. + +#captain-coupon // "A coupon? For what?" +Un coupon ? Pour quoi ? + +#alien-coupon-answer // "For another Singularity Box. It's boxes all the way down." +Pour une autre Boîte Singulière. Ce sont des boîtes jusqu'au bout. + +#captain-boxes-inside // "You're saying the universe is just boxes inside boxes?" +Vous dites que l'univers n'est qu'une boîte dans des boîtes ? + +#alien-getting-it // "Now you're getting it, Captain." +Vous commencez à comprendre, Capitaine. + +#ai-existential // "Commander, I'm detecting a slight existential crisis in your vitals." +Commandant, je détecte une légère crise existentielle dans vos signes vitaux. + +#captain-fine // "I'm fine, ARIA. Just rethinking everything I know about reality." +Ça va, ARIA. Je remets juste en question tout ce que je sais sur la réalité. + +#alien-trade-offer // "I have a Space Helmet for you. In exchange, I want... a story." +J'ai un Casque Spatial pour vous. En échange, je veux... une histoire. + +#captain-story // "A story?" +Une histoire ? + +#alien-first-box // "Tell me about the first box you ever opened." +Racontez-moi la première boîte que vous avez ouverte. + +#captain-first-box-story // "It was small. Cardboard. My parents gave it to me. Inside was a toy rocket ship." +Elle était petite. En carton. Mes parents me l'avaient offerte. À l'intérieur, il y avait une fusée jouet. + +#alien-pause // "..." +... + +#alien-beautiful-trade // "That's the most beautiful thing I've ever heard." +C'est la plus belle chose que j'aie jamais entendue. + +#alien-gives-helmet // "The alien removes its helmet and places it gently in your hands. Its eyes -- all seven of them -- are glistening." +L'extraterrestre retire son casque et le place délicatement dans vos mains. Ses yeux -- les sept -- brillent. + +#captain-crying // "Are you... crying?" +Vous... pleurez ? + +#alien-appreciation // "We don't cry. We leak appreciation fluid. It's different." +Nous ne pleurons pas. Nous sécrétons du fluide d'appréciation. C'est différent. + #alien-dare // "You dare? No one out-opens Zx'thorp!" Vous osez ? Personne ne surpasse Zx'thorp à l'ouverture ! #alien-contest // "...fine. Best of three. You open first." ...très bien. Au meilleur des trois. Vous ouvrez en premier. +#opt-confident // "Open with confidence" +Ouvrir avec assurance + +#opt-flair // "Open with theatrical flair" +Ouvrir avec panache + +#flair-spin // "You crack your knuckles. You stretch your fingers. You do a little spin." +Vous faites craquer vos doigts. Vous étirez vos mains. Vous faites une petite pirouette. + +#captain-watch // "Watch and learn, Zx'thorp." +Regardez et apprenez, Zx'thorp. + +#flair-confetti // "You open the box with a flourish, confetti exploding from inside. Wait -- you didn't put confetti in there." +Vous ouvrez la boîte avec un geste théâtral, des confettis explosent de l'intérieur. Attendez -- vous n'avez pas mis de confettis dedans. + +#alien-score-flair // "Theatrical. I approve. 8 out of 10." +Théâtral. J'approuve. 8 sur 10. + +#ai-confetti // "Commander, where did the confetti come from?" +Commandant, d'où viennent les confettis ? + +#captain-heart // "From the heart, ARIA. From the heart." +Du cœur, ARIA. Du cœur. + +#contest-open // "You grip the box firmly and open it in one clean motion." +Vous saisissez la boîte fermement et l'ouvrez d'un geste net. + +#alien-score // "Clean technique. 7 out of 10." +Technique propre. 7 sur 10. + +#alien-produces // "Zx'thorp produces a box from somewhere. You try not to think about where." +Zx'thorp sort une boîte de quelque part. Vous essayez de ne pas penser d'où. + +#alien-opens // "The alien opens it using three of its tentacles simultaneously. The lid flies off, does a triple backflip, and lands perfectly back on the box." +L'extraterrestre l'ouvre avec trois de ses tentacules simultanément. Le couvercle s'envole, fait un triple salto arrière et atterrit parfaitement sur la boîte. + +#captain-impossible // "That's... that's not even possible." +C'est... c'est même pas possible. + +#alien-score-2 // "10 out of 10. I win." +10 sur 10. Je gagne. + +#ai-correct // "I'm afraid the alien is correct, Commander. That was objectively superior box-opening." +Je crains que l'extraterrestre ait raison, Commandant. C'était objectivement une ouverture de boîte supérieure. + +#captain-rematch // "Rematch. One day. I'll be ready." +Revanche. Un jour. Je serai prêt. + +#alien-waiting // "I look forward to it, Captain. Across the stars, I'll be waiting. With boxes." +J'ai hâte, Capitaine. À travers les étoiles, je vous attendrai. Avec des boîtes. + #explore-course // "Setting course for the nearest box. ETA: approximately one dramatic pause." Cap vers la boîte la plus proche. Arrivée estimée : environ une pause dramatique. @@ -274,20 +364,53 @@ La grande semble contenir les deux autres. Ce sont des boîtes jusqu'au bout. #opt-big // "Open the biggest box first" Ouvrir la plus grande boîte en premier +#opt-all // "Open all three at once|||Not enough fuel for maximum box velocity" +Ouvrir les trois en même temps|||Pas assez de carburant pour la vitesse maximale de boîte + +#opt-happy // "Leave them orbiting, they seem happy" +Les laisser en orbite, elles ont l'air heureuses + #big-open // "You open the biggest box. Inside: two medium boxes and a note." Vous ouvrez la plus grande boîte. À l'intérieur : deux boîtes moyennes et un mot. #big-note // "The note reads: \"Congratulations! You've found the Box Nebula. Population: boxes.\"" Le mot dit : \"Félicitations ! Vous avez trouvé la Nébuleuse des Boîtes. Population : des boîtes.\" -#opt-all // "Open all three at once" -Ouvrir les trois en même temps +#captain-nebula // "There's a whole nebula of boxes?" +Il y a une nébuleuse entière de boîtes ? + +#ai-billion // "Scanners confirm it, Commander. Approximately 4.7 billion boxes, all orbiting a supermassive box." +Les scanners confirment, Commandant. Environ 4,7 milliards de boîtes, toutes en orbite autour d'une boîte supermassive. + +#opt-deeper // "We must go deeper" +Il faut aller plus loin + +#opt-enough // "We've seen enough boxes for one day" +On a vu assez de boîtes pour aujourd'hui + +#deeper-open // "You open the two medium boxes. Each contains two smaller boxes." +Vous ouvrez les deux boîtes moyennes. Chacune contient deux boîtes plus petites. + +#captain-how-many // "ARIA, how many boxes is this now?" +ARIA, ça fait combien de boîtes maintenant ? + +#ai-crashed // "I've lost count, Commander. My box-tracking subroutine has crashed." +J'ai perdu le compte, Commandant. Mon sous-programme de suivi de boîtes a planté. + +#captain-count // "Then let the boxes count themselves." +Alors laissons les boîtes se compter elles-mêmes. + +#ai-not-how // "...that's not how boxes work, Commander." +...ce n'est pas comme ça que les boîtes fonctionnent, Commandant. + +#captain-should-be // "Maybe it should be." +Peut-être que ça devrait l'être. #captain-velocity // "All three, ARIA. Maximum box velocity." Les trois, ARIA. Vitesse maximale de boîte. -#ai-enthusiasm // "That's not a real measurement, but I admire your enthusiasm." -Ce n'est pas une vraie mesure, mais j'admire votre enthousiasme. +#ai-enthusiasm // "That's not a real measurement, but I admire your enthusiasm. Fuel reserves depleted for the maneuver." +Ce n'est pas une vraie mesure, mais j'admire votre enthousiasme. Réserves de carburant épuisées pour la manœuvre. #all-open // "All three boxes burst open simultaneously. The contents mix together in zero gravity." Les trois boîtes s'ouvrent simultanément. Le contenu se mélange en apesanteur. @@ -298,8 +421,14 @@ Commandant, les objets forment... une plus grande boîte. #captain-ofcourse // "Of course they are." Évidemment. -#opt-happy // "Leave them orbiting, they seem happy" -Les laisser en orbite, elles ont l'air heureuses +#ai-proud // "A bigger, better box. It's vibrating at a frequency I've never seen. I think it's... proud of itself." +Une plus grande, meilleure boîte. Elle vibre à une fréquence que je n'ai jamais vue. Je crois qu'elle est... fière d'elle-même. + +#captain-everything // "A proud box. Now I've seen everything." +Une boîte fière. Maintenant j'ai tout vu. + +#ai-doubt // "Commander, I doubt that very much." +Commandant, j'en doute fortement. #captain-orbit // "Let them orbit in peace." Laissons-les orbiter en paix. @@ -307,9 +436,18 @@ Laissons-les orbiter en paix. #ai-philosophical // "A surprisingly philosophical choice, Commander." Un choix étonnamment philosophique, Commandant. -#ai-happy // "The boxes seem to orbit faster. I think they're happy." +#ai-happy-boxes // "The boxes seem to orbit faster. I think they're happy." Les boîtes semblent orbiter plus vite. Je crois qu'elles sont heureuses. +#captain-best-box // "See? Sometimes the best box is the one you don't open." +Vous voyez ? Parfois la meilleure boîte est celle qu'on n'ouvre pas. + +#ai-wisest // "I'm going to write that down. That might be the wisest thing you've ever said." +Je vais noter ça. C'est peut-être la chose la plus sage que vous ayez jamais dite. + +#captain-used-to-it // "Don't get used to it." +N'y prenez pas goût. + #ending-complete // "Adventure complete. Updating ship's log." Aventure terminée. Mise à jour du journal de bord. diff --git a/content/adventures/space/intro.lor b/content/adventures/space/intro.lor index a1108f0..01180c8 100644 --- a/content/adventures/space/intro.lor +++ b/content/adventures/space/intro.lor @@ -29,7 +29,7 @@ beat Intro -> InvestigateBox Ignore it and continue #opt-ignore -> IgnoreBox - Run a deep scan first #opt-scan if fuel > 20 + Run a deep scan first|||Fuel reserves insufficient for deep scan #opt-scan if fuel > 20 fuel -= 20 -> DeepScan @@ -57,7 +57,7 @@ beat InvestigateBox choice Open it immediately #opt-open-now -> OpenSpaceBox - Scan it first #opt-scan-first if fuel > 10 + Scan it first|||Not enough fuel for a scan #opt-scan-first if fuel > 10 fuel -= 10 -> ScanThenOpen Poke it with a stick #opt-poke @@ -73,23 +73,23 @@ beat BoxWhisperer captain: I'm not doing anything, ARIA. I'm just listening. #captain-listening ai: The box has shared a direct route to its home system. No fuel cost. It's folding space around us like... #ai-folding captain: Like folding a box? #captain-folding - ai: I was going to say \"like origami,\" but yes. Like folding a box. #ai-origami + ai: I was going to say "like origami," but yes. Like folding a box. #ai-origami trustAlien = true discovered += 1 -> OpenSpaceBox beat PokeBox You extend the ship's robotic arm and gently poke the box. #poke-arm - The box rotates 90 degrees and reveals a label: \"THIS SIDE UP\" #poke-label - ai: Commander, I don't think boxes in zero gravity have an \"up\". #ai-gravity + The box rotates 90 degrees and reveals a label: "THIS SIDE UP" #poke-label + ai: Commander, I don't think boxes in zero gravity have an "up". #ai-gravity captain: Maybe the box defines its own reality. #captain-reality ai: That's... philosophically concerning. #ai-philosophy -> OpenSpaceBox beat ScanThenOpen - ai: Scan reveals the box contains crystallized starlight and something called a \"Nebula Shard\". #scan-contents + ai: Scan reveals the box contains crystallized starlight and something called a "Nebula Shard". #scan-contents ai: Also what appears to be a very small, very angry alien. #scan-alien - captain: Define \"very small\". #captain-small + captain: Define "very small". #captain-small ai: Approximately the size of a box. Commander, I think the alien IS a box. #ai-alienbox -> OpenSpaceBox @@ -132,7 +132,7 @@ beat LeaveForGood ai: I hope you're happy, Commander. #ai-happy captain: I am. No weird space boxes for me today. #captain-happy ai: Incoming transmission. It's... from the box. #ai-transmission - ai: It says \"you'll be back. they always come back.\" #ai-message + ai: It says "you'll be back. they always come back." #ai-message captain: That's ominous. I love it. #captain-ominous -> Ending @@ -158,20 +158,72 @@ beat AlienEncounter alien: I've been collecting boxes across the galaxy for centuries. #alien-collecting alien: Most species open them. Very few appreciate them. #alien-appreciate captain: I appreciate boxes. Especially ones with good loot. #captain-loot - alien: \"Loot.\" What a crude word for cosmic treasures. #alien-crude + alien: "Loot." What a crude word for cosmic treasures. #alien-crude choice Ask about the galaxy's rarest box #opt-rare-box - alien: The Singularity Box. It contains everything and nothing. Also a coupon. #alien-singularity - -> Ending + -> RareBoxStory Trade items with Zx'thorp #opt-trade - alien: I have a Space Helmet for you. In exchange, I want your sense of wonder. #alien-trade - captain: Deal. Wait-- #captain-deal - -> Ending + -> AlienTrade Challenge the alien to a box-opening contest #opt-contest - alien: You dare? No one out-opens Zx'thorp! #alien-dare - alien: ...fine. Best of three. You open first. #alien-contest - -> Ending + -> BoxContest + +beat RareBoxStory + alien: The Singularity Box. It contains everything and nothing. Also a coupon. #alien-singularity + captain: A coupon? For what? #captain-coupon + alien: For another Singularity Box. It's boxes all the way down. #alien-coupon-answer + captain: You're saying the universe is just boxes inside boxes? #captain-boxes-inside + alien: Now you're getting it, Captain. #alien-getting-it + ai: Commander, I'm detecting a slight existential crisis in your vitals. #ai-existential + captain: I'm fine, ARIA. Just rethinking everything I know about reality. #captain-fine + -> Ending + +beat AlienTrade + alien: I have a Space Helmet for you. In exchange, I want... a story. #alien-trade-offer + captain: A story? #captain-story + alien: Tell me about the first box you ever opened. #alien-first-box + captain: It was small. Cardboard. My parents gave it to me. Inside was a toy rocket ship. #captain-first-box-story + alien: ... #alien-pause + alien: That's the most beautiful thing I've ever heard. #alien-beautiful-trade + The alien removes its helmet and places it gently in your hands. Its eyes -- all seven of them -- are glistening. #alien-gives-helmet + captain: Are you... crying? #captain-crying + alien: We don't cry. We leak appreciation fluid. It's different. #alien-appreciation + -> Ending + +beat BoxContest + alien: You dare? No one out-opens Zx'thorp! #alien-dare + alien: ...fine. Best of three. You open first. #alien-contest + + choice + Open with confidence #opt-confident + -> ContestRoundOne + Open with theatrical flair #opt-flair + -> ContestFlair + +beat ContestFlair + markSecretBranch("space_box_flair") + You crack your knuckles. You stretch your fingers. You do a little spin. #flair-spin + captain: Watch and learn, Zx'thorp. #captain-watch + You open the box with a flourish, confetti exploding from inside. Wait -- you didn't put confetti in there. #flair-confetti + alien: Theatrical. I approve. 8 out of 10. #alien-score-flair + ai: Commander, where did the confetti come from? #ai-confetti + captain: From the heart, ARIA. From the heart. #captain-heart + -> ContestAlienTurn + +beat ContestRoundOne + You grip the box firmly and open it in one clean motion. #contest-open + alien: Clean technique. 7 out of 10. #alien-score + -> ContestAlienTurn + +beat ContestAlienTurn + Zx'thorp produces a box from somewhere. You try not to think about where. #alien-produces + The alien opens it using three of its tentacles simultaneously. The lid flies off, does a triple backflip, and lands perfectly back on the box. #alien-opens + captain: That's... that's not even possible. #captain-impossible + alien: 10 out of 10. I win. #alien-score-2 + ai: I'm afraid the alien is correct, Commander. That was objectively superior box-opening. #ai-correct + captain: Rematch. One day. I'll be ready. #captain-rematch + alien: I look forward to it, Captain. Across the stars, I'll be waiting. With boxes. #alien-waiting + -> Ending beat SpaceExploration ai: Setting course for the nearest box. ETA: approximately one dramatic pause. #explore-course @@ -182,22 +234,54 @@ beat SpaceExploration choice Open the biggest box first #opt-big - You open the biggest box. Inside: two medium boxes and a note. #big-open - The note reads: \"Congratulations! You've found the Box Nebula. Population: boxes.\" #big-note - -> Ending - Open all three at once #opt-all - captain: All three, ARIA. Maximum box velocity. #captain-velocity - ai: That's not a real measurement, but I admire your enthusiasm. #ai-enthusiasm - All three boxes burst open simultaneously. The contents mix together in zero gravity. #all-open - ai: Commander, the items are forming... a bigger box. #ai-biggerbox - captain: Of course they are. #captain-ofcourse - -> Ending + -> BigBox + Open all three at once|||Not enough fuel for maximum box velocity #opt-all if fuel >= 30 + fuel -= 30 + -> AllBoxes Leave them orbiting, they seem happy #opt-happy - captain: Let them orbit in peace. #captain-orbit - ai: A surprisingly philosophical choice, Commander. #ai-philosophical - ai: The boxes seem to orbit faster. I think they're happy. #ai-happy + -> HappyBoxes + +beat BigBox + You open the biggest box. Inside: two medium boxes and a note. #big-open + The note reads: "Congratulations! You've found the Box Nebula. Population: boxes." #big-note + captain: There's a whole nebula of boxes? #captain-nebula + ai: Scanners confirm it, Commander. Approximately 4.7 billion boxes, all orbiting a supermassive box. #ai-billion + + choice + We must go deeper #opt-deeper + -> GoDeeper + We've seen enough boxes for one day #opt-enough -> Ending +beat GoDeeper + You open the two medium boxes. Each contains two smaller boxes. #deeper-open + captain: ARIA, how many boxes is this now? #captain-how-many + ai: I've lost count, Commander. My box-tracking subroutine has crashed. #ai-crashed + captain: Then let the boxes count themselves. #captain-count + ai: ...that's not how boxes work, Commander. #ai-not-how + captain: Maybe it should be. #captain-should-be + -> Ending + +beat AllBoxes + captain: All three, ARIA. Maximum box velocity. #captain-velocity + ai: That's not a real measurement, but I admire your enthusiasm. Fuel reserves depleted for the maneuver. #ai-enthusiasm + All three boxes burst open simultaneously. The contents mix together in zero gravity. #all-open + ai: Commander, the items are forming... a bigger box. #ai-biggerbox + captain: Of course they are. #captain-ofcourse + ai: A bigger, better box. It's vibrating at a frequency I've never seen. I think it's... proud of itself. #ai-proud + captain: A proud box. Now I've seen everything. #captain-everything + ai: Commander, I doubt that very much. #ai-doubt + -> Ending + +beat HappyBoxes + captain: Let them orbit in peace. #captain-orbit + ai: A surprisingly philosophical choice, Commander. #ai-philosophical + ai: The boxes seem to orbit faster. I think they're happy. #ai-happy-boxes + captain: See? Sometimes the best box is the one you don't open. #captain-best-box + ai: I'm going to write that down. That might be the wisest thing you've ever said. #ai-wisest + captain: Don't get used to it. #captain-used-to-it + -> Ending + beat Ending ai: Adventure complete. Updating ship's log. #ending-complete ai: Boxes encountered: $discovered. Box-related existential crises: 1. #ending-log diff --git a/content/data/boxes.json b/content/data/boxes.json index 6fe6aa6..7e094fd 100644 --- a/content/data/boxes.json +++ b/content/data/boxes.json @@ -238,7 +238,6 @@ "rollCount": 1, "entries": [ {"itemDefinitionId": "meta_completion", "weight": 3}, - {"itemDefinitionId": "meta_chat", "weight": 3}, {"itemDefinitionId": "meta_crafting", "weight": 3}, {"itemDefinitionId": "meta_extended_colors", "weight": 3}, {"itemDefinitionId": "box_meta_resources", "weight": 1} diff --git a/content/data/items.json b/content/data/items.json index 0a9df4c..81c9c83 100644 --- a/content/data/items.json +++ b/content/data/items.json @@ -6,7 +6,6 @@ {"id": "meta_resources", "nameKey": "meta.resources", "descriptionKey": "meta.resources.desc", "category": "Meta", "rarity": "Rare", "tags": ["Meta"], "metaUnlock": "ResourcePanel"}, {"id": "meta_stats", "nameKey": "meta.stats", "descriptionKey": "meta.stats.desc", "category": "Meta", "rarity": "Rare", "tags": ["Meta"], "metaUnlock": "StatsPanel"}, {"id": "meta_portrait", "nameKey": "meta.portrait", "descriptionKey": "meta.portrait.desc", "category": "Meta", "rarity": "Epic", "tags": ["Meta"], "metaUnlock": "PortraitPanel"}, - {"id": "meta_chat", "nameKey": "meta.chat", "descriptionKey": "meta.chat.desc", "category": "Meta", "rarity": "Epic", "tags": ["Meta"], "metaUnlock": "ChatPanel"}, {"id": "meta_layout", "nameKey": "meta.layout", "descriptionKey": "meta.layout.desc", "category": "Meta", "rarity": "Legendary", "tags": ["Meta"], "metaUnlock": "FullLayout"}, {"id": "meta_shortcuts", "nameKey": "meta.shortcuts", "descriptionKey": "meta.shortcuts.desc", "category": "Meta", "rarity": "Rare", "tags": ["Meta"], "metaUnlock": "KeyboardShortcuts"}, {"id": "meta_animation", "nameKey": "meta.animation", "descriptionKey": "meta.animation.desc", "category": "Meta", "rarity": "Uncommon", "tags": ["Meta"], "metaUnlock": "BoxAnimation"}, diff --git a/content/strings/en.json b/content/strings/en.json index e79be37..f11faf4 100644 --- a/content/strings/en.json +++ b/content/strings/en.json @@ -19,6 +19,7 @@ "action.appearance": "Change appearance", "action.save": "Save", "action.quit": "Return to menu", + "action.new": "NEW", "prompt.name": "What is your name, brave box-opener?", "prompt.choose_action": "What would you like to do?", @@ -115,7 +116,6 @@ "meta.resources": "Characteristics Panel", "meta.stats": "Stats Panel", "meta.portrait": "Portrait Panel", - "meta.chat": "Chat Panel", "meta.layout": "Full Layout Mode", "meta.shortcuts": "Keyboard Shortcuts", "meta.animation": "Box Opening Animation", @@ -300,8 +300,6 @@ "lore.name_9": "Fragment: The Manual", "lore.name_10": "Fragment: Schrödinger", - "log.title": "Event Log", - "cookie.1": "A box within a box is still a box.", "cookie.2": "ERROR: This cookie contains no fortune. Please try again.", "cookie.3": "You will open many boxes. This prediction has a 100% accuracy rate.", @@ -431,6 +429,7 @@ "adventure.none_available": "No adventures available yet. Keep opening boxes!", "adventure.coming_soon": "Adventure '{0}' is coming soon! The boxes are still being assembled.", "adventure.done": "Done", + "adventure.unavailable": "Unavailable", "adventure.unlocked": "🎉 New adventure unlocked! Discover '{0}' in the adventure menu!", "adventure.name.Space": "Starbound", "adventure.name.Medieval": "Castle Cardboard", @@ -442,6 +441,27 @@ "adventure.name.Microscopic": "Cell Division", "adventure.name.DarkFantasy": "Ashen Wastes", "adventure.name.Destiny": "Gallery of Echoes", + + "character.captain_nova": "Captain Nova", + "character.aria": "ARIA", + "character.zxthorp": "Zx'thorp", + "character.sir_boxalot": "Sir Boxalot", + "character.malkith": "Malkith", + "character.blackbeard_the_unboxable": "Blackbeard the Unboxable", + "character.linu": "Linu", + "character.sandrea": "Sandrea", + "character.samuel": "Samuel", + "character.mordecai_the_grim": "Mordecai the Grim", + "character.pierrick": "Pierrick", + "character.grug": "Grug", + "character.duncan": "Duncan", + "character.chenda": "Chenda", + "character.farah": "Farah", + "character.dr._quantum": "Dr. Quantum", + "character.the_box_entity": "The Box Entity", + "character.dr._cellina": "Dr. Cellina", + "character.mitochondria_mike": "Mitochondria Mike", + "character.the_box": "The Box", "ui.inventory": "Inventory", "stats.boxes_opened": "Boxes Opened", "stats.title": "Stats", @@ -481,7 +501,6 @@ "meta.resources.desc": "Displays your character's characteristics (health, mana, etc.).", "meta.stats.desc": "Shows your progression stats and character attributes.", "meta.portrait.desc": "Displays your character's visual appearance.", - "meta.chat.desc": "Shows an event log of recent actions.", "meta.layout.desc": "Arranges all panels into a full dashboard layout.", "meta.shortcuts.desc": "Enables keyboard shortcuts for quick actions.", "meta.animation.desc": "Adds opening animations when unboxing.", diff --git a/content/strings/fr.json b/content/strings/fr.json index e6dc937..ce6bab5 100644 --- a/content/strings/fr.json +++ b/content/strings/fr.json @@ -19,6 +19,7 @@ "action.appearance": "Changer d'apparence", "action.save": "Sauvegarder", "action.quit": "Retourner au menu", + "action.new": "NOUVEAU", "prompt.name": "Quel est ton nom, brave ouvreur de boîtes ?", "prompt.choose_action": "Que veux-tu faire ?", @@ -115,7 +116,6 @@ "meta.resources": "Panneau de caractéristiques", "meta.stats": "Panneau de statistiques", "meta.portrait": "Panneau portrait", - "meta.chat": "Panneau de discussion", "meta.layout": "Mise en page complète", "meta.shortcuts": "Raccourcis clavier", "meta.animation": "Animation d'ouverture de boîte", @@ -300,8 +300,6 @@ "lore.name_9": "Fragment : Le Manuel", "lore.name_10": "Fragment : Schrödinger", - "log.title": "Journal d'événements", - "cookie.1": "Une boîte dans une boîte reste une boîte.", "cookie.2": "ERREUR : Ce cookie ne contient aucune fortune. Réessayez.", "cookie.3": "Vous ouvrirez beaucoup de boîtes. Cette prédiction a un taux de précision de 100%.", @@ -431,6 +429,7 @@ "adventure.none_available": "Aucune aventure disponible. Continue à ouvrir des boîtes !", "adventure.coming_soon": "L'aventure '{0}' arrive bientôt ! Les boîtes sont encore en cours d'assemblage.", "adventure.done": "Terminée", + "adventure.unavailable": "Indisponible", "adventure.unlocked": "🎉 Nouvelle aventure débloquée ! Découvre '{0}' dans « Partir à l'aventure » !", "adventure.name.Space": "Odyssée stellaire", "adventure.name.Medieval": "Château Carton", @@ -442,6 +441,28 @@ "adventure.name.Microscopic": "Division cellulaire", "adventure.name.DarkFantasy": "Terres Cendrées", "adventure.name.Destiny": "Galerie des Échos", + + "character.captain_nova": "Capitaine Nova", + "character.aria": "ARIA", + "character.zxthorp": "Zx'thorp", + "character.sir_boxalot": "Sire Boîtalot", + "character.malkith": "Malkith", + "character.blackbeard_the_unboxable": "Barbe-Noire l'Inouvrable", + "character.linu": "Linu", + "character.sandrea": "Sandrea", + "character.samuel": "Samuel", + "character.mordecai_the_grim": "Mordecai le Sinistre", + "character.pierrick": "Pierrick", + "character.grug": "Grug", + "character.duncan": "Duncan", + "character.chenda": "Chenda", + "character.farah": "Farah", + "character.dr._quantum": "Dr. Quantum", + "character.the_box_entity": "L'Entité Boîte", + "character.dr._cellina": "Dr. Cellina", + "character.mitochondria_mike": "Mike Mitochondrie", + "character.the_box": "La Boîte", + "ui.inventory": "Inventaire", "stats.boxes_opened": "Boîtes ouvertes", "stats.title": "Stats", @@ -481,7 +502,6 @@ "meta.resources.desc": "Affiche les caractéristiques de ton personnage (santé, mana, etc.).", "meta.stats.desc": "Affiche ta progression et les attributs de ton personnage.", "meta.portrait.desc": "Affiche l'apparence visuelle de ton personnage.", - "meta.chat.desc": "Affiche un journal des événements récents.", "meta.layout.desc": "Organise tous les panneaux en tableau de bord complet.", "meta.shortcuts.desc": "Active les raccourcis clavier pour des actions rapides.", "meta.animation.desc": "Ajoute des animations d'ouverture de boîtes.", diff --git a/src/OpenTheBox/Adventures/AdventureEngine.cs b/src/OpenTheBox/Adventures/AdventureEngine.cs index 567815e..1280327 100644 --- a/src/OpenTheBox/Adventures/AdventureEngine.cs +++ b/src/OpenTheBox/Adventures/AdventureEngine.cs @@ -190,7 +190,16 @@ public sealed class AdventureEngine private void HandleDialogue(Loreline.Interpreter.Dialogue dialogue) { - _renderer.ShowAdventureDialogue(dialogue.Character, dialogue.Text); + // Translate character name if a localization key exists + string? displayName = dialogue.Character; + if (displayName is not null) + { + string key = $"character.{displayName.ToLowerInvariant().Replace(" ", "_").Replace("'", "")}"; + string localized = _loc.Get(key); + if (!localized.StartsWith("[MISSING:")) + displayName = localized; + } + _renderer.ShowAdventureDialogue(displayName, dialogue.Text); _renderer.WaitForKeyPress(); dialogue.Callback(); } @@ -211,7 +220,8 @@ public sealed class AdventureEngine } else { - options.Add($"(unavailable) {text}"); + string prefix = hint ?? _loc.Get("adventure.unavailable"); + options.Add($"({prefix}) {text}"); hints.Add(hint); } } diff --git a/src/OpenTheBox/Core/Enums/UIFeature.cs b/src/OpenTheBox/Core/Enums/UIFeature.cs index 97d5931..f16a02c 100644 --- a/src/OpenTheBox/Core/Enums/UIFeature.cs +++ b/src/OpenTheBox/Core/Enums/UIFeature.cs @@ -28,9 +28,6 @@ public enum UIFeature /// Phase 6: ASCII art portrait reflecting equipped cosmetics. PortraitPanel, - /// Phase 6: Chat panel for NPC dialogues and narrative events. - ChatPanel, - /// Phase 8: Complete multi-panel layout with all UI elements organized. FullLayout, diff --git a/src/OpenTheBox/Core/GameState.cs b/src/OpenTheBox/Core/GameState.cs index 051219b..23494c5 100644 --- a/src/OpenTheBox/Core/GameState.cs +++ b/src/OpenTheBox/Core/GameState.cs @@ -41,12 +41,6 @@ public sealed class GameState public HashSet AvailableTextColors { get; set; } = []; public List ActiveCraftingJobs { get; set; } = []; - /// - /// In-memory event log shown in the ChatPanel (not persisted to save). - /// - [System.Text.Json.Serialization.JsonIgnore] - public List EventLog { get; set; } = []; - /// /// Returns the current value of a resource, or 0 if the resource is not tracked. /// diff --git a/src/OpenTheBox/Program.cs b/src/OpenTheBox/Program.cs index 342039c..33b32b1 100644 --- a/src/OpenTheBox/Program.cs +++ b/src/OpenTheBox/Program.cs @@ -391,7 +391,12 @@ public static class Program actions.Add((_loc.Get("action.inventory"), "inventory")); if (_state.UnlockedAdventures.Count > 0) - actions.Add((_loc.Get("action.adventure"), "adventure")); + { + string adventureLabel = _loc.Get("action.adventure"); + if (_state.CompletedAdventures.Count == 0) + adventureLabel = $"({_loc.Get("action.new")}) {adventureLabel}"; + actions.Add((adventureLabel, "adventure")); + } if (_state.UnlockedCosmetics.Count > 0) actions.Add((_loc.Get("action.appearance"), "appearance")); @@ -503,7 +508,6 @@ public static class Program RefreshRenderer(); var featureLabel = _loc.Get(GetUIFeatureLocKey(uiEvt.Feature)); _renderer.ShowUIFeatureUnlocked(featureLabel); - AddEventLog($"* {featureLabel}"); _renderer.WaitForKeyPress(_loc.Get("prompt.press_key")); break; @@ -524,7 +528,6 @@ public static class Program case ResourceChangedEvent resEvt: var resName = _loc.Get($"resource.{resEvt.Type.ToString().ToLower()}"); _renderer.ShowMessage($"{resName}: {resEvt.OldValue} {UnicodeSupport.Arrow} {resEvt.NewValue}"); - AddEventLog($"{resName}: {resEvt.OldValue} {UnicodeSupport.Arrow} {resEvt.NewValue}"); break; case MessageEvent msgEvt: @@ -542,7 +545,6 @@ public static class Program case AdventureUnlockedEvent advUnlockedEvt: var advName = GetAdventureName(advUnlockedEvt.Theme); _renderer.ShowMessage(_loc.Get("adventure.unlocked", advName)); - AddEventLog($">> {advName}"); break; case AdventureStartedEvent advEvt: @@ -582,10 +584,6 @@ public static class Program { _renderer.ShowLootReveal(allLoot); - // Proposal 6A: Feed loot to the event log - foreach (var (name, rarity, _) in allLoot) - AddEventLog($"+ {name} [{_loc.Get($"rarity.{rarity.ToLower()}")}]"); - // Resource summary removed — characteristics are shown in the dedicated panel } @@ -753,7 +751,6 @@ public static class Program : _loc.Get("inventory.item_used", itemName); _renderer.ShowMessage(usedMsg); _renderer.ShowMessage($"{resName}: {resEvt.OldValue} {UnicodeSupport.Arrow} {resEvt.NewValue}"); - AddEventLog($"{itemName} {UnicodeSupport.Arrow} {resName} {resEvt.OldValue}{UnicodeSupport.Arrow}{resEvt.NewValue}"); break; case MessageEvent msgEvt: _renderer.ShowMessage(_loc.Get(msgEvt.MessageKey, msgEvt.Args ?? [])); @@ -1000,7 +997,6 @@ public static class Program UIFeature.ResourcePanel => "meta.resources", UIFeature.StatsPanel => "meta.stats", UIFeature.PortraitPanel => "meta.portrait", - UIFeature.ChatPanel => "meta.chat", UIFeature.FullLayout => "meta.layout", UIFeature.KeyboardShortcuts => "meta.shortcuts", UIFeature.BoxAnimation => "meta.animation", @@ -1018,18 +1014,6 @@ public static class Program return name.StartsWith("[MISSING:") ? theme.ToString() : name; } - private const int MaxEventLogEntries = 20; - - /// - /// Adds a message to the in-memory event log displayed in the ChatPanel. - /// - private static void AddEventLog(string message) - { - _state.EventLog.Add(message); - if (_state.EventLog.Count > MaxEventLogEntries) - _state.EventLog.RemoveAt(0); - } - private static string GetLocalizedName(string definitionId) { var itemDef = _registry.GetItem(definitionId); diff --git a/src/OpenTheBox/Rendering/Panels/ChatPanel.cs b/src/OpenTheBox/Rendering/Panels/ChatPanel.cs deleted file mode 100644 index 67b23d3..0000000 --- a/src/OpenTheBox/Rendering/Panels/ChatPanel.cs +++ /dev/null @@ -1,45 +0,0 @@ -using OpenTheBox.Localization; -using Spectre.Console; -using Spectre.Console.Rendering; - -namespace OpenTheBox.Rendering.Panels; - -/// -/// Renders a compact event log panel showing recent game events. -/// Replaces the original dialogue-only chat panel with a general-purpose log. -/// -public static class ChatPanel -{ - private const int MaxVisibleMessages = 8; - - /// - /// Builds a renderable event log from a list of recent log messages. - /// - public static IRenderable Render(List logMessages, LocalizationManager? loc = null) - { - var rows = new List(); - - // Show only the most recent messages - var visible = logMessages.Count > MaxVisibleMessages - ? logMessages.Skip(logMessages.Count - MaxVisibleMessages).ToList() - : logMessages; - - if (visible.Count == 0) - { - var emptyText = loc?.Get("craft.panel.empty") ?? "..."; - rows.Add(new Markup($"[dim]{Markup.Escape(emptyText)}[/]")); - } - else - { - foreach (var msg in visible) - { - rows.Add(new Markup($"[dim]{Markup.Escape(msg)}[/]")); - } - } - - var title = loc?.Get("log.title") ?? "Log"; - return new Panel(new Rows(rows)) - .Header($"[bold aqua]{Markup.Escape(title)}[/]") - .Border(BoxBorder.Rounded); - } -} diff --git a/src/OpenTheBox/Rendering/RenderContext.cs b/src/OpenTheBox/Rendering/RenderContext.cs index 16ddd38..6fb3946 100644 --- a/src/OpenTheBox/Rendering/RenderContext.cs +++ b/src/OpenTheBox/Rendering/RenderContext.cs @@ -31,7 +31,6 @@ public sealed class RenderContext public bool HasResourcePanel => Has(UIFeature.ResourcePanel); public bool HasStatsPanel => Has(UIFeature.StatsPanel); public bool HasPortraitPanel => Has(UIFeature.PortraitPanel); - public bool HasChatPanel => Has(UIFeature.ChatPanel); public bool HasFullLayout => Has(UIFeature.FullLayout); public bool HasKeyboardShortcuts => Has(UIFeature.KeyboardShortcuts); public bool HasBoxAnimation => Has(UIFeature.BoxAnimation); diff --git a/src/OpenTheBox/Rendering/RendererFactory.cs b/src/OpenTheBox/Rendering/RendererFactory.cs index 73a90f5..ac72344 100644 --- a/src/OpenTheBox/Rendering/RendererFactory.cs +++ b/src/OpenTheBox/Rendering/RendererFactory.cs @@ -24,7 +24,6 @@ public static class RendererFactory context.HasResourcePanel || context.HasStatsPanel || context.HasPortraitPanel || - context.HasChatPanel || context.HasFullLayout || context.HasKeyboardShortcuts || context.HasBoxAnimation || diff --git a/src/OpenTheBox/Rendering/SpectreRenderer.cs b/src/OpenTheBox/Rendering/SpectreRenderer.cs index 40722d4..335bffa 100644 --- a/src/OpenTheBox/Rendering/SpectreRenderer.cs +++ b/src/OpenTheBox/Rendering/SpectreRenderer.cs @@ -496,9 +496,6 @@ public sealed class SpectreRenderer : IRenderer if (context.HasCraftingPanel) rightItems.Add(CraftingPanel.Render(state, _registry, _loc)); - if (context.HasChatPanel) - rightItems.Add(ChatPanel.Render(state.EventLog, _loc)); - if (context.HasCompletionTracker) rightItems.Add(new Markup($"[bold cyan]{Markup.Escape(_loc.Get("ui.completion", context.CompletionPercent))}[/]")); @@ -547,9 +544,6 @@ public sealed class SpectreRenderer : IRenderer if (context.HasCraftingPanel) AnsiConsole.Write(CraftingPanel.Render(state, _registry, _loc)); - if (context.HasChatPanel) - AnsiConsole.Write(ChatPanel.Render(state.EventLog, _loc)); - if (context.HasCompletionTracker) AnsiConsole.Write(new Rule($"[bold cyan]{Markup.Escape(_loc.Get("ui.completion", context.CompletionPercent))}[/]").RuleStyle("cyan")); } diff --git a/src/OpenTheBox/Simulation/MetaEngine.cs b/src/OpenTheBox/Simulation/MetaEngine.cs index 5c07054..79f418a 100644 --- a/src/OpenTheBox/Simulation/MetaEngine.cs +++ b/src/OpenTheBox/Simulation/MetaEngine.cs @@ -26,7 +26,6 @@ public class MetaEngine "meta_stats", // StatsPanel "meta_resources", // ResourcePanel "meta_portrait", // PortraitPanel - "meta_chat", // ChatPanel "meta_extended_colors", // ExtendedColors "meta_animation", // BoxAnimation "meta_crafting", // CraftingPanel diff --git a/tests/OpenTheBox.Tests/RendererTests.cs b/tests/OpenTheBox.Tests/RendererTests.cs index f2edaa1..c807c95 100644 --- a/tests/OpenTheBox.Tests/RendererTests.cs +++ b/tests/OpenTheBox.Tests/RendererTests.cs @@ -348,60 +348,6 @@ public class InventoryPanelTests } } -public class ChatPanelTests -{ - [Fact] - public void Render_Empty_DoesNotThrow() - { - var result = RenderHelper.RenderToString(ChatPanel.Render([])); - Assert.NotEmpty(result); - } - - [Fact] - public void Render_SingleMessage_DoesNotThrow() - { - var messages = new List { "The door creaks open." }; - var result = RenderHelper.RenderToString(ChatPanel.Render(messages)); - Assert.NotEmpty(result); - } - - [Fact] - public void Render_MultipleMessages_DoesNotThrow() - { - var messages = new List - { - "+ Small Health Potion [Common]", - "★ Text Colors", - "Health: 0 → 10", - "🗺 Starbound" - }; - var result = RenderHelper.RenderToString(ChatPanel.Render(messages)); - Assert.NotEmpty(result); - } - - [Fact] - public void Render_OverflowMessages_ShowsOnlyRecent() - { - var messages = Enumerable.Range(0, 15) - .Select(i => $"Event {i}") - .ToList(); - var result = RenderHelper.RenderToString(ChatPanel.Render(messages)); - Assert.NotEmpty(result); - } - - [Fact] - public void Render_SpecialCharacters_DoesNotThrow() - { - var messages = new List - { - "+ [Boss] item ", - "A [mysterious] voice echoes." - }; - var result = RenderHelper.RenderToString(ChatPanel.Render(messages)); - Assert.NotEmpty(result); - } -} - // ── RenderContext + RendererFactory Tests ──────────────────────────────── public class RenderContextTests @@ -457,7 +403,6 @@ public class RenderContextTests Assert.False(ctx.HasResourcePanel); Assert.False(ctx.HasStatsPanel); Assert.False(ctx.HasPortraitPanel); - Assert.False(ctx.HasChatPanel); Assert.False(ctx.HasFullLayout); Assert.False(ctx.HasKeyboardShortcuts); Assert.False(ctx.HasBoxAnimation); @@ -488,7 +433,6 @@ public class RendererFactoryTests [InlineData(UIFeature.ResourcePanel)] [InlineData(UIFeature.StatsPanel)] [InlineData(UIFeature.PortraitPanel)] - [InlineData(UIFeature.ChatPanel)] [InlineData(UIFeature.FullLayout)] [InlineData(UIFeature.KeyboardShortcuts)] [InlineData(UIFeature.BoxAnimation)] @@ -749,7 +693,6 @@ public class SpectreRendererOutputTests : IDisposable ctx.Unlock(UIFeature.StatsPanel); ctx.Unlock(UIFeature.ResourcePanel); ctx.Unlock(UIFeature.InventoryPanel); - ctx.Unlock(UIFeature.ChatPanel); ctx.Unlock(UIFeature.CompletionTracker); ctx.CompletionPercent = 42; var r = new SpectreRenderer(ctx, _loc); diff --git a/tests/OpenTheBox.Tests/UnitTest1.cs b/tests/OpenTheBox.Tests/UnitTest1.cs index c6b53ed..3ebf6db 100644 --- a/tests/OpenTheBox.Tests/UnitTest1.cs +++ b/tests/OpenTheBox.Tests/UnitTest1.cs @@ -420,7 +420,6 @@ public class ContentValidationTests [UIFeature.ResourcePanel] = "meta.resources", [UIFeature.StatsPanel] = "meta.stats", [UIFeature.PortraitPanel] = "meta.portrait", - [UIFeature.ChatPanel] = "meta.chat", [UIFeature.FullLayout] = "meta.layout", [UIFeature.KeyboardShortcuts] = "meta.shortcuts", [UIFeature.BoxAnimation] = "meta.animation", @@ -1889,6 +1888,29 @@ public class ContentValidationTests } } + // Workstation summary: what each bench can craft + report.AppendLine("## Workstations"); + report.AppendLine(new string('─', 80)); + var recipesByStation = registry.Recipes.Values + .GroupBy(r => r.Workstation) + .OrderBy(g => g.Key.ToString()); + foreach (var stationGroup in recipesByStation) + { + report.AppendLine($" 🔨 {stationGroup.Key}"); + foreach (var recipe in stationGroup.OrderBy(r => r.Id)) + { + var ingredientNames = recipe.Ingredients + .Select(i => registry.Items.TryGetValue(i.ItemDefinitionId, out var iDef) + ? $"{loc.Get(iDef.NameKey)} x{i.Quantity}" + : $"{i.ItemDefinitionId} x{i.Quantity}"); + var resultName = registry.Items.TryGetValue(recipe.Result.ItemDefinitionId, out var rDef) + ? loc.Get(rDef.NameKey) + : recipe.Result.ItemDefinitionId; + report.AppendLine($" {recipe.Id}: {string.Join(" + ", ingredientNames)} → {resultName} x{recipe.Result.Quantity}"); + } + report.AppendLine(); + } + // Orphan check: items with no usage at all report.AppendLine("## Orphan Items (no usage context)"); report.AppendLine(new string('─', 80)); @@ -1903,9 +1925,9 @@ public class ContentValidationTests string reportText = report.ToString(); - // Write snapshot to repo root (tests/snapshots/) so it can be committed - var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..")); - var snapshotDir = Path.Combine(repoRoot, "tests", "snapshots"); + // Write snapshot to tests/snapshots/ relative to the test project file + var testProjectDir = Path.GetDirectoryName(GetThisFilePath())!; + var snapshotDir = Path.Combine(testProjectDir, "..", "snapshots"); Directory.CreateDirectory(snapshotDir); var snapshotPath = Path.Combine(snapshotDir, "item_utility_report.txt"); @@ -1950,4 +1972,6 @@ public class ContentValidationTests if (item.Tags.Contains("Cookie")) count++; return count; } + + private static string GetThisFilePath([System.Runtime.CompilerServices.CallerFilePath] string path = "") => path; } diff --git a/tests/snapshots/item_utility_report.txt b/tests/snapshots/item_utility_report.txt index 26083e2..4f8bc04 100644 --- a/tests/snapshots/item_utility_report.txt +++ b/tests/snapshots/item_utility_report.txt @@ -1,5 +1,5 @@ # Item Utility Report -# Total items: 146 +# Total items: 145 # Total boxes: 31 # Total recipes: 18 @@ -481,7 +481,7 @@ [NO USE] material_wood_nail (Common) — Bois -## Meta (34 items) +## Meta (33 items) ──────────────────────────────────────────────────────────────────────────────── [**] meta_colors (Rare) — Couleurs de texte Loot: box_meta_basics @@ -511,10 +511,6 @@ Loot: box_meta_basics Unlock: PortraitPanel - [**] meta_chat (Epic) — Panneau de discussion - Loot: box_meta_deep - Unlock: ChatPanel - [**] meta_layout (Legendary) — Mise en page complète Loot: box_meta_interface Unlock: FullLayout @@ -610,6 +606,50 @@ [*] meta_stat_wisdom (Rare) — Sagesse Loot: box_meta_mastery +## Workstations +──────────────────────────────────────────────────────────────────────────────── + 🔨 DrawingTable + chart_star_navigation: Coordonnées mystérieuses x1 + Carte stellaire x1 → Clé d'accès au sas x1 + + 🔨 EngineerDesk + engineer_rocket_boots: Short x1 + Titane x1 + Éclat de nébuleuse x2 → Bottes à réaction x1 + + 🔨 EngravingBench + engrave_royal_seal: Blason de chevalier x1 + Parchemin ancien x1 → Sceau royal x1 + + 🔨 Forge + craft_box_cool: Acier x2 + Néon x1 → box_cool x1 + forge_armored_plate: Acier x3 + Fibre de carbone x2 → Armure x1 + forge_carbonfiber_sheet: Fibre de carbone x4 → Fibre de carbone x1 + + 🔨 Foundry + refine_wood: Bois x2 → Bois x1 + + 🔨 Furnace + smelt_bronze_ingot: Bronze x3 → Bronze x1 + smelt_iron_ingot: Fer x3 → Fer x1 + smelt_steel_ingot: Acier x4 → Acier x1 + smelt_titanium_ingot: Titane x5 → Titane x1 + + 🔨 GeneticModStation + splice_glowing_dna: Échantillon de bactérie sentiente x1 + Prion amical (probablement) x1 → Brin d'ADN luminescent x1 + + 🔨 MatterSynthesizer + fuse_cosmic_crystal: Éclat de nébuleuse x2 → Cristal de quasar x1 + + 🔨 Printer3D + craft_box_epic: Titane x2 + Fibre de carbone x1 + Or x1 → box_epic x1 + + 🔨 StasisChamber + preserve_amber: Dent de dinosaure x2 → Pierre d'ambre x1 + + 🔨 TransformationPentacle + enchant_dark_grimoire: Anneau maudit x2 → Grimoire du nécromancien x1 + + 🔨 Workbench + craft_box_ok_tier: Bois x2 + Bronze x1 → box_ok_tier x1 + craft_pilot_glasses: Lunettes de soleil x1 + Bronze x1 + Argent x1 → Lunettes d'aviateur x1 + ## Orphan Items (no usage context) ──────────────────────────────────────────────────────────────────────────────── material_wood_nail (Material, Common)