Feast 2.0!
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 

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