Feast 2.0!
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 

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