import { Creature, POV } from '../entity' import { Damage, DamageType, ConstantDamageFormula, Vigor, Side, GroupAction, CombatTest, Stat, DamageFormula, UniformRandomDamageFormula, Action, DamageInstance, StatDamageFormula, VoreStat } from '../combat' import { ImproperNoun, POVPair, ProperNoun, FemalePronouns, RandomWord, Adjective, POVPairArgs, POVSoloArgs, Verb } from '../language' import { LogLine, LogLines, LogEntry, Newline } from '../interface' import { VoreType, Stomach, VoreContainer, Vore, NormalContainer, Container } from '../vore' import { AttackAction, FeedAction, TransferAction, EatenAction } from '../combat/actions' import { TogetherCondition, ContainerCondition, EnemyCondition, AllyCondition, PairCondition } from '../combat/conditions' import { InstantKill } from '../combat/effects' import * as Words from '../words' import { StatVigorTest } from '../combat/tests' class HypnotizeAction extends Action { lines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`Your hypnotic gaze enthralls ${target.name}, putting ${target.pronouns.objective} under your control!`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s hypnotic gaze enthralls you, putting you under ${user.pronouns.possessive} control!`)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital}'s 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.lines.run(user, target) } describe (user: Creature, target: Creature): LogEntry { return new LogLine(`Force your target to fight by your side`) } constructor () { super( `Hypnotize`, `Change their mind!`, [ new TogetherCondition(), new EnemyCondition() ] ) } } class MawContainer extends NormalContainer { consumeVerb = new Verb('grab', 'grabs', 'grabbing', 'grabbed') releaseVerb = new Verb('release') struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled') consumeLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`You snatch ${target.name} up in your jaws`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} snatches you up in ${user.pronouns.possessive} maw`)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} snatches ${target.name} up in ${user.pronouns.possessive} maw`)] ]) releaseLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`You let out ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} lets you out `)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} lets out ${target.name}`)] ]) struggleLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`You claw your way free of ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} forces ${user.pronouns.possessive} way free!`)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} escapes from ${target.name}`)] ]) constructor (owner: Vore, stomach: VoreContainer) { super(new ImproperNoun('maw'), owner, new Set([VoreType.Oral]), 50) this.actions.push(new TransferAction(this, stomach)) } } class FlexToesAction extends GroupAction { lines = new POVPairArgs([ [[POV.First, POV.Third], (user, target, args) => new LogLine(`Your toes crush ${target.name} for `, args.damage.renderShort(), ` damage!`)], [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital}'s toes crush you for `, args.damage.renderShort(), ` damage!`)], [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${user.name.capital}'s toes crush ${target.name} 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.lines.run(user, target, { damage: damage })) } describe (user: Creature, target: Creature): LogEntry { return new LogLine(`Flex your toes! `, this.damage.describe(user, target)) } constructor (private damage: DamageFormula, container: Container) { super('Flex Toes', 'Flex your toes!', [ new ContainerCondition(container), new PairCondition() ]) } } class BootContainer extends NormalContainer { consumeLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`You stuff ${target.name} into your boot.`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} stuffs you in ${user.pronouns.possessive} boot, pinning you between toes and insole.`)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} stuffs ${target.name} in ${user.pronouns.possessive} boot.`)] ]) releaseLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`You dump ${target.name} out from your boot.`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} dumps you out from ${user.pronouns.possessive} boot.`)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} dumps ${target.name} out from ${user.pronouns.possessive} boot.`)] ]) struggleLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`You slip out from ${target.name}'s boot.`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} squeezes ${user.pronouns.possessive} way free of your footwear!`)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} escapes from ${target.name}'s boot.`)] ]) 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: Vigor.Health, type: DamageType.Crush, amount: 50 }, { target: Vigor.Stamina, type: DamageType.Crush, amount: 50 }, { target: Vigor.Resolve, type: DamageType.Crush, amount: 50 } ), 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 { lines: POVPairArgs = new POVPairArgs([ [[POV.First, POV.Third], (user, target, args: { damage: Damage }) => new LogLine(`You chew on ${target.name} for `, args.damage.renderShort(), `!`)], [[POV.Third, POV.First], (user, target, args: { damage: Damage }) => new LogLine(`${user.name.capital} chews on you for `, args.damage.renderShort(), `!`)], [[POV.Third, POV.Third], (user, target, args: { damage: Damage }) => new LogLine(`${user.name.capital} chews on ${target.name} 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.lines.run(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') } constructor (private damage: DamageFormula, container: Container, private killAction: Action) { super('Chew', 'Give them the big chew', [ new ContainerCondition(container) ]) } } class StompAction extends GroupAction { lines: POVPair = new POVPair([ [[POV.First, POV.Third], (user: Creature, target: Creature) => new LogLine(`You flatten ${target.name} under your foot!`)], [[POV.Third, POV.First], (user: Creature) => new LogLine(`${user.name.capital} flattens you under ${user.pronouns.possessive} ${huge} foot!`)], [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens ${target.name} under ${user.pronouns.possessive} ${huge} foot!`)] ]) execute (user: Creature, target: Creature): LogEntry { return new LogLines(this.lines.run(user, target), new InstantKill().apply(target)) } 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!') } constructor () { super('Stomp', 'STOMP!', [ new TogetherCondition(), new EnemyCondition() ]) } } class StompAllyAction extends Action { lines: POVPair = new POVPair([ [[POV.First, POV.Third], (user: Creature, target: Creature) => new LogLine(`You flatten ${target.name} under your boot!`)], [[POV.Third, POV.First], (user: Creature) => new LogLine(`${user.name.capital} flattens you under ${user.pronouns.possessive} ${huge} boot!`)], [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens ${target.name} 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) return new LogLines( this.lines.run(user, target), new InstantKill().apply(target), 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') } constructor () { super('Stomp Ally', '-1 ally, +1 buff', [ new TogetherCondition(), new AllyCondition() ]) } } class DevourAllAction extends GroupAction { lines: POVPair = new POVPair([ [[POV.First, POV.Third], (user: Creature, target: Creature) => new LogLine(`You scoop up ${target.name}!`)], [[POV.Third, POV.First], (user: Creature) => new LogLine(`${user.name.capital} scoops you up!`)], [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} scoops ${target.name} up!`)] ]) groupLines = new POVSoloArgs([ [[POV.First], (user, args) => new LogLine(`${Words.SwallowSound.allCaps}! All ${args.count} of your prey pour down your ${Words.Slick} throat. They're just ${user.kind.all} chow now`)], [[POV.Third], (user, args) => new LogLine(`${Words.SwallowSound.allCaps}! All ${args.count} of ${user.pronouns.possessive} prey pour down ${user.name}'s ${Words.Slick} gullet as ${user.pronouns.subjective} ${Words.Swallows.singular}; they're just ${user.kind.all} chow now`)] ]) execute (user: Creature, target: Creature): LogEntry { this.container.consume(target) return new LogLines(this.lines.run(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.groupLines.run(user, { count: targets.length }) ] )) } describeGroup (user: Creature, targets: Array): LogEntry { return new LogLine('Eat all ', targets.length.toString(), ' of \'em!') } private test: CombatTest constructor (private container: VoreContainer) { super('Devour All', 'GULP!', [ new TogetherCondition(), new EnemyCondition() ]) this.test = new StatVigorTest(Stat.Power) } } 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 } )) stomach.tickLines = new POVPairArgs([ [[POV.First, POV.Third], (user, target, args) => new LogLine(`Your stomach ${Words.Churns.singular} ${target.name} for `, args.damage.renderShort())], [[POV.Third, POV.First], (user, target, args) => new LogLine(`${user.name.capital}'s stomach ${Words.Churns.singular} you for `, args.damage.renderShort())], [[POV.Third, POV.Third], (user, target, args) => new LogLine(`${user.name.capital} ${Words.Churns.singular} ${target.name} for `, args.damage.renderShort())] ]) stomach.digestLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLine(`Your stomach ${Words.Digests.singular} ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s stomach ${Words.Digests.singular} you`)], [[POV.Third, POV.Third], (user, target) => new LogLine(`${target.name.capital}'s ${Words.Struggles.present} fades as the ${target.kind.all} is ${Words.Digests.past} by the ${user.kind.all}'s ${stomach.name}.`)] ]) 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) this.actions.push(new ChewAction( new UniformRandomDamageFormula(new Damage( { target: Vigor.Health, type: DamageType.Crush, amount: 10000 } ), 0.5), maw, new TransferAction(maw, stomach) )) 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()) } }