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

376 строки
16 KiB

  1. import { Creature, POV } from '../entity'
  2. import { Damage, DamageType, ConstantDamageFormula, Vigor, Side, GroupAction, CombatTest, Stat, DamageFormula, UniformRandomDamageFormula, Action, DamageInstance, StatDamageFormula, VoreStat } from '../combat'
  3. import { ImproperNoun, POVPair, ProperNoun, FemalePronouns, RandomWord, Adjective, POVPairArgs, POVSoloArgs, Verb } from '../language'
  4. import { LogLine, LogLines, LogEntry, Newline } from '../interface'
  5. import { VoreType, Stomach, VoreContainer, Vore, NormalContainer, Container } from '../vore'
  6. import { AttackAction, FeedAction, TransferAction, EatenAction } from '../combat/actions'
  7. import { TogetherCondition, ContainerCondition, EnemyCondition, AllyCondition, PairCondition } from '../combat/conditions'
  8. import { InstantKill } from '../combat/effects'
  9. import * as Words from '../words'
  10. import { StatVigorTest } from '../combat/tests'
  11. class HypnotizeAction extends Action {
  12. lines = new POVPair<Creature, Creature>([
  13. [[POV.First, POV.Third], (user, target) => new LogLine(`Your hypnotic gaze enthralls ${target.name}, putting ${target.pronouns.objective} under your control!`)],
  14. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s hypnotic gaze enthralls you, putting you under ${user.pronouns.possessive} control!`)],
  15. [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital}'s hypnotic gaze enthralls ${target.name}, putting ${target.pronouns.objective} under ${user.pronouns.possessive} control!`)]
  16. ])
  17. execute (user: Creature, target: Creature): LogEntry {
  18. target.side = user.side
  19. return this.lines.run(user, target)
  20. }
  21. describe (user: Creature, target: Creature): LogEntry {
  22. return new LogLine(`Force your target to fight by your side`)
  23. }
  24. constructor () {
  25. super(
  26. `Hypnotize`,
  27. `Change their mind!`,
  28. [
  29. new TogetherCondition(),
  30. new EnemyCondition()
  31. ]
  32. )
  33. }
  34. }
  35. class MawContainer extends NormalContainer {
  36. consumeVerb = new Verb('grab', 'grabs', 'grabbing', 'grabbed')
  37. releaseVerb = new Verb('release')
  38. struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled')
  39. consumeLines = new POVPair<Vore, Vore>([
  40. [[POV.First, POV.Third], (user, target) => new LogLine(`You snatch ${target.name} up in your jaws`)],
  41. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} snatches you up in ${user.pronouns.possessive} maw`)],
  42. [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} snatches ${target.name} up in ${user.pronouns.possessive} maw`)]
  43. ])
  44. releaseLines = new POVPair([
  45. [[POV.First, POV.Third], (user, target) => new LogLine(`You let out ${target.name}`)],
  46. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} lets you out `)],
  47. [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} lets out ${target.name}`)]
  48. ])
  49. struggleLines = new POVPair([
  50. [[POV.First, POV.Third], (user, target) => new LogLine(`You claw your way free of ${target.name}`)],
  51. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} forces ${user.pronouns.possessive} way free!`)],
  52. [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} escapes from ${target.name}`)]
  53. ])
  54. constructor (owner: Vore, stomach: VoreContainer) {
  55. super(new ImproperNoun('maw'), owner, new Set([VoreType.Oral]), 50)
  56. this.actions.push(new TransferAction(this, stomach))
  57. }
  58. }
  59. class FlexToesAction extends GroupAction {
  60. lines = new POVPairArgs<Creature, Creature, { damage: Damage }>([
  61. [[POV.First, POV.Third], (user, target, args) => new LogLine(`Your toes crush ${target.name} for `, args.damage.renderShort(), ` damage!`)],
  62. [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital}'s toes crush you for `, args.damage.renderShort(), ` damage!`)],
  63. [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${user.name.capital}'s toes crush ${target.name} for `, args.damage.renderShort(), ` damage!`)]
  64. ])
  65. describeGroup (user: Creature, targets: Creature[]): LogEntry {
  66. return new LogLine(`Flex your toes. `, this.damage.explain(user))
  67. }
  68. execute (user: Creature, target: Creature): LogEntry {
  69. const damage = this.damage.calc(user, target)
  70. return new LogLines(target.takeDamage(damage), this.lines.run(user, target, { damage: damage }))
  71. }
  72. describe (user: Creature, target: Creature): LogEntry {
  73. return new LogLine(`Flex your toes! `, this.damage.describe(user, target))
  74. }
  75. constructor (private damage: DamageFormula, container: Container) {
  76. super('Flex Toes', 'Flex your toes!', [
  77. new ContainerCondition(container),
  78. new PairCondition()
  79. ])
  80. }
  81. }
  82. class BootContainer extends NormalContainer {
  83. consumeLines = new POVPair<Vore, Vore>([
  84. [[POV.First, POV.Third], (user, target) => new LogLine(`You stuff ${target.name} into your boot.`)],
  85. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} stuffs you in ${user.pronouns.possessive} boot, pinning you between toes and insole.`)],
  86. [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} stuffs ${target.name} in ${user.pronouns.possessive} boot.`)]
  87. ])
  88. releaseLines = new POVPair([
  89. [[POV.First, POV.Third], (user, target) => new LogLine(`You dump ${target.name} out from your boot.`)],
  90. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} dumps you out from ${user.pronouns.possessive} boot.`)],
  91. [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} dumps ${target.name} out from ${user.pronouns.possessive} boot.`)]
  92. ])
  93. struggleLines = new POVPair([
  94. [[POV.First, POV.Third], (user, target) => new LogLine(`You slip out from ${target.name}'s boot.`)],
  95. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} squeezes ${user.pronouns.possessive} way free of your footwear!`)],
  96. [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} escapes from ${target.name}'s boot.`)]
  97. ])
  98. consumeVerb = new Verb('trap', 'traps', 'trapped', 'trapping')
  99. releaseVerb = new Verb('dump')
  100. struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled')
  101. constructor (owner: Vore) {
  102. super(new ImproperNoun('boot'), owner, new Set(), 50)
  103. const flex = new FlexToesAction(
  104. new UniformRandomDamageFormula(new Damage(
  105. { target: Vigor.Health, type: DamageType.Crush, amount: 50 },
  106. { target: Vigor.Stamina, type: DamageType.Crush, amount: 50 },
  107. { target: Vigor.Resolve, type: DamageType.Crush, amount: 50 }
  108. ), 0.5),
  109. this
  110. )
  111. this.actions.push(flex)
  112. }
  113. }
  114. const huge = new RandomWord([
  115. new Adjective('massive'),
  116. new Adjective('colossal'),
  117. new Adjective('big ol\''),
  118. new Adjective('heavy'),
  119. new Adjective('crushing'),
  120. new Adjective('huge')
  121. ])
  122. class BiteAction extends AttackAction {
  123. constructor () {
  124. super(
  125. new ConstantDamageFormula(new Damage({ amount: 50, type: DamageType.Slash, target: Vigor.Health })),
  126. new Verb('bite', 'bites', 'biting', 'bit')
  127. )
  128. this.name = "Bite"
  129. }
  130. }
  131. class ChewAction extends GroupAction {
  132. lines: POVPairArgs<Creature, Creature, { damage: Damage }> = new POVPairArgs([
  133. [[POV.First, POV.Third], (user, target, args: { damage: Damage }) => new LogLine(`You chew on ${target.name} for `, args.damage.renderShort(), `!`)],
  134. [[POV.Third, POV.First], (user, target, args: { damage: Damage }) => new LogLine(`${user.name.capital} chews on you for `, args.damage.renderShort(), `!`)],
  135. [[POV.Third, POV.Third], (user, target, args: { damage: Damage }) => new LogLine(`${user.name.capital} chews on ${target.name} for `, args.damage.renderShort(), `!`)]
  136. ])
  137. describeGroup (user: Creature, targets: Creature[]): LogEntry {
  138. return new LogLine('Crunch \'em all. ', this.damage.explain(user))
  139. }
  140. execute (user: Creature, target: Creature): LogEntry {
  141. const damage = this.damage.calc(user, target)
  142. const results: Array<LogEntry> = []
  143. results.push(this.lines.run(user, target, { damage: damage }))
  144. results.push(new LogLine(' '))
  145. results.push(target.takeDamage(damage))
  146. if (target.vigors.Health <= 0) {
  147. if (this.killAction.allowed(user, target)) {
  148. results.push(new Newline())
  149. results.push(this.killAction.execute(user, target))
  150. }
  151. }
  152. return new LogLine(...results)
  153. }
  154. describe (user: Creature, target: Creature): LogEntry {
  155. return new LogLine('Do the crunch')
  156. }
  157. constructor (private damage: DamageFormula, container: Container, private killAction: Action) {
  158. super('Chew', 'Give them the big chew', [
  159. new ContainerCondition(container)
  160. ])
  161. }
  162. }
  163. class StompAction extends GroupAction {
  164. lines: POVPair<Creature, Creature> = new POVPair([
  165. [[POV.First, POV.Third], (user: Creature, target: Creature) => new LogLine(`You flatten ${target.name} under your foot!`)],
  166. [[POV.Third, POV.First], (user: Creature) => new LogLine(`${user.name.capital} flattens you under ${user.pronouns.possessive} ${huge} foot!`)],
  167. [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens ${target.name} under ${user.pronouns.possessive} ${huge} foot!`)]
  168. ])
  169. execute (user: Creature, target: Creature): LogEntry {
  170. return new LogLines(this.lines.run(user, target), new InstantKill().apply(target))
  171. }
  172. describe (user: Creature, target: Creature): LogEntry {
  173. return new LogLine('Stomp one sucker')
  174. }
  175. describeGroup (user: Creature, targets: Array<Creature>): LogEntry {
  176. return new LogLine('Stomp all ', targets.length.toString(), ' of \'em!')
  177. }
  178. constructor () {
  179. super('Stomp', 'STOMP!', [
  180. new TogetherCondition(),
  181. new EnemyCondition()
  182. ])
  183. }
  184. }
  185. class StompAllyAction extends Action {
  186. lines: POVPair<Creature, Creature> = new POVPair([
  187. [[POV.First, POV.Third], (user: Creature, target: Creature) => new LogLine(`You flatten ${target.name} under your boot!`)],
  188. [[POV.Third, POV.First], (user: Creature) => new LogLine(`${user.name.capital} flattens you under ${user.pronouns.possessive} ${huge} boot!`)],
  189. [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens ${target.name} under ${user.pronouns.possessive} ${huge} boot!`)]
  190. ])
  191. execute (user: Creature, target: Creature): LogEntry {
  192. const damages: Array<DamageInstance> = Object.keys(Stat).map(stat => ({
  193. target: stat as Stat,
  194. amount: target.stats[stat as Stat] / 3,
  195. type: DamageType.Heal
  196. }))
  197. const heal = new Damage(
  198. ...damages
  199. )
  200. user.takeDamage(heal)
  201. return new LogLines(
  202. this.lines.run(user, target),
  203. new InstantKill().apply(target),
  204. new LogLine(`${user.name.capital} absorbs ${target.pronouns.possessive} power, gaining `, heal.renderShort())
  205. )
  206. }
  207. describe (user: Creature, target: Creature): LogEntry {
  208. return new LogLine('Crush an ally to absorb their power')
  209. }
  210. constructor () {
  211. super('Stomp Ally', '-1 ally, +1 buff', [
  212. new TogetherCondition(),
  213. new AllyCondition()
  214. ])
  215. }
  216. }
  217. class DevourAllAction extends GroupAction {
  218. lines: POVPair<Creature, Creature> = new POVPair([
  219. [[POV.First, POV.Third], (user: Creature, target: Creature) => new LogLine(`You scoop up ${target.name}!`)],
  220. [[POV.Third, POV.First], (user: Creature) => new LogLine(`${user.name.capital} scoops you up!`)],
  221. [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} scoops ${target.name} up!`)]
  222. ])
  223. groupLines = new POVSoloArgs<Creature, { count: number }>([
  224. [[POV.First], (user, args) => new LogLine(`${Words.SwallowSound.allCaps}! All ${args.count} of your prey pour down your ${Words.Slick} throat. They're just ${user.kind.all} chow now`)],
  225. [[POV.Third], (user, args) => new LogLine(`${Words.SwallowSound.allCaps}! All ${args.count} of ${user.pronouns.possessive} prey pour down ${user.name}'s ${Words.Slick} gullet as ${user.pronouns.subjective} ${Words.Swallows.singular}; they're just ${user.kind.all} chow now`)]
  226. ])
  227. execute (user: Creature, target: Creature): LogEntry {
  228. this.container.consume(target)
  229. return new LogLines(this.lines.run(user, target))
  230. }
  231. describe (user: Creature, target: Creature): LogEntry {
  232. return new LogLine('Stomp one sucker')
  233. }
  234. executeGroup (user: Creature, targets: Array<Creature>): LogEntry {
  235. return new LogLines(...targets.filter(target => this.test.test(user, target)).map(target => this.execute(user, target)).concat(
  236. [
  237. new Newline(),
  238. this.groupLines.run(user, { count: targets.length })
  239. ]
  240. ))
  241. }
  242. describeGroup (user: Creature, targets: Array<Creature>): LogEntry {
  243. return new LogLine('Eat all ', targets.length.toString(), ' of \'em!')
  244. }
  245. private test: CombatTest
  246. constructor (private container: VoreContainer) {
  247. super('Devour All', 'GULP!', [
  248. new TogetherCondition(),
  249. new EnemyCondition()
  250. ])
  251. this.test = new StatVigorTest(Stat.Power)
  252. }
  253. }
  254. export class Withers extends Creature {
  255. title = "Huge Hellhound"
  256. desc = "Will eat your party"
  257. constructor () {
  258. super(
  259. new ProperNoun('Withers'),
  260. new ImproperNoun('hellhound', 'hellhounds'),
  261. FemalePronouns,
  262. { Toughness: 40, Power: 50, Speed: 30, Willpower: 40, Charm: 70 },
  263. new Set(),
  264. new Set([VoreType.Oral]),
  265. 5000
  266. )
  267. this.actions.push(new BiteAction())
  268. this.groupActions.push(new StompAction())
  269. this.side = Side.Monsters
  270. const stomach = new Stomach(this, 50, new Damage(
  271. { amount: 300, type: DamageType.Acid, target: Vigor.Health },
  272. { amount: 200, type: DamageType.Crush, target: Vigor.Stamina },
  273. { amount: 200, type: DamageType.Dominance, target: Vigor.Resolve }
  274. ))
  275. stomach.tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([
  276. [[POV.First, POV.Third], (user, target, args) => new LogLine(`Your stomach ${Words.Churns.singular} ${target.name} for `, args.damage.renderShort())],
  277. [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital}'s stomach ${Words.Churns.singular} you for `, args.damage.renderShort())],
  278. [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${user.name.capital} ${Words.Churns.singular} ${target.name} for `, args.damage.renderShort())]
  279. ])
  280. stomach.digestLines = new POVPair<Vore, Vore>([
  281. [[POV.First, POV.Third], (user, target) => new LogLine(`Your stomach ${Words.Digests.singular} ${target.name}`)],
  282. [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s stomach ${Words.Digests.singular} you`)],
  283. [[POV.Third, POV.Third], (user, target) => new LogLine(`${target.name.capital}'s ${Words.Struggles.present} fades as the ${target.kind.all} is ${Words.Digests.past} by the ${user.kind.all}'s ${stomach.name}.`)]
  284. ])
  285. this.containers.push(stomach)
  286. this.otherActions.push(new FeedAction(stomach))
  287. this.groupActions.push(new DevourAllAction(stomach))
  288. const maw = new MawContainer(this, stomach)
  289. this.otherContainers.push(maw)
  290. this.actions.push(new ChewAction(
  291. new UniformRandomDamageFormula(new Damage(
  292. { target: Vigor.Health, type: DamageType.Crush, amount: 10000 }
  293. ), 0.5),
  294. maw,
  295. new TransferAction(maw, stomach)
  296. ))
  297. const boot = new BootContainer(this)
  298. this.otherContainers.push(boot)
  299. this.actions.push(new StompAllyAction())
  300. this.actions.push(
  301. new AttackAction(
  302. new StatDamageFormula([
  303. { fraction: 0.5, stat: Stat.Toughness, target: Vigor.Health, type: DamageType.Crush },
  304. { fraction: 0.05, stat: VoreStat.Bulk, target: Vigor.Health, type: DamageType.Crush }
  305. ]),
  306. new Verb('stomp')
  307. )
  308. )
  309. this.actions.push(new HypnotizeAction())
  310. }
  311. }