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

314 строки
14 KiB

  1. import { Entity, Mortal, POV, Creature } from './entity'
  2. import { Damage, Actionable, Action, DevourAction, FeedAction, DigestAction, ReleaseAction, StruggleAction, Vigor } from './combat'
  3. import { LogLines, LogEntry, CompositeLog, LogLine } from './interface'
  4. import { Noun, POVPair, POVPairArgs, ImproperNoun } from './language'
  5. export enum VoreType {
  6. Oral = "Oral Vore",
  7. Anal = "Anal Vore",
  8. Cock = "Cock Vore",
  9. Unbirth = "Unbirthing"
  10. }
  11. export interface Vore extends Mortal {
  12. preyPrefs: Set<VoreType>;
  13. bulk: number;
  14. containedIn: Container | null;
  15. predPrefs: Set<VoreType>;
  16. containers: Array<Container>;
  17. }
  18. export interface Container extends Actionable {
  19. name: Noun;
  20. owner: Vore;
  21. voreTypes: Set<VoreType>;
  22. contents: Array<Vore>;
  23. capacity: number;
  24. fullness: number;
  25. canTake: (prey: Vore) => boolean;
  26. consume: (prey: Vore) => LogEntry;
  27. release: (prey: Vore) => LogEntry;
  28. struggle: (prey: Vore) => LogEntry;
  29. tick: (dt: number) => LogEntry;
  30. describe: () => LogEntry;
  31. digest: (prey: Vore) => LogEntry;
  32. absorb: (prey: Vore) => LogEntry;
  33. dispose: (preys: Vore[]) => LogEntry;
  34. actions: Array<Action>;
  35. }
  36. abstract class NormalContainer implements Container {
  37. contents: Array<Vore>
  38. abstract consumeLines: POVPair<Vore, Vore>
  39. abstract releaseLines: POVPair<Vore, Vore>
  40. abstract struggleLines: POVPair<Vore, Vore>
  41. abstract tickLines: POVPairArgs<Vore, Vore, { damage: Damage }>
  42. abstract digestLines: POVPair<Vore, Vore>
  43. abstract absorbLines: POVPair<Vore, Vore>
  44. abstract disposeLines: POVPair<Vore, Vore>
  45. get fullness (): number {
  46. return Array.from(this.contents.values()).reduce((total: number, prey: Vore) => total + prey.bulk, 0)
  47. }
  48. canTake (prey: Vore): boolean {
  49. const fits = this.capacity - this.fullness >= prey.bulk
  50. const permitted = Array.from(this.voreTypes).every(voreType => {
  51. return prey.preyPrefs.has(voreType)
  52. })
  53. return fits && permitted
  54. }
  55. consume (prey: Vore): LogEntry {
  56. this.contents.push(prey)
  57. prey.containedIn = this
  58. return this.consumeLines.run(this.owner, prey)
  59. }
  60. release (prey: Vore): LogEntry {
  61. prey.containedIn = this.owner.containedIn
  62. this.contents = this.contents.filter(victim => victim !== prey)
  63. if (this.owner.containedIn !== null) {
  64. this.owner.containedIn.contents.push(prey)
  65. }
  66. return this.releaseLines.run(this.owner, prey)
  67. }
  68. struggle (prey: Vore): LogEntry {
  69. return this.struggleLines.run(prey, this.owner)
  70. }
  71. tick (dt: number): LogEntry {
  72. const digested: Array<Vore> = []
  73. const absorbed: Array<Vore> = []
  74. const scaled = this.damage.scale(dt / 60)
  75. this.contents.forEach(prey => {
  76. const start = prey.vigors[Vigor.Health]
  77. prey.takeDamage(scaled)
  78. const end = prey.vigors[Vigor.Health]
  79. if (start > 0 && end <= 0) {
  80. digested.push(prey)
  81. }
  82. if (start > -100 && end <= -100) {
  83. absorbed.push(prey)
  84. }
  85. })
  86. const tickedEntries = new CompositeLog(...this.contents.map(prey => this.tickLines.run(this.owner, prey, { damage: scaled })))
  87. const digestedEntries = new CompositeLog(...digested.map(prey => this.digest(prey)))
  88. const absorbedEntries = new CompositeLog(...absorbed.map(prey => this.absorb(prey)))
  89. this.contents = this.contents.filter(prey => {
  90. return prey.vigors[Vigor.Health] > -100
  91. })
  92. return new CompositeLog(tickedEntries, digestedEntries, absorbedEntries)
  93. }
  94. describe (): LogEntry {
  95. const lines: Array<string> = []
  96. this.contents.forEach(prey => {
  97. lines.push(prey.toString())
  98. })
  99. return new LogLines(...lines)
  100. }
  101. digest (prey: Vore): LogEntry {
  102. return this.digestLines.run(this.owner, prey)
  103. }
  104. absorb (prey: Vore): LogEntry {
  105. return this.absorbLines.run(this.owner, prey)
  106. }
  107. dispose (preys: Vore[]): LogEntry {
  108. return new CompositeLog(...preys.map(prey => this.disposeLines.run(this.owner, prey)))
  109. }
  110. actions: Array<Action>
  111. constructor (public name: Noun, public owner: Vore, public voreTypes: Set<VoreType>, public capacity: number, private damage: Damage) {
  112. this.contents = []
  113. this.actions = []
  114. this.name = name
  115. this.actions.push(new DevourAction(this))
  116. this.actions.push(new DigestAction(this))
  117. this.actions.push(new ReleaseAction(this))
  118. this.actions.push(new StruggleAction(this))
  119. }
  120. }
  121. abstract class InnerContainer extends NormalContainer {
  122. release (prey: Vore): LogEntry {
  123. prey.containedIn = this.escape
  124. this.contents = this.contents.filter(victim => victim !== prey)
  125. return this.releaseLines.run(this.owner, prey)
  126. }
  127. constructor (name: Noun, owner: Vore, voreTypes: Set<VoreType>, capacity: number, damage: Damage, private escape: Container) {
  128. super(name, owner, voreTypes, capacity, damage)
  129. this.actions = []
  130. this.actions.push(new DigestAction(this))
  131. this.actions.push(new StruggleAction(this))
  132. }
  133. }
  134. export class Stomach extends NormalContainer {
  135. constructor (owner: Vore, capacity: number, damage: Damage) {
  136. super(new ImproperNoun('stomach', 'stomachs').all, owner, new Set([VoreType.Oral]), capacity, damage)
  137. }
  138. consumeLines = new POVPair([
  139. [[POV.First, POV.Third], (user, target) => new LogLines(`You devour ${target.name}`)],
  140. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} munches you`)],
  141. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} munches ${target.name}`)]
  142. ])
  143. releaseLines = new POVPair([
  144. [[POV.First, POV.Third], (user, target) => new LogLines(`You hork up ${target.name}`)],
  145. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} horks you up`)],
  146. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} horks up ${target.name}`)]
  147. ])
  148. struggleLines = new POVPair([
  149. [[POV.First, POV.Third], (user, target) => new LogLines(`You claw your way out of ${target.name}`)],
  150. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} forces ${user.pronouns.possessive} way up your throat!`)],
  151. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} escapes from the gut of ${target.name}`)]
  152. ])
  153. tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([
  154. [[POV.First, POV.Third], (user, target, args) => new LogLine(`Your stomach gurgles ${target.name} for `, args.damage.renderShort())],
  155. [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital}'s stomach churns you for `, args.damage.renderShort())],
  156. [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${user.name.capital} churns ${target.name} for `, args.damage.renderShort())]
  157. ])
  158. digestLines = new POVPair([
  159. [[POV.First, POV.Third], (user, target) => new LogLines(`Your stomach overwhelms ${target.name}`)],
  160. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s stomach finishes you off`)],
  161. [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name.capital}'s squirms fade, overwhelmed by the stomach of ${user.name}`)]
  162. ])
  163. absorbLines = new POVPair([
  164. [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)],
  165. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)],
  166. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)]
  167. ])
  168. disposeLines = new POVPair([
  169. [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)],
  170. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)],
  171. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)]
  172. ])
  173. }
  174. export class InnerStomach extends InnerContainer {
  175. constructor (owner: Vore, capacity: number, damage: Damage, escape: Container) {
  176. super(new ImproperNoun('inner stomach', 'inner stomachs').all, owner, new Set([VoreType.Oral]), capacity, damage, escape)
  177. }
  178. consumeLines = new POVPair([
  179. [[POV.First, POV.Third], (user, target) => new LogLines(`You devour ${target.name}`)],
  180. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} munches you`)],
  181. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} munches ${target.name.capital}`)]
  182. ])
  183. releaseLines = new POVPair([
  184. [[POV.First, POV.Third], (user, target) => new LogLines(`You hork up ${target.name}`)],
  185. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} horks you up`)],
  186. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} horks up ${target.name.capital}`)]
  187. ])
  188. struggleLines = new POVPair([
  189. [[POV.First, POV.Third], (user, target) => new LogLines(`You claw your way out of ${target.name}`)],
  190. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} forces ${user.pronouns.possessive} way up your throat!`)],
  191. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} escapes from the gut of ${target.name}`)]
  192. ])
  193. tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([
  194. [[POV.First, POV.Third], (user, target, args) => new LogLine(`Your stomach gurgles ${target.name} for `, args.damage.renderShort())],
  195. [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital}'s stomach churns you for `, args.damage.renderShort())],
  196. [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${user.name.capital} churns ${target.name} for `, args.damage.renderShort())]
  197. ])
  198. digestLines = new POVPair([
  199. [[POV.First, POV.Third], (user, target) => new LogLines(`Your stomach overwhelms ${target.name}`)],
  200. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s stomach finishes you off`)],
  201. [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name.capital}'s squirms fade, overwhelmed by the stomach of ${user.name}`)]
  202. ])
  203. absorbLines = new POVPair([
  204. [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)],
  205. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)],
  206. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)]
  207. ])
  208. disposeLines = new POVPair([
  209. [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)],
  210. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)],
  211. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)]
  212. ])
  213. }
  214. export class Bowels extends NormalContainer {
  215. constructor (owner: Vore, capacity: number, damage: Damage) {
  216. super(new ImproperNoun('bowel', 'bowels').plural, owner, new Set([VoreType.Anal]), capacity, damage)
  217. }
  218. consumeLines = new POVPair([
  219. [[POV.First, POV.Third], (user, target) => new LogLines(`You force ${target.name} into your bowels`)],
  220. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} works you into ${user.pronouns.possessive} ass`)],
  221. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} anal-vores ${target.name.capital}`)]
  222. ])
  223. releaseLines = new POVPair([
  224. [[POV.First, POV.Third], (user, target) => new LogLines(`You let out ${target.name}`)],
  225. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} lets you out `)],
  226. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} lets out ${target.name.capital}`)]
  227. ])
  228. struggleLines = new POVPair([
  229. [[POV.First, POV.Third], (user, target) => new LogLines(`You claw your way out of ${target.name}`)],
  230. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} forces ${user.pronouns.possessive} way out your rump!`)],
  231. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} escapes from the bowels of ${target.name}`)]
  232. ])
  233. tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([
  234. [[POV.First, POV.Third], (user, target, args) => new LogLine(`Your bowels gurgle ${target.name} for `, args.damage.renderShort())],
  235. [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital}'s bowels churn you for `, args.damage.renderShort())],
  236. [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${target.name.capital} churns ${user.name} for `, args.damage.renderShort())]
  237. ])
  238. digestLines = new POVPair([
  239. [[POV.First, POV.Third], (user, target) => new LogLines(`Your bowels overwhelm ${target.name}`)],
  240. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s bowels finish you off`)],
  241. [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name.capital}'s squirms fade, overwhelmed by the bowels of ${user.name}`)]
  242. ])
  243. absorbLines = new POVPair([
  244. [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)],
  245. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)],
  246. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)]
  247. ])
  248. disposeLines = new POVPair([
  249. [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)],
  250. [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)],
  251. [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)]
  252. ])
  253. }