Feast 2.0!
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

449 行
11 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. }
  81. const emptyConfig: WordOptions = {
  82. allCaps: false,
  83. capital: false,
  84. count: false,
  85. nounKind: NounKind.Specific,
  86. verbKind: VerbKind.Root,
  87. plural: false,
  88. proper: false,
  89. vowel: VowelSound.Default
  90. }
  91. export type TextLike = { toString: () => string }
  92. // updates as needed
  93. export class LiveText<T> {
  94. toString (): string {
  95. return this.run(this.contents).toString()
  96. }
  97. constructor (private contents: T, private run: (thing: T) => TextLike) {
  98. }
  99. }
  100. export class DynText {
  101. private parts: Array<TextLike>
  102. constructor (...parts: TextLike[]) {
  103. this.parts = parts
  104. }
  105. toString (): string {
  106. return (this.parts.map(part => part.toString())).join('')
  107. }
  108. }
  109. export abstract class Word {
  110. constructor (public opt: WordOptions = emptyConfig) {
  111. }
  112. abstract configure (opts: WordOptions): Word;
  113. abstract toString (): string;
  114. // These functions are pure; they don't mutate the original object.
  115. // This is necessary to avoid causing chaos.
  116. get allCaps (): this {
  117. const opts: WordOptions = Object.assign({}, this.opt)
  118. opts.allCaps = true
  119. return this.configure(opts) as this
  120. }
  121. get capital (): this {
  122. const opts: WordOptions = Object.assign({}, this.opt)
  123. opts.capital = true
  124. return this.configure(opts) as this
  125. }
  126. get plural (): this {
  127. const opts: WordOptions = Object.assign({}, this.opt)
  128. opts.plural = true
  129. return this.configure(opts) as this
  130. }
  131. get proper (): this {
  132. const opts: WordOptions = Object.assign({}, this.opt)
  133. opts.proper = true
  134. return this.configure(opts) as this
  135. }
  136. get improper (): this {
  137. const opts: WordOptions = Object.assign({}, this.opt)
  138. opts.proper = false
  139. return this.configure(opts) as this
  140. }
  141. get specific (): this {
  142. const opts: WordOptions = Object.assign({}, this.opt)
  143. opts.nounKind = NounKind.Specific
  144. return this.configure(opts) as this
  145. }
  146. get nonspecific (): this {
  147. const opts: WordOptions = Object.assign({}, this.opt)
  148. opts.nounKind = NounKind.Nonspecific
  149. return this.configure(opts) as this
  150. }
  151. get all (): this {
  152. const opts: WordOptions = Object.assign({}, this.opt)
  153. opts.nounKind = NounKind.All
  154. return this.configure(opts) as this
  155. }
  156. get uncountable (): this {
  157. const opts: WordOptions = Object.assign({}, this.opt)
  158. opts.count = false
  159. return this.configure(opts) as this
  160. }
  161. get root (): this {
  162. const opts: WordOptions = Object.assign({}, this.opt)
  163. opts.verbKind = VerbKind.Root
  164. return this.configure(opts) as this
  165. }
  166. get singular (): this {
  167. const opts: WordOptions = Object.assign({}, this.opt)
  168. opts.verbKind = VerbKind.Singular
  169. return this.configure(opts) as this
  170. }
  171. get present (): this {
  172. const opts: WordOptions = Object.assign({}, this.opt)
  173. opts.verbKind = VerbKind.Present
  174. return this.configure(opts) as this
  175. }
  176. get past (): this {
  177. const opts: WordOptions = Object.assign({}, this.opt)
  178. opts.verbKind = VerbKind.Past
  179. return this.configure(opts) as this
  180. }
  181. get pastParticiple (): this {
  182. const opts: WordOptions = Object.assign({}, this.opt)
  183. opts.verbKind = VerbKind.PastParticiple
  184. return this.configure(opts) as this
  185. }
  186. }
  187. export class RandomWord extends Word {
  188. private history: { last: number }
  189. constructor (public choices: Array<Word>, opt: WordOptions = emptyConfig, history: { last: number } = { last: -1 }) {
  190. super(opt)
  191. this.history = history
  192. }
  193. configure (opts: WordOptions): Word {
  194. return new RandomWord(this.choices, opts, this.history)
  195. }
  196. toString (): string {
  197. let choice
  198. do {
  199. choice = Math.floor(Math.random() * this.choices.length)
  200. } while (choice === this.history.last)
  201. this.history.last = choice
  202. return this.choices[choice].configure(this.opt).toString()
  203. }
  204. }
  205. export class Noun extends Word {
  206. constructor (private singularNoun: string, private pluralNoun: string|null = null, private options: WordOptions = emptyConfig) {
  207. super(options)
  208. }
  209. configure (opts: WordOptions): Word {
  210. return new Noun(this.singularNoun, this.pluralNoun, opts)
  211. }
  212. toString (): string {
  213. let result: string
  214. if (this.options.plural) {
  215. if (this.pluralNoun === null) {
  216. result = this.singularNoun
  217. } else {
  218. result = (this.pluralNoun as string)
  219. }
  220. } else {
  221. result = this.singularNoun
  222. }
  223. if (!this.options.proper) {
  224. if (this.options.nounKind === NounKind.Nonspecific && this.options.count) {
  225. if (this.options.plural) {
  226. result = 'some ' + result
  227. } else {
  228. if (this.options.vowel === VowelSound.Default) {
  229. if ('aeiouAEIOU'.indexOf(result.slice(0, 1)) >= 0) {
  230. result = 'an ' + result
  231. } else {
  232. result = 'a ' + result
  233. }
  234. } else if (this.options.vowel === VowelSound.Vowel) {
  235. result = 'an ' + result
  236. } else if (this.options.vowel === VowelSound.NonVowel) {
  237. result = 'a ' + result
  238. }
  239. }
  240. } else if (this.options.nounKind === NounKind.Specific) {
  241. result = 'the ' + result
  242. }
  243. }
  244. if (this.options.allCaps) {
  245. result = result.toUpperCase()
  246. } else if (this.options.capital) {
  247. result = result.slice(0, 1).toUpperCase() + result.slice(1)
  248. }
  249. return result
  250. }
  251. }
  252. export class ImproperNoun extends Noun {
  253. constructor (singularNoun: string, pluralNoun: string = singularNoun) {
  254. super(singularNoun, pluralNoun, { plural: false, allCaps: false, capital: false, proper: false, nounKind: NounKind.Specific, verbKind: VerbKind.Root, vowel: VowelSound.Default, count: true })
  255. }
  256. }
  257. export class ProperNoun extends Noun {
  258. constructor (singularNoun: string) {
  259. super(singularNoun, null, { plural: false, allCaps: false, capital: false, proper: true, nounKind: NounKind.Specific, verbKind: VerbKind.Root, vowel: VowelSound.Default, count: true })
  260. }
  261. }
  262. export class Adjective extends Word {
  263. constructor (private adjective: string, opt: WordOptions = emptyConfig) {
  264. super(opt)
  265. }
  266. configure (opts: WordOptions): Word {
  267. return new Adjective(this.adjective, opts)
  268. }
  269. // TODO caps et al.
  270. toString (): string {
  271. return this.adjective
  272. }
  273. }
  274. export class Verb extends Word {
  275. configure (opts: WordOptions): Word {
  276. return new Verb(
  277. this._root,
  278. this._singular,
  279. this._present,
  280. this._past,
  281. this._pastParticiple,
  282. opts
  283. )
  284. }
  285. toString (): string {
  286. let choice: string
  287. switch (this.opt.verbKind) {
  288. case VerbKind.Root: choice = this._root; break
  289. case VerbKind.Singular: choice = this._singular; break
  290. case VerbKind.Present: choice = this._present; break
  291. case VerbKind.Past: choice = this._past; break
  292. case VerbKind.PastParticiple: choice = this._pastParticiple; break
  293. }
  294. if (this.opt.allCaps) {
  295. choice = choice.toUpperCase()
  296. } else if (this.opt.capital) {
  297. choice = choice.slice(0, 1).toUpperCase() + choice.slice(1)
  298. }
  299. return choice
  300. }
  301. 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) {
  302. super(opt)
  303. }
  304. }
  305. interface PronounDict {
  306. subjective: string;
  307. objective: string;
  308. possessive: string;
  309. reflexive: string;
  310. }
  311. export class Pronoun implements Pluralizable {
  312. constructor (private pronouns: PronounDict, private capitalize: boolean = false, public isPlural: boolean = false) {
  313. }
  314. get capital (): Pronoun {
  315. return new Pronoun(this.pronouns, true)
  316. }
  317. get subjective (): string {
  318. return this.caps(this.pronouns.subjective)
  319. }
  320. get objective (): string {
  321. return this.caps(this.pronouns.objective)
  322. }
  323. get possessive (): string {
  324. return this.caps(this.pronouns.possessive)
  325. }
  326. get reflexive (): string {
  327. return this.caps(this.pronouns.reflexive)
  328. }
  329. private caps (input: string): string {
  330. if (this.capitalize) {
  331. return input.slice(0, 1).toUpperCase() + input.slice(1)
  332. } else {
  333. return input
  334. }
  335. }
  336. }
  337. export const MalePronouns = new Pronoun({
  338. subjective: 'he',
  339. objective: 'him',
  340. possessive: 'his',
  341. reflexive: 'himself'
  342. })
  343. export const FemalePronouns = new Pronoun({
  344. subjective: 'she',
  345. objective: 'her',
  346. possessive: 'her',
  347. reflexive: 'herself'
  348. })
  349. export const TheyPronouns = new Pronoun({
  350. subjective: 'they',
  351. objective: 'them',
  352. possessive: 'their',
  353. reflexive: 'themself'
  354. }, false, true)
  355. export const TheyPluralPronouns = new Pronoun({
  356. subjective: 'they',
  357. objective: 'them',
  358. possessive: 'their',
  359. reflexive: 'themselves'
  360. }, false, true)
  361. export const ObjectPronouns = new Pronoun({
  362. subjective: 'it',
  363. objective: 'it',
  364. possessive: 'its',
  365. reflexive: 'itself'
  366. })