UNPKG

luzosa-cli

Version:

An interactive One Piece quiz game with pirate-themed styling and multiple difficulty levels

407 lines (394 loc) 12 kB
#!/usr/bin/env node import inquirer from "inquirer"; import chalk from "chalk"; import chalkAnimation from "chalk-animation"; import figlet from "figlet"; import gradient from "gradient-string"; // Check for non-interactive mode flag const isNonInteractive = process.argv.includes("--non-interactive"); // Check if running in interactive environment if (!process.stdin.isTTY && !isNonInteractive) { console.log("This CLI tool requires an interactive terminal."); console.log("Please run: npm install -g luzosa-cli && luzosa"); console.log("Or use: luzosa --non-interactive for testing"); process.exit(1); } // Luffy ASCII Art (simple, fits console) const onePieceQuestions = { easy: [ { question: "What is the name of Luffy’s ship?", options: ["Going Merry", "Red Force", "Thousand Sunny", "Moby Dick"], answer: "Thousand Sunny", }, { question: "Who is the navigator of the Straw Hat Pirates?", options: ["Robin", "Nami", "Sanji", "Chopper"], answer: "Nami", }, { question: "What is Luffy’s signature attack?", options: ["Gomu Gomu no Pistol", "Jet Pistol", "Red Hawk", "King Cobra"], answer: "Gomu Gomu no Pistol", }, { question: "Who is the doctor of the Straw Hat crew?", options: ["Usopp", "Chopper", "Brook", "Franky"], answer: "Chopper", }, { question: "Which fruit did Luffy eat?", options: [ "Mera Mera no Mi", "Gomu Gomu no Mi", "Hie Hie no Mi", "Ope Ope no Mi", ], answer: "Gomu Gomu no Mi", }, { question: "Who is the swordsman in the crew?", options: ["Sanji", "Zoro", "Franky", "Jinbe"], answer: "Zoro", }, { question: "What animal is Tony Tony Chopper?", options: ["Monkey", "Dog", "Reindeer", "Cat"], answer: "Reindeer", }, { question: "Which crew is Luffy the captain of?", options: [ "Red Hair Pirates", "Heart Pirates", "Straw Hat Pirates", "Whitebeard Pirates", ], answer: "Straw Hat Pirates", }, { question: "Who is the cook of the Straw Hat Pirates?", options: ["Zoro", "Sanji", "Brook", "Franky"], answer: "Sanji", }, { question: "Who gave Luffy his straw hat?", options: ["Dragon", "Shanks", "Rayleigh", "Ace"], answer: "Shanks", }, ], medium: [ { question: "What is Nico Robin’s Devil Fruit power?", options: [ "Flower-Flower Fruit", "Shadow-Shadow Fruit", "Soul-Soul Fruit", "Clone-Clone Fruit", ], answer: "Flower-Flower Fruit", }, { question: "What is the name of Zoro’s three swords style?", options: ["Santoryu", "Nitoryu", "Ichitoryu", "Zantoryu"], answer: "Santoryu", }, { question: "Who is the current Fleet Admiral of the Marines?", options: ["Akainu", "Aokiji", "Kizaru", "Garp"], answer: "Akainu", }, { question: "What is the real name of Luffy’s Devil Fruit?", options: [ "Gomu Gomu no Mi", "Hito Hito no Mi: Model Nika", "Nika Nika no Mi", "Mythical Gum Fruit", ], answer: "Hito Hito no Mi: Model Nika", }, { question: "Which island was Sanji trained on after the Sabaody Archipelago?", options: [ "Momoiro Island", "Rusukaina", "Karate Island", "Kamabakka Kingdom", ], answer: "Kamabakka Kingdom", }, { question: "Who defeated Gecko Moria?", options: ["Luffy", "Jinbe", "Doflamingo", "Kaido"], answer: "Doflamingo", }, { question: "What is the name of the prison where Ace was held?", options: ["Enies Lobby", "Impel Down", "Marineford", "Punk Hazard"], answer: "Impel Down", }, { question: "Which Yonko was defeated by Luffy in Wano?", options: ["Shanks", "Kaido", "Big Mom", "Blackbeard"], answer: "Kaido", }, { question: "Who is the archaeologist of the Straw Hat crew?", options: ["Brook", "Nami", "Robin", "Franky"], answer: "Robin", }, { question: "Who trained Luffy in Haki during the time skip?", options: ["Shanks", "Dragon", "Rayleigh", "Sabo"], answer: "Rayleigh", }, ], hard: [ { question: "What was the name of the fish-man Arlong's crew?", options: [ "Sun Pirates", "Fish-Man Force", "Arlong Pirates", "Blue Shark Crew", ], answer: "Arlong Pirates", }, { question: "What is the full name of Trafalgar Law?", options: [ "Trafalgar D. Water Law", "Trafalgar Rosinante Law", "Trafalgar D. Rosinante", "Trafalgar Law D.", ], answer: "Trafalgar D. Water Law", }, { question: "What is the name of the sword Enma's previous owner?", options: ["Oden", "Zoro", "Kozuki Toki", "Ryuma"], answer: "Oden", }, { question: "What race does King from the Beast Pirates belong to?", options: ["Giant", "Lunarian", "Skypiean", "Oni"], answer: "Lunarian", }, { question: "What is the name of the ancient weapon that Shirahoshi is?", options: ["Poseidon", "Uranus", "Pluton", "Neptune"], answer: "Poseidon", }, { question: "Who was the first Warlord defeated by Luffy?", options: ["Crocodile", "Moria", "Doflamingo", "Buggy"], answer: "Crocodile", }, { question: "Which scientist created the Pacifistas?", options: ["Vegapunk", "Caesar Clown", "Judge", "Franky"], answer: "Vegapunk", }, { question: "What is the codename of CP0’s strongest agent?", options: ["Lucci", "Spandam", "Blueno", "Jabra"], answer: "Lucci", }, { question: "What title did Luffy get after defeating Doflamingo?", options: [ "Fifth Emperor", "Conqueror", "The Pirate King", "King of Dressrosa", ], answer: "Fifth Emperor", }, { question: "What island was the final Poneglyph found on?", options: ["Zou", "Wano", "Raftel", "Ohara"], answer: "Wano", }, ], }; async function luffyIntro() { return new Promise((resolve) => { // Print One Piece Quiz title with figlet and gradient figlet("One Piece Quiz!", (err, data) => { if (!err) { console.log(gradient.cristal.multiline(data)); } // Animate Luffy's message const animation = chalkAnimation.karaoke( chalk.yellow.bold( "Yohohoho! I am Monkey D. Luffy, and welcome to the Grand One Piece Quiz Adventure!\n" ) + chalk.blue( "Test your knowledge and see if you have what it takes to join the Straw Hat crew!\n" ) ); setTimeout(() => { animation.stop(); console.log(chalk.red.bold("\nLet's set sail!\n")); resolve(); }, 3500); }); }); } async function askQuestion(questionObj, qNum, level) { console.log( chalk.cyan(`\n[${level.toUpperCase()} Q${qNum + 1}] `) + chalk.bold(questionObj.question) ); const { userAnswer } = await inquirer.prompt([ { type: "list", name: "userAnswer", message: chalk.magenta("Choose your answer:"), choices: questionObj.options, }, ]); const correct = userAnswer === questionObj.answer; if (correct) { console.log(chalk.greenBright("Correct! 🍖 Luffy is proud!")); } else { console.log( chalk.redBright("Wrong!") + chalk.yellow(` The right answer was: ${questionObj.answer}`) ); } return { correct, userAnswer }; } async function playLevel(levelName, questions) { let score = 0; let lastQuestion = ""; let lastUserAnswer = ""; for (let i = 0; i < questions.length; i++) { const { correct, userAnswer } = await askQuestion( questions[i], i, levelName ); lastQuestion = questions[i].question; lastUserAnswer = userAnswer; if (correct) score++; console.log(chalk.blueBright(`Current Score: ${score}/${i + 1}`)); } return { score, lastQuestion, lastUserAnswer }; } async function main() { try { await luffyIntro(); let exitGame = false; // Handle Ctrl+C (SIGINT) gracefully let sigintPromptActive = false; process.on("SIGINT", async () => { if (sigintPromptActive) return; // Prevent multiple prompts sigintPromptActive = true; const { exitChoice } = await inquirer.prompt([ { type: "input", name: "exitChoice", message: chalk.yellow( "Do you want to exit? (y/n)\n(Tip: Press Ctrl+C again to force quit immediately.)" ), validate: (input) => { if (!["y", "n", "Y", "N"].includes(input.trim())) { return "Please enter 'y' or 'n'."; } return true; }, }, ]); if (exitChoice.trim().toLowerCase() === "y") { console.log( chalk.yellow("\nThanks for playing! Set sail for more adventures!") ); process.exit(0); } else { sigintPromptActive = false; // Resume the game } }); while (!exitGame) { console.log(chalk.bgBlue.bold("Choose your difficulty, nakama!")); const { level } = await inquirer.prompt([ { type: "list", name: "level", message: chalk.yellow("Select your level:"), choices: [ { name: "Easy (East Blue)", value: "easy" }, { name: "Medium (Grand Line)", value: "medium" }, { name: "Hard (New World)", value: "hard" }, ], }, ]); console.log( chalk.bgMagenta.bold( `\nYou chose: ${level.toUpperCase()}! Get ready for 10 questions!\n` ) ); const { score, lastQuestion, lastUserAnswer } = await playLevel( level, onePieceQuestions[level] ); console.log(chalk.bgYellow.bold("\n--- Quiz Complete! ---")); console.log(chalk.greenBright(`\nYour final score: ${score}/10`)); console.log( chalk.cyanBright("Last question you answered: ") + chalk.white(lastQuestion) ); console.log( chalk.cyanBright("Your answer: ") + chalk.white(lastUserAnswer) ); if (score === 10) { console.log(chalk.bgGreen.bold("\nYou're a true Pirate King! 🏴‍☠️")); } else if (score >= 7) { console.log(chalk.bgBlue.bold("\nYou'd make a great Straw Hat!")); } else { console.log( chalk.bgRed.bold("\nYou might need to study the Grand Line more!") ); // Prompt user if they want to exit or continue const { exitChoice } = await inquirer.prompt([ { type: "input", name: "exitChoice", message: chalk.yellow("You lost! Do you want to exit? (y/n)"), validate: (input) => { if (!["y", "n", "Y", "N"].includes(input.trim())) { return "Please enter 'y' or 'n'."; } return true; }, }, ]); if (exitChoice.trim().toLowerCase() === "y") { exitGame = true; console.log( chalk.yellow("\nThanks for playing! Set sail for more adventures!") ); break; } else { // Continue the loop (play again) continue; } } // If not lost, always thank and break console.log( chalk.yellow("\nThanks for playing! Set sail for more adventures!") ); break; } } catch (error) { console.error("Error running the CLI:", error.message); console.log( "Please ensure you have Node.js 18+ installed and are running in an interactive terminal." ); process.exit(1); } } main();