import { Creature } from '../entity' import { Damage, DamageType, ConstantDamageFormula, Vigor, Side, GroupAction, CombatTest, Stat, DamageFormula, UniformRandomDamageFormula, Action, DamageInstance, StatDamageFormula, VoreStat } from '../combat' import { ImproperNoun, ProperNoun, FemalePronouns, RandomWord, Adjective, Verb, POV, PairLine } from '../language' import { LogLine, LogLines, LogEntry, Newline } from '../interface' import { VoreType, Stomach, VoreContainer, Vore, NormalContainer, Container, InnerStomach } from '../vore' import { AttackAction, FeedAction, TransferAction, EatenAction, DevourAction } from '../combat/actions' import { TogetherCondition, ContainsCondition, EnemyCondition, AllyCondition, PairCondition, CapableCondition } from '../combat/conditions' import { InstantKillEffect, ShieldEffect, PredatorCounterEffect } from '../combat/effects' import * as Words from '../words' import { StatVigorTest } from '../combat/tests' class LevelDrain extends Action { constructor (private container: Container) { super( 'Level Drain', 'Drain energy from your prey', [ new ContainsCondition(container), new CapableCondition() ] ) } execute (user: Creature, target: Creature): LogEntry { const damage: Damage = new Damage(...Object.keys(Stat).map(stat => { return { type: DamageType.Acid, target: stat as Stat, amount: target.baseStats[stat as Stat] / 5 } })) const heal: Damage = new Damage(...Object.keys(Stat).map(stat => { return { type: DamageType.Heal, target: stat as Stat, amount: target.baseStats[stat as Stat] / 5 } })) // TODO make this respect resistances user.takeDamage(heal) const targetResult = target.takeDamage(damage) return new LogLines( new LogLine(`${user.name.capital.possessive} ${this.container.name} drains power from ${target.name.objective}, siphoning `, damage.renderShort(), ` from ${target.pronouns.possessive} body!`), targetResult ) } describe (user: Creature, target: Creature): LogEntry { return new LogLine(`Drain energy from ${target.name}`) } } class HypnotizeAction extends Action { constructor () { super( `Hypnotize`, `Change their mind!`, [ new TogetherCondition(), new EnemyCondition(), new CapableCondition() ] ) } line: PairLine = (user, target) => new LogLine( `${user.name.capital.possessive} hypnotic gaze enthralls ${target.name}, putting ${target.pronouns.objective} under ${user.pronouns.possessive} control!` ) execute (user: Creature, target: Creature): LogEntry { target.side = user.side return this.line(user, target) } describe (user: Creature, target: Creature): LogEntry { return new LogLine(`Force your target to fight by your side`) } } class MawContainer extends NormalContainer { consumeVerb = new Verb('grab', 'grabs', 'grabbing', 'grabbed') releaseVerb = new Verb('release') struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled') constructor (owner: Vore, stomach: VoreContainer) { super(new ImproperNoun('maw'), owner, new Set([VoreType.Oral]), 50) const transfer = new TransferAction(this, stomach) transfer.verb = new Verb('gulp') this.actions.push(transfer) } } class FlexToesAction extends GroupAction { constructor (private damage: DamageFormula, container: Container) { super('Flex Toes', 'Flex your toes!', [ new ContainsCondition(container), new PairCondition() ]) } line = (user: Creature, target: Creature, args: { damage: Damage }) => new LogLine(`${user.name.capital.possessive} toes crush ${target.name.objective} for `, args.damage.renderShort(), ` damage!`) describeGroup (user: Creature, targets: Creature[]): LogEntry { return new LogLine(`Flex your toes. `, this.damage.explain(user)) } execute (user: Creature, target: Creature): LogEntry { const damage = this.damage.calc(user, target) return new LogLines(target.takeDamage(damage), this.line(user, target, { damage: damage })) } describe (user: Creature, target: Creature): LogEntry { return new LogLine(`Flex your toes! `, this.damage.describe(user, target)) } } class BootContainer extends NormalContainer { consumeVerb = new Verb('trap', 'traps', 'trapped', 'trapping') releaseVerb = new Verb('dump') struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled') constructor (owner: Vore) { super(new ImproperNoun('boot'), owner, new Set(), 50) const flex = new FlexToesAction( new UniformRandomDamageFormula(new Damage( { target: Stat.Toughness, type: DamageType.Crush, amount: 10 }, { target: Stat.Power, type: DamageType.Crush, amount: 10 }, { target: Stat.Speed, type: DamageType.Crush, amount: 10 }, { target: Stat.Willpower, type: DamageType.Crush, amount: 30 }, { target: Stat.Charm, type: DamageType.Crush, amount: 10 } ), 0.5), this ) this.actions.push(flex) } } const huge = new RandomWord([ new Adjective('massive'), new Adjective('colossal'), new Adjective('big ol\''), new Adjective('heavy'), new Adjective('crushing'), new Adjective('huge') ]) class BiteAction extends AttackAction { constructor () { super( new ConstantDamageFormula(new Damage({ amount: 50, type: DamageType.Slash, target: Vigor.Health })), new Verb('bite', 'bites', 'biting', 'bit') ) this.name = "Bite" } } class ChewAction extends GroupAction { constructor (private damage: DamageFormula, container: Container, private killAction: Action) { super('Chew', 'Give them the big chew', [ new ContainsCondition(container) ]) } line = (user: Creature, target: Creature, args: { damage: Damage }) => new LogLine(`${user.name.capital} chews on ${target.name.objective} for `, args.damage.renderShort(), `!`) describeGroup (user: Creature, targets: Creature[]): LogEntry { return new LogLine('Crunch \'em all. ', this.damage.explain(user)) } execute (user: Creature, target: Creature): LogEntry { const damage = this.damage.calc(user, target) const results: Array = [] results.push(this.line(user, target, { damage: damage })) results.push(new LogLine(' ')) results.push(target.takeDamage(damage)) if (target.vigors.Health <= 0) { if (this.killAction.allowed(user, target)) { results.push(new Newline()) results.push(this.killAction.execute(user, target)) } } return new LogLine(...results) } describe (user: Creature, target: Creature): LogEntry { return new LogLine('Do the crunch') } } class StompAction extends GroupAction { constructor () { super('Stomp', 'STOMP!', [ new TogetherCondition(), new EnemyCondition(), new CapableCondition() ]) } line: PairLine = (user, target) => new LogLine( `${user.name.capital} ${user.name.conjugate(new Verb('flatten'))} ${target.name.objective} under ${user.pronouns.possessive} ${huge} foot!` ) execute (user: Creature, target: Creature): LogEntry { return new LogLines(this.line(user, target), target.applyEffect(new InstantKillEffect())) } describe (user: Creature, target: Creature): LogEntry { return new LogLine('Stomp one sucker') } describeGroup (user: Creature, targets: Array): LogEntry { return new LogLine('Stomp all ', targets.length.toString(), ' of \'em!') } } class StompAllyAction extends Action { constructor () { super('Stomp Ally', '-1 ally, +1 buff', [ new TogetherCondition(), new AllyCondition(), new CapableCondition() ]) } line: PairLine = (user, target) => new LogLine( `${user.name.capital} ${user.name.conjugate(new Verb('flatten'))} ${target.name.objective} under ${user.pronouns.possessive} ${huge} boot!` ) execute (user: Creature, target: Creature): LogEntry { const damages: Array = Object.keys(Stat).map(stat => ({ target: stat as Stat, amount: target.stats[stat as Stat] / 3, type: DamageType.Heal })) const heal = new Damage( ...damages ) user.takeDamage(heal) target.destroyed = true return new LogLines( this.line(user, target), target.applyEffect(new InstantKillEffect()), user.applyEffect(new ShieldEffect( [DamageType.Crush, DamageType.Slash, DamageType.Pierce], 0.5 )), new LogLine(`${user.name.capital} absorbs ${target.pronouns.possessive} power, gaining `, heal.renderShort()) ) } describe (user: Creature, target: Creature): LogEntry { return new LogLine('Crush an ally to absorb their power') } } class DevourAllAction extends GroupAction { private test: CombatTest constructor (private container: VoreContainer) { super('Devour All', 'GULP!', [ new TogetherCondition(), new EnemyCondition(), new CapableCondition() ]) this.test = new StatVigorTest(Stat.Power) } line = (user: Creature, target: Creature) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('scoop'))} ${target.name} up!`) groupLine = (user: Creature, args: { count: number }) => new LogLine(`${Words.SwallowSound.allCaps}! All ${args.count} of ${user.pronouns.possessive} prey pour down ${user.name.possessive} ${Words.Slick} gullet as ${user.pronouns.subjective} ${user.name.conjugate(Words.Swallows)}; they're just ${user.kind.all} chow now`) execute (user: Creature, target: Creature): LogEntry { this.container.consume(target) return new LogLines(this.line(user, target)) } describe (user: Creature, target: Creature): LogEntry { return new LogLine('Stomp one sucker') } executeGroup (user: Creature, targets: Array): LogEntry { return new LogLines(...targets.filter(target => this.test.test(user, target)).map(target => this.execute(user, target)).concat( [ new Newline(), this.groupLine(user, { count: targets.length }) ] )) } describeGroup (user: Creature, targets: Array): LogEntry { return new LogLine('Eat all ', targets.length.toString(), ' of \'em!') } } export class Withers extends Creature { title = "Huge Hellhound" desc = "Will eat your party" constructor () { super( new ProperNoun('Withers'), new ImproperNoun('hellhound', 'hellhounds'), FemalePronouns, { Toughness: 40, Power: 50, Speed: 30, Willpower: 40, Charm: 70 }, new Set(), new Set([VoreType.Oral]), 5000 ) this.actions.push(new BiteAction()) this.groupActions.push(new StompAction()) this.side = Side.Monsters const stomach = new Stomach(this, 50, new Damage( { amount: 300, type: DamageType.Acid, target: Vigor.Health }, { amount: 200, type: DamageType.Crush, target: Vigor.Stamina }, { amount: 200, type: DamageType.Dominance, target: Vigor.Resolve } )) this.containers.push(stomach) this.otherActions.push(new FeedAction(stomach)) this.groupActions.push(new DevourAllAction(stomach)) const maw = new MawContainer(this, stomach) this.otherContainers.push(maw) const transfer = new TransferAction(maw, stomach) transfer.verb = new Verb('gulp') this.actions.push(new ChewAction( new UniformRandomDamageFormula(new Damage( { target: Vigor.Health, type: DamageType.Crush, amount: 10000 } ), 0.5), maw, transfer )) const boot = new BootContainer(this) this.otherContainers.push(boot) this.actions.push(new StompAllyAction()) this.actions.push( new AttackAction( new StatDamageFormula([ { fraction: 0.5, stat: Stat.Toughness, target: Vigor.Health, type: DamageType.Crush }, { fraction: 0.05, stat: VoreStat.Bulk, target: Vigor.Health, type: DamageType.Crush } ]), new Verb('stomp') ) ) this.actions.push(new HypnotizeAction()) this.actions.push(new LevelDrain(stomach)) } }