|  | import { StatTest, StatVigorTest } from './tests'
import { POVPairArgs, POVPair, DynText, LiveText, TextLike } from '../language'
import { Entity, POV, Creature } from '../entity'
import { Damage, DamageFormula, Stat, Vigor, Action } from '../combat'
import { LogLine, LogLines, LogEntry, CompositeLog } from '../interface'
import { VoreContainer, Container } from '../vore'
import { CapableCondition, DrainedVigorCondition, TogetherCondition, EnemyCondition, SoloCondition, PairCondition } from './conditions'
export class AttackAction extends Action {
  protected test: StatTest
  protected successLines: POVPairArgs<Entity, Entity, { damage: Damage }> = new POVPairArgs([
    [[POV.First, POV.Third], (user, target, args) => new LogLine(
      `You smack ${target.name} for `,
      args.damage.renderShort()
    )],
    [[POV.Third, POV.First], (user, target, args) => new LogLine(
      `${user.name.capital} smacks you for `,
      args.damage.renderShort()
    )],
    [[POV.Third, POV.Third], (user, target, args) => new LogLine(
      `${user.name.capital} smacks ${target.name} for `,
      args.damage.renderShort()
    )]
  ])
  protected failLines: POVPair<Entity, Entity> = new POVPair([
    [[POV.First, POV.Third], (user, target) => new LogLine(`You try to smack ${target.name}, but you miss`)],
    [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} misses you`)],
    [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} misses ${target.name}`)]
  ])
  constructor (protected damage: DamageFormula) {
    super(
      'Attack',
      'Attack the enemy',
      [new CapableCondition(), new TogetherCondition(), new EnemyCondition()]
    )
    this.test = new StatTest(Stat.Power)
  }
  execute (user: Creature, target: Creature): LogEntry {
    if (this.test.test(user, target)) {
      const damage = this.damage.calc(user, target)
      const targetResult = target.takeDamage(damage)
      const ownResult = this.successLines.run(user, target, { damage: damage })
      return new CompositeLog(ownResult, targetResult)
    } else {
      return this.failLines.run(user, target)
    }
  }
  describe (user: Creature, target: Creature): LogEntry {
    return new LogLine(`Attack ${target.name}. `, this.damage.describe(user, target), '. ', this.test.explain(user, target))
  }
}
export class DevourAction extends Action {
  private test: StatVigorTest
  protected failLines: POVPairArgs<Entity, Entity, { container: Container }> = new POVPairArgs([
    [[POV.First, POV.Third], (user, target, args) => new LogLine(`You fail to ${args.container.consumeVerb} ${target.name}`)],
    [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital} tries to ${args.container.consumeVerb} you, but fails`)],
    [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${user.name.capital} unsuccessfully tries to ${args.container.consumeVerb} ${target.name}`)]
  ])
  allowed (user: Creature, target: Creature): boolean {
    const owner = this.container.owner === user
    const predOk = Array.from(this.container.voreTypes).every(pref => user.predPrefs.has(pref))
    const preyOk = Array.from(this.container.voreTypes).every(pref => target.preyPrefs.has(pref))
    if (owner && predOk && preyOk) {
      return super.allowed(user, target)
    } else {
      return false
    }
  }
  constructor (protected container: Container) {
    super(
      new DynText(new LiveText(container, x => x.consumeVerb.capital), ' (', new LiveText(container, x => x.name.all), ')'),
      new LiveText(container, x => `Try to ${x.consumeVerb} your foe`),
      [new CapableCondition(), new TogetherCondition()]
    )
    this.test = new StatVigorTest(Stat.Power)
  }
  execute (user: Creature, target: Creature): LogEntry {
    if (this.test.test(user, target)) {
      return this.container.consume(target)
    } else {
      return this.failLines.run(user, target, { container: this.container })
    }
  }
  describe (user: Creature, target: Creature): LogEntry {
    return new LogLine(`Try to ${this.container.consumeVerb} your opponent, sending them to your ${this.container.name}. `, this.test.explain(user, target))
  }
}
export class FeedAction extends Action {
  private test: StatTest
  protected failLines: POVPair<Entity, Entity> = new POVPair([
    [[POV.First, POV.Third], (user, target) => new LogLine(`You fail to feed yourself to ${target.name}`)],
    [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} tries to feed ${user.pronouns.possessive} to you, but fails`)],
    [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} unsuccessfully tries to feed ${user.pronouns.possessive} to ${target.name}`)]
  ])
  allowed (user: Creature, target: Creature): boolean {
    const owner = this.container.owner === target
    const predOk = Array.from(this.container.voreTypes).every(pref => user.predPrefs.has(pref))
    const preyOk = Array.from(this.container.voreTypes).every(pref => target.preyPrefs.has(pref))
    if (owner && predOk && preyOk) {
      return super.allowed(user, target)
    } else {
      return false
    }
  }
  constructor (protected container: Container) {
    super(
      'Feed',
      'Feed yourself to your opponent',
      [new DrainedVigorCondition(Vigor.Resolve), new TogetherCondition()]
    )
    this.name += ` (${container.name})`
    this.test = new StatTest(Stat.Power)
  }
  execute (user: Creature, target: Creature): LogEntry {
    return this.container.consume(user)
  }
  describe (user: Creature, target: Creature): LogEntry {
    return new LogLine(`Your willpower is drained, and you really feel like shoving yourself into ${target.name}'s ${this.container.name}...`)
  }
}
export class StruggleAction extends Action {
  private test: StatVigorTest
  protected failLines: POVPair<Entity, Entity> = new POVPair([
    [[POV.First, POV.Third], (user, target) => new LogLine(`You fail to escape from ${target.name}`)],
    [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} tries to escape from you, but fails`)],
    [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} unsuccessfully struggles against ${target.name}`)]
  ])
  allowed (user: Creature, target: Creature) {
    if (user.containedIn === this.container && this.container.owner === target) {
      return super.allowed(user, target)
    } else {
      return false
    }
  }
  constructor (public container: Container) {
    super(
      new DynText('Struggle (', new LiveText(container, x => x.name.all), ')'),
      'Try to escape from your foe',
      [new CapableCondition(), new PairCondition()]
    )
    this.test = new StatVigorTest(Stat.Power)
  }
  execute (user: Creature, target: Creature): LogEntry {
    if (user.containedIn !== null) {
      if (this.test.test(user, target)) {
        return user.containedIn.release(user)
      } else {
        return this.failLines.run(user, target)
      }
    } else {
      return new LogLine("Vore's bugged!")
    }
  }
  describe (user: Creature, target: Creature): LogEntry {
    return new LogLine(`Try to escape from ${target.name}'s ${this.container.name}. `, this.test.explain(user, target))
  }
}
export abstract class EatenAction extends Action {
  protected lines: POVPair<Entity, Entity> = new POVPair([])
  allowed (user: Creature, target: Creature) {
    if (target.containedIn === this.container) {
      return super.allowed(user, target)
    } else {
      return false
    }
  }
  constructor (public container: Container, name: TextLike, desc: string) {
    super(
      new DynText(name, ' (', new LiveText(container, x => x.name.all), ')'),
      desc,
      [new CapableCondition(), new PairCondition()]
    )
  }
}
export class DigestAction extends Action {
  protected lines: POVPair<Entity, Entity> = new POVPair([])
  allowed (user: Creature, target: Creature) {
    if (this.container.owner === user && this.container.contents.length > 0) {
      return super.allowed(user, target)
    } else {
      return false
    }
  }
  constructor (protected container: VoreContainer) {
    super(
      new DynText('Digest (', new LiveText(container, container => container.name.all), ')'),
      'Digest your prey',
      [new CapableCondition(), new SoloCondition()]
    )
  }
  execute (user: Creature, target: Creature): LogEntry {
    const results = this.container.tick(60)
    return new CompositeLog(results)
  }
  describe (user: Creature, target: Creature): LogEntry {
    return new LogLine(`Digest everyone inside of your ${this.container.name}.`)
  }
}
export class ReleaseAction extends Action {
  allowed (user: Creature, target: Creature) {
    if (target.containedIn === this.container && this.container.contents.indexOf(target) >= 0) {
      return super.allowed(user, target)
    } else {
      return false
    }
  }
  constructor (protected container: Container) {
    super(
      new DynText('Release (', new LiveText(container, x => x.name.all), ')'),
      'Release one of your prey',
      [new CapableCondition(), new PairCondition()]
    )
  }
  execute (user: Creature, target: Creature): LogEntry {
    return this.container.release(target)
  }
  describe (user: Creature, target: Creature): LogEntry {
    return new LogLine(`Release ${target.name} from your ${this.container.name}.`)
  }
}
export class TransferAction extends Action {
  lines: POVPairArgs<Entity, Entity, { from: Container; to: Container }> = new POVPairArgs([
    [[POV.First, POV.Third], (user, target, args) => new LogLine(`You squeeze ${target.name} from your ${args.from.name} to your ${args.to.name}`)],
    [[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}`)],
    [[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}`)]
  ])
  allowed (user: Creature, target: Creature) {
    if (target.containedIn === this.from && this.from.contents.includes(target)) {
      return super.allowed(user, target)
    } else {
      return false
    }
  }
  constructor (protected from: Container, protected to: Container, name = 'Transfer') {
    super(
      name,
      `${from.name.all.capital} to ${to.name.all}`,
      [new CapableCondition(), new PairCondition()]
    )
  }
  execute (user: Creature, target: Creature): LogEntry {
    this.from.release(target)
    this.to.consume(target)
    return this.lines.run(user, target, { from: this.from, to: this.to })
  }
  describe (user: Creature, target: Creature): LogEntry {
    return new LogLine(`Push ${target.name} from your ${this.from.name} to your ${this.to.name}`)
  }
}
 |