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

259 строки
10 KiB

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