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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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}`) } }