|
- import { LogEntry } from "@/game/interface"
- import { parseTwoDigitYear } from "moment"
-
- export enum POV {
- First,
- Second,
- Third
- }
-
- export type SoloLine<T> = (user: T) => LogEntry
- export type SoloLineArgs<T, V> = (user: T, args: V) => LogEntry
- export type PairLine<T> = (user: T, target: T) => LogEntry
- export type PairLineArgs<T, V> = (user: T, target: T, args: V) => LogEntry
- export type GroupLine<T> = (user: T, targets: Array<T>) => LogEntry
-
- enum NounKind {
- Specific,
- Nonspecific,
- All
- }
-
- enum VowelSound {
- Default,
- Vowel,
- NonVowel
- }
-
- enum VerbKind {
- Root,
- Singular,
- Present,
- Past,
- PastParticiple
- }
-
- export interface Pluralizable {
- isPlural: boolean;
- }
-
- interface WordOptions {
- plural: boolean;
- capital: boolean;
- allCaps: boolean;
- proper: boolean;
- nounKind: NounKind;
- verbKind: VerbKind;
- vowel: VowelSound;
- count: boolean;
- possessive: boolean;
- objective: boolean;
- perspective: POV;
- }
-
- const emptyConfig: WordOptions = {
- allCaps: false,
- capital: false,
- count: false,
- nounKind: NounKind.Specific,
- verbKind: VerbKind.Root,
- plural: false,
- proper: false,
- vowel: VowelSound.Default,
- possessive: false,
- objective: false,
- perspective: POV.Third
- }
-
- export type TextLike = { toString: () => string }
-
- // updates as needed
- export class LiveText<T> {
- constructor (private contents: T, private run: (thing: T) => TextLike) {}
-
- toString (): string {
- return this.run(this.contents).toString()
- }
- }
-
- export class DynText {
- private parts: Array<TextLike>
- constructor (...parts: TextLike[]) {
- this.parts = parts
- }
-
- toString (): string {
- return this.parts.map(part => part.toString()).join("")
- }
- }
-
- export abstract class Word {
- constructor (public opt: WordOptions = emptyConfig) {}
-
- abstract configure(opts: WordOptions): Word
- abstract toString(): string
-
- // These functions are pure; they don't mutate the original object.
- // This is necessary to avoid causing chaos.
-
- get allCaps (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.allCaps = true
- return this.configure(opts) as this
- }
-
- get capital (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.capital = true
- return this.configure(opts) as this
- }
-
- get plural (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.plural = true
- return this.configure(opts) as this
- }
-
- get proper (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.proper = true
- return this.configure(opts) as this
- }
-
- get improper (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.proper = false
- return this.configure(opts) as this
- }
-
- get specific (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.nounKind = NounKind.Specific
- return this.configure(opts) as this
- }
-
- get nonspecific (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.nounKind = NounKind.Nonspecific
- return this.configure(opts) as this
- }
-
- get all (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.nounKind = NounKind.All
- return this.configure(opts) as this
- }
-
- get uncountable (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.count = false
- return this.configure(opts) as this
- }
-
- get root (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.verbKind = VerbKind.Root
- return this.configure(opts) as this
- }
-
- get singular (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.verbKind = VerbKind.Singular
- return this.configure(opts) as this
- }
-
- get present (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.verbKind = VerbKind.Present
- return this.configure(opts) as this
- }
-
- get past (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.verbKind = VerbKind.Past
- return this.configure(opts) as this
- }
-
- get pastParticiple (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.verbKind = VerbKind.PastParticiple
- return this.configure(opts) as this
- }
-
- get possessive (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.possessive = true
- return this.configure(opts) as this
- }
-
- get objective (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.objective = true
- return this.configure(opts) as this
- }
-
- get pov1 (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.perspective = POV.First
- return this.configure(opts) as this
- }
-
- get pov2 (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.perspective = POV.Second
- return this.configure(opts) as this
- }
-
- get pov3 (): this {
- const opts: WordOptions = Object.assign({}, this.opt)
- opts.perspective = POV.Third
- return this.configure(opts) as this
- }
- }
-
- export class OptionalWord extends Word {
- constructor (public word: Word, private chance = 0.5, private suffix = " ") {
- super(word.opt)
- }
-
- configure (opts: WordOptions): Word {
- return new OptionalWord(this.word.configure(opts), this.chance, this.suffix)
- }
-
- toString (): string {
- if (Math.random() < this.chance) {
- return this.word + this.suffix
- } else {
- return ""
- }
- }
- }
-
- export class RandomWord extends Word {
- private history: { last: number }
- constructor (
- public choices: Array<Word>,
- opt: WordOptions = emptyConfig,
- history: { last: number } = { last: -1 }
- ) {
- super(opt)
- this.history = history
- }
-
- configure (opts: WordOptions): Word {
- return new RandomWord(this.choices, opts, this.history)
- }
-
- toString (): string {
- let choice
-
- do {
- choice = Math.floor(Math.random() * this.choices.length)
- } while (choice === this.history.last && this.choices.length > 1)
-
- this.history.last = choice
- return this.choices[choice].configure(this.opt).toString()
- }
- }
-
- export class Noun extends Word {
- constructor (
- protected singularNoun: string,
- protected pluralNoun: string | null = null,
- protected possessiveNoun: string | null = null,
- protected options: WordOptions = emptyConfig
- ) {
- super(options)
- }
-
- configure (opts: WordOptions): Word {
- return new Noun(
- this.singularNoun,
- this.pluralNoun,
- this.possessiveNoun,
- opts
- )
- }
-
- toString (): string {
- let result: string
-
- // TODO: plural possessive nouns?
- if (this.options.possessive) {
- if (this.possessiveNoun === null) {
- result = this.singularNoun + "'s"
- } else {
- result = this.possessiveNoun
- }
- } else if (this.options.plural) {
- if (this.pluralNoun === null) {
- result = this.singularNoun
- } else {
- result = this.pluralNoun as string
- }
- } else {
- result = this.singularNoun
- }
-
- if (!this.options.proper) {
- if (
- this.options.nounKind === NounKind.Nonspecific &&
- this.options.count
- ) {
- if (this.options.plural) {
- result = "some " + result
- } else {
- if (this.options.vowel === VowelSound.Default) {
- if ("aeiouAEIOU".indexOf(result.slice(0, 1)) >= 0) {
- result = "an " + result
- } else {
- result = "a " + result
- }
- } else if (this.options.vowel === VowelSound.Vowel) {
- result = "an " + result
- } else if (this.options.vowel === VowelSound.NonVowel) {
- result = "a " + result
- }
- }
- } else if (this.options.nounKind === NounKind.Specific) {
- result = "the " + result
- }
- }
-
- if (this.options.allCaps) {
- result = result.toUpperCase()
- } else if (this.options.capital) {
- result = result.slice(0, 1).toUpperCase() + result.slice(1)
- }
-
- return result
- }
-
- conjugate (verb: Word): Word {
- if (this.opt.plural) {
- return verb.root
- } else {
- return verb.singular
- }
- }
- }
-
- export class ImproperNoun extends Noun {
- constructor (singularNoun: string, pluralNoun: string = singularNoun) {
- super(singularNoun, pluralNoun, null, {
- plural: false,
- allCaps: false,
- capital: false,
- proper: false,
- nounKind: NounKind.Specific,
- verbKind: VerbKind.Root,
- vowel: VowelSound.Default,
- count: true,
- possessive: false,
- objective: false,
- perspective: POV.Third
- })
- }
- }
-
- export class ProperNoun extends Noun {
- constructor (singularNoun: string) {
- super(singularNoun, null, null, {
- plural: false,
- allCaps: false,
- capital: false,
- proper: true,
- nounKind: NounKind.Specific,
- verbKind: VerbKind.Root,
- vowel: VowelSound.Default,
- count: true,
- possessive: false,
- objective: false,
- perspective: POV.Third
- })
- }
- }
-
- export class Adjective extends Word {
- constructor (private adjective: string, opt: WordOptions = emptyConfig) {
- super(opt)
- }
-
- configure (opts: WordOptions): Word {
- return new Adjective(this.adjective, opts)
- }
-
- toString (): string {
- let word = this.adjective
- if (this.opt.allCaps) {
- word = word.toUpperCase()
- } else if (this.opt.capital) {
- word = word.slice(0, 1).toUpperCase() + word.slice(1)
- }
- return word
- }
- }
-
- export class Adverb extends Word {
- constructor (private adverb: string, opt: WordOptions = emptyConfig) {
- super(opt)
- }
-
- configure (opt: WordOptions): Word {
- return new Adverb(this.adverb, opt)
- }
-
- toString (): string {
- return this.adverb
- }
- }
-
- /**
- * root: break
- * singular: breaks
- * present: breaking
- * past: broken
- */
- export class Verb extends Word {
- constructor (
- private _root: string,
- private _singular: string = _root + "s",
- private _present: string = _root + "ing",
- private _past: string = _root + "ed",
- private _pastParticiple: string = _past,
- public opt: WordOptions = emptyConfig
- ) {
- super(opt)
- }
-
- configure (opts: WordOptions): Word {
- return new Verb(
- this._root,
- this._singular,
- this._present,
- this._past,
- this._pastParticiple,
- opts
- )
- }
-
- toString (): string {
- let choice: string
-
- switch (this.opt.verbKind) {
- case VerbKind.Root:
- choice = this._root
- break
- case VerbKind.Singular:
- choice = this._singular
- break
- case VerbKind.Present:
- choice = this._present
- break
- case VerbKind.Past:
- choice = this._past
- break
- case VerbKind.PastParticiple:
- choice = this._pastParticiple
- break
- }
-
- if (this.opt.allCaps) {
- choice = choice.toUpperCase()
- } else if (this.opt.capital) {
- choice = choice.slice(0, 1).toUpperCase() + choice.slice(1)
- }
-
- return choice
- }
- }
-
- export class Preposition extends Word {
- constructor (private word: string, public opt: WordOptions = emptyConfig) {
- super(opt)
- }
-
- configure (opts: WordOptions): Word {
- return new Preposition(this.word, opts)
- }
-
- toString (): string {
- if (this.opt.capital) {
- return this.word.slice(0, 1).toUpperCase() + this.word.slice(1)
- } else {
- return this.word
- }
- }
- }
-
- // this one is obnoxious
- export class ToBe extends Word {
- constructor (protected opts: WordOptions = emptyConfig) {
- super(opts)
- }
-
- configure (opts: WordOptions): Word {
- return new ToBe(opts)
- }
-
- toString (): string {
- let choice
-
- if (this.opts.plural) {
- choice = "are"
- }
- switch (this.opts.perspective) {
- case POV.First:
- choice = "am"
- break
- case POV.Second:
- choice = "are"
- break
- case POV.Third:
- choice = "is"
- break
- }
-
- if (this.opt.allCaps) {
- choice = choice.toUpperCase()
- } else if (this.opt.capital) {
- choice = choice.slice(0, 1).toUpperCase() + choice.slice(1)
- }
-
- return choice
- }
- }
-
- interface PronounDict {
- subjective: string;
- objective: string;
- possessive: string;
- reflexive: string;
- }
-
- export class Pronoun implements Pluralizable {
- constructor (
- private pronouns: PronounDict,
- private capitalize: boolean = false,
- public isPlural: boolean = false
- ) {}
-
- get capital (): Pronoun {
- return new Pronoun(this.pronouns, true)
- }
-
- get subjective (): string {
- return this.caps(this.pronouns.subjective)
- }
-
- get objective (): string {
- return this.caps(this.pronouns.objective)
- }
-
- get possessive (): string {
- return this.caps(this.pronouns.possessive)
- }
-
- get reflexive (): string {
- return this.caps(this.pronouns.reflexive)
- }
-
- conjugate (verb: Word): Word {
- if (this.isPlural) {
- return verb.root
- } else {
- return verb.singular
- }
- }
-
- private caps (input: string): string {
- if (this.capitalize) {
- return input.slice(0, 1).toUpperCase() + input.slice(1)
- } else {
- return input
- }
- }
- }
-
- export type OnomatopoeiaPart = [string, number, number]
-
- export class Onomatopoeia extends Word {
- constructor (protected parts: Array<OnomatopoeiaPart>, public opts: WordOptions = emptyConfig) {
- super(opts)
- }
-
- configure (opts: WordOptions): Word {
- return new Onomatopoeia(this.parts, opts)
- }
-
- toString (): string {
- const built = this.parts.reduce((result, next) => {
- const [piece, min, max] = next
- const count = Math.floor(Math.random() * (max - min)) + min
- for (let i = 0; i < count; i++) {
- result += piece
- }
- return result
- }, "")
-
- return built
- }
- }
-
- export const MalePronouns = new Pronoun({
- subjective: "he",
- objective: "him",
- possessive: "his",
- reflexive: "himself"
- })
-
- export const FemalePronouns = new Pronoun({
- subjective: "she",
- objective: "her",
- possessive: "her",
- reflexive: "herself"
- })
-
- export const TheyPronouns = new Pronoun(
- {
- subjective: "they",
- objective: "them",
- possessive: "their",
- reflexive: "themself"
- },
- false,
- true
- )
-
- export const TheyPluralPronouns = new Pronoun(
- {
- subjective: "they",
- objective: "them",
- possessive: "their",
- reflexive: "themselves"
- },
- false,
- true
- )
-
- export const ObjectPronouns = new Pronoun({
- subjective: "it",
- objective: "it",
- possessive: "its",
- reflexive: "itself"
- })
-
- export const SecondPersonPronouns = new Pronoun(
- {
- subjective: "you",
- objective: "you",
- possessive: "your",
- reflexive: "yourself"
- },
- false,
- true
- )
-
- export const FirstPersonPronouns = new Pronoun(
- {
- subjective: "I",
- objective: "me",
- possessive: "my",
- reflexive: "myself"
- },
- false,
- true
- )
-
- export class PronounAsNoun extends Noun {
- constructor (private pronouns: Pronoun, opt: WordOptions = emptyConfig) {
- super(pronouns.subjective, pronouns.subjective, pronouns.possessive, opt)
- this.options.nounKind = NounKind.All
- this.options.plural = true
- }
-
- configure (opts: WordOptions): Word {
- return new PronounAsNoun(this.pronouns, opts)
- }
-
- toString (): string {
- if (this.options.objective) {
- return new Noun(
- this.pronouns.objective,
- this.pronouns.objective,
- this.pronouns.possessive,
- this.options
- ).toString()
- } else {
- return super.toString()
- }
- }
-
- conjugate (verb: Word): Word {
- if (this.pronouns === FirstPersonPronouns) {
- return super.conjugate(verb.pov1)
- } else if (this.pronouns === SecondPersonPronouns) {
- return super.conjugate(verb.pov2)
- } else {
- return super.conjugate(verb.pov3)
- }
- }
- }
|