Feast 2.0!
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 

545 строки
13 KiB

  1. import { LogEntry } from '@/game/interface'
  2. export enum POV {First, Second, Third}
  3. export type SoloLine<T> = (user: T) => LogEntry
  4. export type SoloLineArgs<T, V> = (user: T, args: V) => LogEntry
  5. export type PairLine<T> = (user: T, target: T) => LogEntry
  6. export type PairLineArgs<T, V> = (user: T, target: T, args: V) => LogEntry
  7. enum NounKind {
  8. Specific,
  9. Nonspecific,
  10. All
  11. }
  12. enum VowelSound {
  13. Default,
  14. Vowel,
  15. NonVowel
  16. }
  17. enum VerbKind {
  18. Root,
  19. Singular,
  20. Present,
  21. Past,
  22. PastParticiple
  23. }
  24. export interface Pluralizable {
  25. isPlural: boolean;
  26. }
  27. interface WordOptions {
  28. plural: boolean;
  29. capital: boolean;
  30. allCaps: boolean;
  31. proper: boolean;
  32. nounKind: NounKind;
  33. verbKind: VerbKind;
  34. vowel: VowelSound;
  35. count: boolean;
  36. possessive: boolean;
  37. objective: boolean;
  38. perspective: POV;
  39. }
  40. const emptyConfig: WordOptions = {
  41. allCaps: false,
  42. capital: false,
  43. count: false,
  44. nounKind: NounKind.Specific,
  45. verbKind: VerbKind.Root,
  46. plural: false,
  47. proper: false,
  48. vowel: VowelSound.Default,
  49. possessive: false,
  50. objective: false,
  51. perspective: POV.Third
  52. }
  53. export type TextLike = { toString: () => string }
  54. // updates as needed
  55. export class LiveText<T> {
  56. constructor (private contents: T, private run: (thing: T) => TextLike) {
  57. }
  58. toString (): string {
  59. return this.run(this.contents).toString()
  60. }
  61. }
  62. export class DynText {
  63. private parts: Array<TextLike>
  64. constructor (...parts: TextLike[]) {
  65. this.parts = parts
  66. }
  67. toString (): string {
  68. return (this.parts.map(part => part.toString())).join('')
  69. }
  70. }
  71. export abstract class Word {
  72. constructor (public opt: WordOptions = emptyConfig) {
  73. }
  74. abstract configure (opts: WordOptions): Word;
  75. abstract toString (): string;
  76. // These functions are pure; they don't mutate the original object.
  77. // This is necessary to avoid causing chaos.
  78. get allCaps (): this {
  79. const opts: WordOptions = Object.assign({}, this.opt)
  80. opts.allCaps = true
  81. return this.configure(opts) as this
  82. }
  83. get capital (): this {
  84. const opts: WordOptions = Object.assign({}, this.opt)
  85. opts.capital = true
  86. return this.configure(opts) as this
  87. }
  88. get plural (): this {
  89. const opts: WordOptions = Object.assign({}, this.opt)
  90. opts.plural = true
  91. return this.configure(opts) as this
  92. }
  93. get proper (): this {
  94. const opts: WordOptions = Object.assign({}, this.opt)
  95. opts.proper = true
  96. return this.configure(opts) as this
  97. }
  98. get improper (): this {
  99. const opts: WordOptions = Object.assign({}, this.opt)
  100. opts.proper = false
  101. return this.configure(opts) as this
  102. }
  103. get specific (): this {
  104. const opts: WordOptions = Object.assign({}, this.opt)
  105. opts.nounKind = NounKind.Specific
  106. return this.configure(opts) as this
  107. }
  108. get nonspecific (): this {
  109. const opts: WordOptions = Object.assign({}, this.opt)
  110. opts.nounKind = NounKind.Nonspecific
  111. return this.configure(opts) as this
  112. }
  113. get all (): this {
  114. const opts: WordOptions = Object.assign({}, this.opt)
  115. opts.nounKind = NounKind.All
  116. return this.configure(opts) as this
  117. }
  118. get uncountable (): this {
  119. const opts: WordOptions = Object.assign({}, this.opt)
  120. opts.count = false
  121. return this.configure(opts) as this
  122. }
  123. get root (): this {
  124. const opts: WordOptions = Object.assign({}, this.opt)
  125. opts.verbKind = VerbKind.Root
  126. return this.configure(opts) as this
  127. }
  128. get singular (): this {
  129. const opts: WordOptions = Object.assign({}, this.opt)
  130. opts.verbKind = VerbKind.Singular
  131. return this.configure(opts) as this
  132. }
  133. get present (): this {
  134. const opts: WordOptions = Object.assign({}, this.opt)
  135. opts.verbKind = VerbKind.Present
  136. return this.configure(opts) as this
  137. }
  138. get past (): this {
  139. const opts: WordOptions = Object.assign({}, this.opt)
  140. opts.verbKind = VerbKind.Past
  141. return this.configure(opts) as this
  142. }
  143. get pastParticiple (): this {
  144. const opts: WordOptions = Object.assign({}, this.opt)
  145. opts.verbKind = VerbKind.PastParticiple
  146. return this.configure(opts) as this
  147. }
  148. get possessive (): this {
  149. const opts: WordOptions = Object.assign({}, this.opt)
  150. opts.possessive = true
  151. return this.configure(opts) as this
  152. }
  153. get objective (): this {
  154. const opts: WordOptions = Object.assign({}, this.opt)
  155. opts.objective = true
  156. return this.configure(opts) as this
  157. }
  158. get pov1 (): this {
  159. const opts: WordOptions = Object.assign({}, this.opt)
  160. opts.perspective = POV.First
  161. return this.configure(opts) as this
  162. }
  163. get pov2 (): this {
  164. const opts: WordOptions = Object.assign({}, this.opt)
  165. opts.perspective = POV.Second
  166. return this.configure(opts) as this
  167. }
  168. get pov3 (): this {
  169. const opts: WordOptions = Object.assign({}, this.opt)
  170. opts.perspective = POV.Third
  171. return this.configure(opts) as this
  172. }
  173. }
  174. export class RandomWord extends Word {
  175. private history: { last: number }
  176. constructor (public choices: Array<Word>, opt: WordOptions = emptyConfig, history: { last: number } = { last: -1 }) {
  177. super(opt)
  178. this.history = history
  179. }
  180. configure (opts: WordOptions): Word {
  181. return new RandomWord(this.choices, opts, this.history)
  182. }
  183. toString (): string {
  184. let choice
  185. do {
  186. choice = Math.floor(Math.random() * this.choices.length)
  187. } while (choice === this.history.last && this.choices.length > 1)
  188. this.history.last = choice
  189. return this.choices[choice].configure(this.opt).toString()
  190. }
  191. }
  192. export class Noun extends Word {
  193. constructor (protected singularNoun: string, protected pluralNoun: string|null = null, protected possessiveNoun: string|null = null, protected options: WordOptions = emptyConfig) {
  194. super(options)
  195. }
  196. configure (opts: WordOptions): Word {
  197. return new Noun(this.singularNoun, this.pluralNoun, this.possessiveNoun, opts)
  198. }
  199. toString (): string {
  200. let result: string
  201. // TODO: plural possessive nouns?
  202. if (this.options.possessive) {
  203. if (this.possessiveNoun === null) {
  204. result = this.singularNoun + "'s"
  205. } else {
  206. result = this.possessiveNoun
  207. }
  208. } else if (this.options.plural) {
  209. if (this.pluralNoun === null) {
  210. result = this.singularNoun
  211. } else {
  212. result = (this.pluralNoun as string)
  213. }
  214. } else {
  215. result = this.singularNoun
  216. }
  217. if (!this.options.proper) {
  218. if (this.options.nounKind === NounKind.Nonspecific && this.options.count) {
  219. if (this.options.plural) {
  220. result = 'some ' + result
  221. } else {
  222. if (this.options.vowel === VowelSound.Default) {
  223. if ('aeiouAEIOU'.indexOf(result.slice(0, 1)) >= 0) {
  224. result = 'an ' + result
  225. } else {
  226. result = 'a ' + result
  227. }
  228. } else if (this.options.vowel === VowelSound.Vowel) {
  229. result = 'an ' + result
  230. } else if (this.options.vowel === VowelSound.NonVowel) {
  231. result = 'a ' + result
  232. }
  233. }
  234. } else if (this.options.nounKind === NounKind.Specific) {
  235. result = 'the ' + result
  236. }
  237. }
  238. if (this.options.allCaps) {
  239. result = result.toUpperCase()
  240. } else if (this.options.capital) {
  241. result = result.slice(0, 1).toUpperCase() + result.slice(1)
  242. }
  243. return result
  244. }
  245. conjugate (verb: Word): Word {
  246. if (this.opt.plural) {
  247. return verb.root
  248. } else {
  249. return verb.singular
  250. }
  251. }
  252. }
  253. export class ImproperNoun extends Noun {
  254. constructor (singularNoun: string, pluralNoun: string = singularNoun) {
  255. 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 })
  256. }
  257. }
  258. export class ProperNoun extends Noun {
  259. constructor (singularNoun: string) {
  260. 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 })
  261. }
  262. }
  263. export class Adjective extends Word {
  264. constructor (private adjective: string, opt: WordOptions = emptyConfig) {
  265. super(opt)
  266. }
  267. configure (opts: WordOptions): Word {
  268. return new Adjective(this.adjective, opts)
  269. }
  270. // TODO caps et al.
  271. toString (): string {
  272. return this.adjective
  273. }
  274. }
  275. export class Verb extends Word {
  276. 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) {
  277. super(opt)
  278. }
  279. configure (opts: WordOptions): Word {
  280. return new Verb(
  281. this._root,
  282. this._singular,
  283. this._present,
  284. this._past,
  285. this._pastParticiple,
  286. opts
  287. )
  288. }
  289. toString (): string {
  290. let choice: string
  291. switch (this.opt.verbKind) {
  292. case VerbKind.Root: choice = this._root; break
  293. case VerbKind.Singular: choice = this._singular; break
  294. case VerbKind.Present: choice = this._present; break
  295. case VerbKind.Past: choice = this._past; break
  296. case VerbKind.PastParticiple: choice = this._pastParticiple; break
  297. }
  298. if (this.opt.allCaps) {
  299. choice = choice.toUpperCase()
  300. } else if (this.opt.capital) {
  301. choice = choice.slice(0, 1).toUpperCase() + choice.slice(1)
  302. }
  303. return choice
  304. }
  305. }
  306. export class Preposition extends Word {
  307. constructor (private word: string, public opt: WordOptions = emptyConfig) {
  308. super(opt)
  309. }
  310. configure (opts: WordOptions): Word {
  311. return new Preposition(this.word, opts)
  312. }
  313. toString (): string {
  314. if (this.opt.capital) {
  315. return this.word.slice(0, 1).toUpperCase() + this.word.slice(1)
  316. } else {
  317. return this.word
  318. }
  319. }
  320. }
  321. // this one is obnoxious
  322. export class ToBe extends Word {
  323. constructor (protected opts: WordOptions = emptyConfig) {
  324. super(opts)
  325. }
  326. configure (opts: WordOptions): Word {
  327. return new ToBe(opts)
  328. }
  329. toString (): string {
  330. let choice
  331. if (this.opts.plural) {
  332. choice = 'are'
  333. }
  334. switch (this.opts.perspective) {
  335. case POV.First: choice = 'am'; break
  336. case POV.Second: choice = 'are'; break
  337. case POV.Third: choice = 'is'; break
  338. }
  339. if (this.opt.allCaps) {
  340. choice = choice.toUpperCase()
  341. } else if (this.opt.capital) {
  342. choice = choice.slice(0, 1).toUpperCase() + choice.slice(1)
  343. }
  344. return choice
  345. }
  346. }
  347. interface PronounDict {
  348. subjective: string;
  349. objective: string;
  350. possessive: string;
  351. reflexive: string;
  352. }
  353. export class Pronoun implements Pluralizable {
  354. constructor (private pronouns: PronounDict, private capitalize: boolean = false, public isPlural: boolean = false) {
  355. }
  356. get capital (): Pronoun {
  357. return new Pronoun(this.pronouns, true)
  358. }
  359. get subjective (): string {
  360. return this.caps(this.pronouns.subjective)
  361. }
  362. get objective (): string {
  363. return this.caps(this.pronouns.objective)
  364. }
  365. get possessive (): string {
  366. return this.caps(this.pronouns.possessive)
  367. }
  368. get reflexive (): string {
  369. return this.caps(this.pronouns.reflexive)
  370. }
  371. conjugate (verb: Word): Word {
  372. if (this.isPlural) {
  373. return verb.root
  374. } else {
  375. return verb.singular
  376. }
  377. }
  378. private caps (input: string): string {
  379. if (this.capitalize) {
  380. return input.slice(0, 1).toUpperCase() + input.slice(1)
  381. } else {
  382. return input
  383. }
  384. }
  385. }
  386. export const MalePronouns = new Pronoun({
  387. subjective: 'he',
  388. objective: 'him',
  389. possessive: 'his',
  390. reflexive: 'himself'
  391. })
  392. export const FemalePronouns = new Pronoun({
  393. subjective: 'she',
  394. objective: 'her',
  395. possessive: 'her',
  396. reflexive: 'herself'
  397. })
  398. export const TheyPronouns = new Pronoun({
  399. subjective: 'they',
  400. objective: 'them',
  401. possessive: 'their',
  402. reflexive: 'themself'
  403. }, false, true)
  404. export const TheyPluralPronouns = new Pronoun({
  405. subjective: 'they',
  406. objective: 'them',
  407. possessive: 'their',
  408. reflexive: 'themselves'
  409. }, false, true)
  410. export const ObjectPronouns = new Pronoun({
  411. subjective: 'it',
  412. objective: 'it',
  413. possessive: 'its',
  414. reflexive: 'itself'
  415. })
  416. export const SecondPersonPronouns = new Pronoun({
  417. subjective: 'you',
  418. objective: 'you',
  419. possessive: 'your',
  420. reflexive: 'yourself'
  421. })
  422. export const FirstPersonPronouns = new Pronoun({
  423. subjective: 'I',
  424. objective: 'me',
  425. possessive: 'my',
  426. reflexive: 'myself'
  427. })
  428. export class PronounAsNoun extends Noun {
  429. constructor (private pronouns: Pronoun, opt: WordOptions = emptyConfig) {
  430. super(pronouns.subjective, pronouns.subjective, pronouns.possessive, opt)
  431. this.options.nounKind = NounKind.All
  432. this.options.plural = true
  433. }
  434. configure (opts: WordOptions): Word {
  435. return new PronounAsNoun(this.pronouns, opts)
  436. }
  437. toString (): string {
  438. if (this.options.objective) {
  439. return new Noun(this.pronouns.objective, this.pronouns.objective, this.pronouns.possessive, this.options).toString()
  440. } else {
  441. return super.toString()
  442. }
  443. }
  444. conjugate (verb: Word): Word {
  445. if (this.pronouns === FirstPersonPronouns) {
  446. return super.conjugate(verb.pov1)
  447. } else if (this.pronouns === SecondPersonPronouns) {
  448. return super.conjugate(verb.pov2)
  449. } else {
  450. return super.conjugate(verb.pov3)
  451. }
  452. }
  453. }