You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
7.6 KiB
170 lines
7.6 KiB
import chalk from 'chalk' |
|
import prompts from 'prompts' |
|
import { selectRandom } from '../ao-lib/util.js' |
|
import { greenChalk, theAO, theMenu, headerStyle } from './styles.js' |
|
|
|
// Different sets of messages that can be randomly selected from |
|
const welcomeMessages = [ |
|
`You turn a corner and are suddenly back in the halls of ${theAO}.`, |
|
`You make the sign of ${theAO} and are whisked away on a gust of divine wind.`, |
|
`You take a closer look at the folder you are in and realize it is a room.`, |
|
`You draw an alchemical symbol and open a doorway into ${theAO}. You step through.`, |
|
`"Ah, there you are again!" The old man greets you as you step through the portal.`, |
|
`A line of doge-masked worshippers glide by. By the time you exit the trance, you are in ${theAO}. Doge bless.`, |
|
`You spraypaint an ${greenChalk.bold('A')} superimposed on an ${greenChalk.bold('O')} and step through the portal.`, |
|
`You receive a phone call. You answer it. You are in ${theAO}.`, |
|
`You dab fiercely, and when you raise your head, you are in ${theAO}.`, |
|
`A ship arrives and takes you out to sea. The ship sinks and you somehow wash up safely in ${theAO}.`, |
|
`You are reading in the Library when you find a strange book. Whatever you read next in the book is ${theAO}.`, |
|
`You plant a magic seed and it grows into a great tree. Climbing up into its branches, you know ${theAO} is here.`, |
|
`In the late afternoon, a warm sunbeam highlights motes of dust over your book. These motes are ${theAO}.`, |
|
`A black cat crosses your path. Most people wouldn't notice, but you know you have entered the AO.`, |
|
`Dipping your brush in ink, you draw a perfect circle. This is ${theAO}.`, |
|
`You are offered a choice between two pills. However, you have secretly built up an immunity to both pills, and trick your opponent into taking one. Inconceviably, you are in ${theAO}.`, |
|
`A young man with spiky hair and glowing skin appears before you in a halo of light. He guides you to ${theAO}.`, |
|
`Looking for a shortcut, you worm your way through through the hedges, and, after struggling through the brush, emerge into a sunny estate garden. You've found the AO.`, |
|
`You find a small animal burrow dug-out near the riverside. Crawling in, you find a network of caves that lead to ${theAO}.`, |
|
`You receive a handwritten letter in the mail, which reads, in fine calligraphy:, "Dear —, You are in ${theAO}."`, |
|
`An unexpected calm settles over you. The ${greenChalk.bold('AO')} is here: Here is ${theAO}.`, |
|
`You plant a seed, and from that one seed grow many trees. The forest and the tradition of tree-planting are ${theAO}.` |
|
] |
|
const menuMessages = [ |
|
`You see ${theMenu}:`, |
|
`A page of aged paper wafts into your hand. On it is written ${theMenu}:`, |
|
`A minstrel walks by playing a haunting melody, and in its harmonies you hear the refrain of ${theMenu}:`, |
|
`You pick up an apple from a nearby table and take a bite. You suddenly recall the words of ${theMenu}:`, |
|
`With a screeching sound, a page containing ${theMenu} slowly emerges, line-by-line, from a dot-matrix printer:`, |
|
`In the shadows cast in the cavernous space, you see the forms of ${theMenu}:`, |
|
`With a low hum, standing waves appear on the reflecting pool at your feet. Impossibly, they spell out ${theMenu}:`, |
|
`You see a box of candies labeled 'Eat Me'. Why not? you think. You find ${theMenu} printed on the wrapper:`, |
|
`You see an ornate bottle labeled 'Drink Me'. Why not? you think. You take a sip and shrink to the size of a doormouse. Now you can read ${theMenu} scratched into the wainscoating:`, |
|
`Cretaceous jungle plants tower overhead, overgrown from the safari room. The ancient fractals of the branches prefigure the structure of ${theMenu}:`, |
|
] |
|
const exclamationMessages = [ |
|
'Woah there!', |
|
'Shiver me timbers!', |
|
'iNtErEsTiNg!', |
|
'Turing\'s ghost!', |
|
'Frack!', |
|
'Frell!', |
|
'Good grief!', |
|
'With great power comes great responsibility.', |
|
] |
|
const rogerMessages = [ |
|
'You\'ve got it.', |
|
'Aye-aye, captain!', |
|
'The AO provides.', |
|
'Roger.', |
|
'Yokai.' |
|
] |
|
const farewellMessages = [ |
|
'Goodbye!', |
|
'Goodbye! Goodbye! Goodbye...!', |
|
'The AO will always be with you.', |
|
'Please return soon; the AO needs your virtue.', |
|
'The AO will await your return.', |
|
'Doge bless.', |
|
'Please remember the AO throughout your day as a ward against evil.', |
|
'Remember your PrioriTEA™.', |
|
'Know thyself.', |
|
'With great power comes great responsibility.', |
|
'The AO is a state of mind.', |
|
'Go for the low-hanging fruit.', |
|
] |
|
|
|
// Prints a random RPG-style welcome message to contextualize the AO experience and the main menu |
|
export async function welcome() { |
|
const randomWelcomeMessage = selectRandom(welcomeMessages) |
|
const randomMenuMessage = selectRandom(menuMessages) |
|
const welcomeMessage = (' ' + randomWelcomeMessage + ' ' + randomMenuMessage).wordWrap(process.stdout.columns - 2) |
|
// todo: line breaks would be more accurate if there were a function to count the length of a string minus the formatting codes (regex) |
|
// right now the invisible formatting characters are counted so lines are wrapped early |
|
console.log('\n' + welcomeMessage) |
|
|
|
} |
|
|
|
// Returns a random exclamatory remark |
|
export function exclaim() { |
|
return selectRandom(exclamationMessages) |
|
} |
|
|
|
// Returns a random obedient/affirmative remark denoting that a command was executed |
|
export function roger() { |
|
return selectRandom(rogerMessages) |
|
} |
|
|
|
// Returns a random farewell message |
|
export function farewell() { |
|
console.log(chalk.yellow.bold(selectRandom(farewellMessages))) |
|
} |
|
|
|
// Asks the given yes or no answer returns true or false for their response |
|
export async function yesOrNo(prompt = 'Yes or no?', defaultAnswer = true) { |
|
const answer = await prompts({ |
|
type: 'confirm', |
|
name: 'value', |
|
message: prompt, |
|
initial: defaultAnswer |
|
}) |
|
return answer.value || 'ESC' |
|
} |
|
|
|
// Ask the user the given question and returns their textual response |
|
export async function askQuestionText(prompt = 'Please enter a string:', promptOptions = {}) { |
|
let options = { |
|
type: 'text', |
|
name: 'value', |
|
message: prompt |
|
} |
|
Object.assign(options, promptOptions) |
|
const answer = await prompts(options) |
|
return answer.value || false |
|
} |
|
|
|
export async function promptMenu(choices, prompt = 'Please choose:', hint = '(Use arrow keys)', defaultValue = null, warningMessage = null, numbered = false) { |
|
if(prompt !== 'Please choose:') { |
|
prompt = `\n${headerStyle(prompt)}` |
|
} |
|
if(numbered) { |
|
const prependNumber = (num, str) => num + '. ' + str |
|
for(let i = 0; i < choices.length; i++) { |
|
if(typeof choices[i] === 'string') { |
|
choices[i] = prependNumber(i + 1, choices[i]) |
|
} else if(typeof choices[i].title === 'string') { |
|
if(!choices[i].value) { |
|
choices[i].value = choices[i].title |
|
} |
|
choices[i].title = prependNumber(i + 1, choices[i].title) |
|
} |
|
} |
|
} |
|
if(defaultValue && typeof defaultValue !== 'number') { |
|
defaultValue = null |
|
} |
|
const answer = await prompts({ |
|
type: 'select', |
|
name: 'value', |
|
message: prompt, |
|
choices: choices, |
|
hint: hint, |
|
initial: defaultValue, |
|
warn: warningMessage |
|
}) |
|
if(answer && Object.keys(answer).length === 0 && Object.getPrototypeOf(answer) === Object.prototype) { |
|
return false |
|
} |
|
if(typeof answer.value === 'string') { |
|
return answer.value |
|
} |
|
if(!isNaN(answer.value) && (answer.value >= 0 && answer.value < choices.length)) { |
|
const chosenOption = choices[answer.value]?.value || choices[answer.value]?.title || choices[answer.value] |
|
if(isNaN(chosenOption) && !chosenOption) { |
|
return answer.value |
|
} |
|
return chosenOption |
|
} else if(isNaN(answer.value)) { |
|
return answer.value |
|
} |
|
|
|
return false |
|
}
|
|
|