An interactive command-line interface (CLI) tool to help you install, use, and administer an AO instance.
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

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
}