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

495 строки
12 KiB

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