Feast 2.0!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

267 lines
9.4 KiB

  1. import { StatTest, StatVigorTest } from './tests'
  2. import { DynText, LiveText, TextLike, Verb, PairLine, PairLineArgs } from '../language'
  3. import { Entity, Creature } from '../entity'
  4. import { Damage, DamageFormula, Stat, Vigor, Action } from '../combat'
  5. import { LogLine, LogLines, LogEntry, CompositeLog } from '../interface'
  6. import { VoreContainer, Container } from '../vore'
  7. import { CapableCondition, UserDrainedVigorCondition, TogetherCondition, EnemyCondition, SoloCondition, PairCondition, ContainsCondition, ContainedByCondition } from './conditions'
  8. export class AttackAction extends Action {
  9. protected test: StatTest
  10. protected successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLine(
  11. `${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} for `,
  12. args.damage.renderShort()
  13. )
  14. protected failLine: PairLine<Creature> = (user, target) => new LogLine(
  15. `${user.name.capital} ${user.name.conjugate(new Verb('miss', 'misses'))} ${target.name.objective}`
  16. )
  17. constructor (protected damage: DamageFormula, protected verb: Verb = new Verb('smack')) {
  18. super(
  19. verb.root.capital,
  20. 'Attack the enemy',
  21. [new CapableCondition(), new TogetherCondition(), new EnemyCondition()]
  22. )
  23. this.test = new StatTest(Stat.Power)
  24. }
  25. execute (user: Creature, target: Creature): LogEntry {
  26. if (this.test.test(user, target)) {
  27. const damage = this.damage.calc(user, target)
  28. const targetResult = target.takeDamage(damage)
  29. const ownResult = this.successLine(user, target, { damage: damage })
  30. return new CompositeLog(ownResult, targetResult)
  31. } else {
  32. return this.failLine(user, target)
  33. }
  34. }
  35. describe (user: Creature, target: Creature): LogEntry {
  36. return new LogLine(`Attack ${target.name}. `, this.damage.describe(user, target), '. ', this.test.explain(user, target))
  37. }
  38. }
  39. export class DevourAction extends Action {
  40. private test: StatVigorTest
  41. protected failLine: PairLineArgs<Entity, { container: Container }> = (user, target, args) => new LogLine(
  42. `${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${args.container.consumeVerb} ${target.name.objective}.`
  43. )
  44. allowed (user: Creature, target: Creature): boolean {
  45. const owner = this.container.owner === user
  46. const predOk = Array.from(this.container.voreTypes).every(pref => user.predPrefs.has(pref))
  47. const preyOk = Array.from(this.container.voreTypes).every(pref => target.preyPrefs.has(pref))
  48. if (owner && predOk && preyOk) {
  49. return super.allowed(user, target)
  50. } else {
  51. return false
  52. }
  53. }
  54. constructor (protected container: Container) {
  55. super(
  56. new DynText(new LiveText(container, x => x.consumeVerb.capital), ' (', new LiveText(container, x => x.name.all), ')'),
  57. new LiveText(container, x => `Try to ${x.consumeVerb} your foe`),
  58. [new CapableCondition(), new TogetherCondition()]
  59. )
  60. this.test = new StatVigorTest(Stat.Power)
  61. }
  62. execute (user: Creature, target: Creature): LogEntry {
  63. if (this.test.test(user, target)) {
  64. return this.container.consume(target)
  65. } else {
  66. return this.failLine(user, target, { container: this.container })
  67. }
  68. }
  69. describe (user: Creature, target: Creature): LogEntry {
  70. return new LogLine(`Try to ${this.container.consumeVerb} your opponent, sending them to your ${this.container.name}. `, this.test.explain(user, target))
  71. }
  72. }
  73. export class FeedAction extends Action {
  74. protected successLine: PairLine<Entity> = (user, target) => new LogLine(
  75. `${user.name.capital} ${user.name.conjugate(new Verb('feed'))} ${user.pronouns.reflexive} to ${target.name}. `
  76. )
  77. protected failLine: PairLine<Entity> = (user, target) => new LogLine(
  78. `${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to feed ${user.pronouns.reflexive} to ${target.name}. `
  79. )
  80. allowed (user: Creature, target: Creature): boolean {
  81. const owner = this.container.owner === target
  82. const predOk = Array.from(this.container.voreTypes).every(pref => user.preyPrefs.has(pref))
  83. const preyOk = Array.from(this.container.voreTypes).every(pref => target.predPrefs.has(pref))
  84. if (owner && predOk && preyOk) {
  85. return super.allowed(user, target)
  86. } else {
  87. return false
  88. }
  89. }
  90. constructor (protected container: Container) {
  91. super(
  92. 'Feed',
  93. 'Feed yourself to your opponent',
  94. [new UserDrainedVigorCondition(Vigor.Resolve), new TogetherCondition()]
  95. )
  96. this.name += ` (${container.name})`
  97. }
  98. execute (user: Creature, target: Creature): LogEntry {
  99. return new LogLines(this.successLine(user, target), this.container.consume(user))
  100. }
  101. describe (user: Creature, target: Creature): LogEntry {
  102. return new LogLine(`Your willpower is drained, and you really feel like shoving yourself into ${target.name}'s ${this.container.name}...`)
  103. }
  104. }
  105. export class StruggleAction extends Action {
  106. private test: StatVigorTest
  107. protected successLine: PairLineArgs<Entity, { container: Container }> = (prey, pred, args) => new LogLine(
  108. `${prey.name.capital} ${prey.name.conjugate(new Verb('escape'))} from ${pred.name.possessive} ${args.container.name}.`
  109. )
  110. protected failLine: PairLineArgs<Entity, { container: Container }> = (prey, pred, args) => new LogLine(
  111. `${prey.name.capital} ${prey.name.conjugate(new Verb('fail'))} to escape from ${pred.name.possessive} ${args.container.name}.`
  112. )
  113. constructor (public container: Container) {
  114. super(
  115. new DynText('Struggle (', new LiveText(container, x => x.name.all), ')'),
  116. 'Try to escape from your foe',
  117. [new CapableCondition(), new PairCondition(), new ContainedByCondition(container)]
  118. )
  119. this.test = new StatVigorTest(Stat.Power)
  120. }
  121. execute (user: Creature, target: Creature): LogEntry {
  122. if (user.containedIn !== null) {
  123. if (this.test.test(user, target)) {
  124. return new LogLines(this.successLine(user, target, { container: this.container }), user.containedIn.release(user))
  125. } else {
  126. return this.failLine(user, target, { container: this.container })
  127. }
  128. } else {
  129. return new LogLine("Vore's bugged!")
  130. }
  131. }
  132. describe (user: Creature, target: Creature): LogEntry {
  133. return new LogLine(`Try to escape from ${target.name}'s ${this.container.name}. `, this.test.explain(user, target))
  134. }
  135. }
  136. export abstract class EatenAction extends Action {
  137. allowed (user: Creature, target: Creature) {
  138. if (target.containedIn === this.container) {
  139. return super.allowed(user, target)
  140. } else {
  141. return false
  142. }
  143. }
  144. constructor (public container: Container, name: TextLike, desc: string) {
  145. super(
  146. new DynText(name, ' (', new LiveText(container, x => x.name.all), ')'),
  147. desc,
  148. [new CapableCondition(), new PairCondition()]
  149. )
  150. }
  151. }
  152. export class DigestAction extends Action {
  153. allowed (user: Creature, target: Creature) {
  154. if (this.container.owner === user && this.container.contents.length > 0) {
  155. return super.allowed(user, target)
  156. } else {
  157. return false
  158. }
  159. }
  160. constructor (protected container: VoreContainer) {
  161. super(
  162. new DynText('Digest (', new LiveText(container, container => container.name.all), ')'),
  163. 'Digest your prey',
  164. [new CapableCondition(), new SoloCondition()]
  165. )
  166. }
  167. execute (user: Creature, target: Creature): LogEntry {
  168. const results = this.container.tick(60)
  169. return new CompositeLog(results)
  170. }
  171. describe (user: Creature, target: Creature): LogEntry {
  172. return new LogLine(`Digest everyone inside of your ${this.container.name}.`)
  173. }
  174. }
  175. export class ReleaseAction extends Action {
  176. allowed (user: Creature, target: Creature) {
  177. if (target.containedIn === this.container && this.container.contents.indexOf(target) >= 0) {
  178. return super.allowed(user, target)
  179. } else {
  180. return false
  181. }
  182. }
  183. constructor (protected container: Container) {
  184. super(
  185. new DynText('Release (', new LiveText(container, x => x.name.all), ')'),
  186. 'Release one of your prey',
  187. [new CapableCondition(), new PairCondition(), new ContainsCondition(container)]
  188. )
  189. }
  190. execute (user: Creature, target: Creature): LogEntry {
  191. return this.container.release(target)
  192. }
  193. describe (user: Creature, target: Creature): LogEntry {
  194. return new LogLine(`Release ${target.name} from your ${this.container.name}.`)
  195. }
  196. }
  197. export class TransferAction extends Action {
  198. verb: Verb = new Verb('send')
  199. line: PairLineArgs<Creature, { from: Container; to: Container }> = (user, target, args) => new LogLine(
  200. `${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} from ${user.pronouns.possessive} ${args.from.name} to ${user.pronouns.possessive} ${args.to.name}`
  201. )
  202. allowed (user: Creature, target: Creature) {
  203. if (target.containedIn === this.from && this.from.contents.includes(target)) {
  204. return super.allowed(user, target)
  205. } else {
  206. return false
  207. }
  208. }
  209. constructor (protected from: Container, protected to: Container, name = 'Transfer') {
  210. super(
  211. name,
  212. `${from.name.all.capital} to ${to.name.all}`,
  213. [new CapableCondition(), new PairCondition()]
  214. )
  215. }
  216. execute (user: Creature, target: Creature): LogEntry {
  217. this.from.release(target)
  218. this.to.consume(target)
  219. return this.line(user, target, { from: this.from, to: this.to })
  220. }
  221. describe (user: Creature, target: Creature): LogEntry {
  222. return new LogLine(`Push ${target.name} from your ${this.from.name} to your ${this.to.name}`)
  223. }
  224. }