|
- import { LogEntry } from '@/game/interface'
-
- 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)
- }
-
- // TODO caps et al.
- toString (): string {
- return this.adjective
- }
- }
-
- 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
- }
- }
-
- 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 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'
- })
-
- export const FirstPersonPronouns = new Pronoun({
- subjective: 'I',
- objective: 'me',
- possessive: 'my',
- reflexive: 'myself'
- })
-
- 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)
- }
- }
- }
|