| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- import type { CompanionBones, Eye, Hat, Species } from './types.js'
- import {
- axolotl,
- blob,
- cactus,
- capybara,
- cat,
- chonk,
- dragon,
- duck,
- ghost,
- goose,
- mushroom,
- octopus,
- owl,
- penguin,
- rabbit,
- robot,
- snail,
- turtle,
- } from './types.js'
- // Each sprite is 5 lines tall, 12 wide (after {E}→1char substitution).
- // Multiple frames per species for idle fidget animation.
- // Line 0 is the hat slot — must be blank in frames 0-1; frame 2 may use it.
- const BODIES: Record<Species, string[][]> = {
- [duck]: [
- [
- ' ',
- ' __ ',
- ' <({E} )___ ',
- ' ( ._> ',
- ' `--´ ',
- ],
- [
- ' ',
- ' __ ',
- ' <({E} )___ ',
- ' ( ._> ',
- ' `--´~ ',
- ],
- [
- ' ',
- ' __ ',
- ' <({E} )___ ',
- ' ( .__> ',
- ' `--´ ',
- ],
- ],
- [goose]: [
- [
- ' ',
- ' ({E}> ',
- ' || ',
- ' _(__)_ ',
- ' ^^^^ ',
- ],
- [
- ' ',
- ' ({E}> ',
- ' || ',
- ' _(__)_ ',
- ' ^^^^ ',
- ],
- [
- ' ',
- ' ({E}>> ',
- ' || ',
- ' _(__)_ ',
- ' ^^^^ ',
- ],
- ],
- [blob]: [
- [
- ' ',
- ' .----. ',
- ' ( {E} {E} ) ',
- ' ( ) ',
- ' `----´ ',
- ],
- [
- ' ',
- ' .------. ',
- ' ( {E} {E} ) ',
- ' ( ) ',
- ' `------´ ',
- ],
- [
- ' ',
- ' .--. ',
- ' ({E} {E}) ',
- ' ( ) ',
- ' `--´ ',
- ],
- ],
- [cat]: [
- [
- ' ',
- ' /\\_/\\ ',
- ' ( {E} {E}) ',
- ' ( ω ) ',
- ' (")_(") ',
- ],
- [
- ' ',
- ' /\\_/\\ ',
- ' ( {E} {E}) ',
- ' ( ω ) ',
- ' (")_(")~ ',
- ],
- [
- ' ',
- ' /\\-/\\ ',
- ' ( {E} {E}) ',
- ' ( ω ) ',
- ' (")_(") ',
- ],
- ],
- [dragon]: [
- [
- ' ',
- ' /^\\ /^\\ ',
- ' < {E} {E} > ',
- ' ( ~~ ) ',
- ' `-vvvv-´ ',
- ],
- [
- ' ',
- ' /^\\ /^\\ ',
- ' < {E} {E} > ',
- ' ( ) ',
- ' `-vvvv-´ ',
- ],
- [
- ' ~ ~ ',
- ' /^\\ /^\\ ',
- ' < {E} {E} > ',
- ' ( ~~ ) ',
- ' `-vvvv-´ ',
- ],
- ],
- [octopus]: [
- [
- ' ',
- ' .----. ',
- ' ( {E} {E} ) ',
- ' (______) ',
- ' /\\/\\/\\/\\ ',
- ],
- [
- ' ',
- ' .----. ',
- ' ( {E} {E} ) ',
- ' (______) ',
- ' \\/\\/\\/\\/ ',
- ],
- [
- ' o ',
- ' .----. ',
- ' ( {E} {E} ) ',
- ' (______) ',
- ' /\\/\\/\\/\\ ',
- ],
- ],
- [owl]: [
- [
- ' ',
- ' /\\ /\\ ',
- ' (({E})({E})) ',
- ' ( >< ) ',
- ' `----´ ',
- ],
- [
- ' ',
- ' /\\ /\\ ',
- ' (({E})({E})) ',
- ' ( >< ) ',
- ' .----. ',
- ],
- [
- ' ',
- ' /\\ /\\ ',
- ' (({E})(-)) ',
- ' ( >< ) ',
- ' `----´ ',
- ],
- ],
- [penguin]: [
- [
- ' ',
- ' .---. ',
- ' ({E}>{E}) ',
- ' /( )\\ ',
- ' `---´ ',
- ],
- [
- ' ',
- ' .---. ',
- ' ({E}>{E}) ',
- ' |( )| ',
- ' `---´ ',
- ],
- [
- ' .---. ',
- ' ({E}>{E}) ',
- ' /( )\\ ',
- ' `---´ ',
- ' ~ ~ ',
- ],
- ],
- [turtle]: [
- [
- ' ',
- ' _,--._ ',
- ' ( {E} {E} ) ',
- ' /[______]\\ ',
- ' `` `` ',
- ],
- [
- ' ',
- ' _,--._ ',
- ' ( {E} {E} ) ',
- ' /[______]\\ ',
- ' `` `` ',
- ],
- [
- ' ',
- ' _,--._ ',
- ' ( {E} {E} ) ',
- ' /[======]\\ ',
- ' `` `` ',
- ],
- ],
- [snail]: [
- [
- ' ',
- ' {E} .--. ',
- ' \\ ( @ ) ',
- ' \\_`--´ ',
- ' ~~~~~~~ ',
- ],
- [
- ' ',
- ' {E} .--. ',
- ' | ( @ ) ',
- ' \\_`--´ ',
- ' ~~~~~~~ ',
- ],
- [
- ' ',
- ' {E} .--. ',
- ' \\ ( @ ) ',
- ' \\_`--´ ',
- ' ~~~~~~ ',
- ],
- ],
- [ghost]: [
- [
- ' ',
- ' .----. ',
- ' / {E} {E} \\ ',
- ' | | ',
- ' ~`~``~`~ ',
- ],
- [
- ' ',
- ' .----. ',
- ' / {E} {E} \\ ',
- ' | | ',
- ' `~`~~`~` ',
- ],
- [
- ' ~ ~ ',
- ' .----. ',
- ' / {E} {E} \\ ',
- ' | | ',
- ' ~~`~~`~~ ',
- ],
- ],
- [axolotl]: [
- [
- ' ',
- '}~(______)~{',
- '}~({E} .. {E})~{',
- ' ( .--. ) ',
- ' (_/ \\_) ',
- ],
- [
- ' ',
- '~}(______){~',
- '~}({E} .. {E}){~',
- ' ( .--. ) ',
- ' (_/ \\_) ',
- ],
- [
- ' ',
- '}~(______)~{',
- '}~({E} .. {E})~{',
- ' ( -- ) ',
- ' ~_/ \\_~ ',
- ],
- ],
- [capybara]: [
- [
- ' ',
- ' n______n ',
- ' ( {E} {E} ) ',
- ' ( oo ) ',
- ' `------´ ',
- ],
- [
- ' ',
- ' n______n ',
- ' ( {E} {E} ) ',
- ' ( Oo ) ',
- ' `------´ ',
- ],
- [
- ' ~ ~ ',
- ' u______n ',
- ' ( {E} {E} ) ',
- ' ( oo ) ',
- ' `------´ ',
- ],
- ],
- [cactus]: [
- [
- ' ',
- ' n ____ n ',
- ' | |{E} {E}| | ',
- ' |_| |_| ',
- ' | | ',
- ],
- [
- ' ',
- ' ____ ',
- ' n |{E} {E}| n ',
- ' |_| |_| ',
- ' | | ',
- ],
- [
- ' n n ',
- ' | ____ | ',
- ' | |{E} {E}| | ',
- ' |_| |_| ',
- ' | | ',
- ],
- ],
- [robot]: [
- [
- ' ',
- ' .[||]. ',
- ' [ {E} {E} ] ',
- ' [ ==== ] ',
- ' `------´ ',
- ],
- [
- ' ',
- ' .[||]. ',
- ' [ {E} {E} ] ',
- ' [ -==- ] ',
- ' `------´ ',
- ],
- [
- ' * ',
- ' .[||]. ',
- ' [ {E} {E} ] ',
- ' [ ==== ] ',
- ' `------´ ',
- ],
- ],
- [rabbit]: [
- [
- ' ',
- ' (\\__/) ',
- ' ( {E} {E} ) ',
- ' =( .. )= ',
- ' (")__(") ',
- ],
- [
- ' ',
- ' (|__/) ',
- ' ( {E} {E} ) ',
- ' =( .. )= ',
- ' (")__(") ',
- ],
- [
- ' ',
- ' (\\__/) ',
- ' ( {E} {E} ) ',
- ' =( . . )= ',
- ' (")__(") ',
- ],
- ],
- [mushroom]: [
- [
- ' ',
- ' .-o-OO-o-. ',
- '(__________)',
- ' |{E} {E}| ',
- ' |____| ',
- ],
- [
- ' ',
- ' .-O-oo-O-. ',
- '(__________)',
- ' |{E} {E}| ',
- ' |____| ',
- ],
- [
- ' . o . ',
- ' .-o-OO-o-. ',
- '(__________)',
- ' |{E} {E}| ',
- ' |____| ',
- ],
- ],
- [chonk]: [
- [
- ' ',
- ' /\\ /\\ ',
- ' ( {E} {E} ) ',
- ' ( .. ) ',
- ' `------´ ',
- ],
- [
- ' ',
- ' /\\ /| ',
- ' ( {E} {E} ) ',
- ' ( .. ) ',
- ' `------´ ',
- ],
- [
- ' ',
- ' /\\ /\\ ',
- ' ( {E} {E} ) ',
- ' ( .. ) ',
- ' `------´~ ',
- ],
- ],
- }
- const HAT_LINES: Record<Hat, string> = {
- none: '',
- crown: ' \\^^^/ ',
- tophat: ' [___] ',
- propeller: ' -+- ',
- halo: ' ( ) ',
- wizard: ' /^\\ ',
- beanie: ' (___) ',
- tinyduck: ' ,> ',
- }
- export function renderSprite(bones: CompanionBones, frame = 0): string[] {
- const frames = BODIES[bones.species]
- const body = frames[frame % frames.length]!.map(line =>
- line.replaceAll('{E}', bones.eye),
- )
- const lines = [...body]
- // Only replace with hat if line 0 is empty (some fidget frames use it for smoke etc)
- if (bones.hat !== 'none' && !lines[0]!.trim()) {
- lines[0] = HAT_LINES[bones.hat]
- }
- // Drop blank hat slot — wastes a row in the Card and ambient sprite when
- // there's no hat and the frame isn't using it for smoke/antenna/etc.
- // Only safe when ALL frames have blank line 0; otherwise heights oscillate.
- if (!lines[0]!.trim() && frames.every(f => !f[0]!.trim())) lines.shift()
- return lines
- }
- export function spriteFrameCount(species: Species): number {
- return BODIES[species].length
- }
- export function renderFace(bones: CompanionBones): string {
- const eye: Eye = bones.eye
- switch (bones.species) {
- case duck:
- case goose:
- return `(${eye}>`
- case blob:
- return `(${eye}${eye})`
- case cat:
- return `=${eye}ω${eye}=`
- case dragon:
- return `<${eye}~${eye}>`
- case octopus:
- return `~(${eye}${eye})~`
- case owl:
- return `(${eye})(${eye})`
- case penguin:
- return `(${eye}>)`
- case turtle:
- return `[${eye}_${eye}]`
- case snail:
- return `${eye}(@)`
- case ghost:
- return `/${eye}${eye}\\`
- case axolotl:
- return `}${eye}.${eye}{`
- case capybara:
- return `(${eye}oo${eye})`
- case cactus:
- return `|${eye} ${eye}|`
- case robot:
- return `[${eye}${eye}]`
- case rabbit:
- return `(${eye}..${eye})`
- case mushroom:
- return `|${eye} ${eye}|`
- case chonk:
- return `(${eye}.${eye})`
- }
- }
|