import { Entity, Mortal, POV } from './entity' import { Damage, Actionable, Action, DevourAction, DigestAction, ReleaseAction, StruggleAction } from './combat' import { LogLines, LogEntry, CompositeLog } from './interface' import { POVSolo, POVPair, POVPairArgs } from './language' export enum VoreType { Oral = "Oral Vore", Anal = "Anal Vore", Cock = "Cock Vore", Unbirth = "Unbirthing" } export interface Prey extends Mortal { preyPrefs: Set; bulk: number; containedIn: Container | null; } export interface Pred extends Entity { predPrefs: Set; containers: Array; } export interface Container extends Actionable { name: string; owner: Pred; voreTypes: Set; contents: Array; capacity: number; fullness: number; canTake: (prey: Prey) => boolean; consume: (prey: Prey) => LogEntry; release: (prey: Prey) => LogEntry; struggle: (prey: Prey) => LogEntry; tick: (dt: number) => LogEntry; describe: () => LogEntry; digest: (prey: Prey) => LogEntry; absorb: (prey: Prey) => LogEntry; dispose: (preys: Prey[]) => LogEntry; actions: Array; } abstract class NormalContainer implements Container { contents: Array abstract consumeLines: POVPair abstract releaseLines: POVPair abstract struggleLines: POVPair abstract tickLines: POVSolo abstract digestLines: POVPair abstract absorbLines: POVPair abstract disposeLines: POVPair get fullness (): number { return Array.from(this.contents.values()).reduce((total: number, prey: Prey) => total + prey.bulk, 0) } canTake (prey: Prey): boolean { const fits = this.capacity - this.fullness >= prey.bulk const permitted = Array.from(this.voreTypes).every(voreType => { return prey.preyPrefs.has(voreType) }) return fits && permitted } consume (prey: Prey): LogEntry { this.contents.push(prey) prey.containedIn = this return this.consumeLines.run(this.owner, prey) } release (prey: Prey): LogEntry { prey.containedIn = null this.contents = this.contents.filter(victim => victim !== prey) return this.releaseLines.run(this.owner, prey) } struggle (prey: Prey): LogEntry { return this.struggleLines.run(prey, this.owner) } tick (dt: number): LogEntry { const digested: Array = [] const absorbed: Array = [] this.contents.forEach(prey => { const start = prey.health prey.takeDamage(this.damage.scale(dt / 3600)) const end = prey.health if (start > 0 && end <= 0) { digested.push(prey) } else if (start > -100 && end <= -100) { absorbed.push(prey) } }) const digestedEntries = new CompositeLog(...digested.map(prey => this.digest(prey))) const absorbedEntries = new CompositeLog(...digested.map(prey => this.absorb(prey))) this.contents = this.contents.filter(prey => { return prey.health > -100 }) return new CompositeLog(this.tickLines.run(this.owner), digestedEntries, absorbedEntries) } describe (): LogEntry { const lines: Array = [] this.contents.forEach(prey => { lines.push(prey.toString()) }) return new LogLines(...lines) } digest (prey: Prey): LogEntry { return this.digestLines.run(this.owner, prey) } absorb (prey: Prey): LogEntry { return this.absorbLines.run(this.owner, prey) } dispose (preys: Prey[]): LogEntry { return new CompositeLog(...preys.map(prey => this.disposeLines.run(this.owner, prey))) } actions: Array constructor (public name: string, public owner: Pred, public voreTypes: Set, public capacity: number, private damage: Damage) { this.contents = [] this.actions = [] this.actions.push(new DevourAction(this)) this.actions.push(new DigestAction(this)) this.actions.push(new ReleaseAction(this)) this.actions.push(new StruggleAction(this)) } } export class Stomach extends NormalContainer { constructor (owner: Pred, capacity: number, damage: Damage) { super('Stomach', owner, new Set([VoreType.Oral]), capacity, damage) } consumeLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`You devour ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} munches you`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} munches ${target.name.capital}`)] ]) releaseLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`You hork up ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} horks you up`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} horks up ${target.name.capital}`)] ]) struggleLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`You claw your way out of ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} forces ${user.pronouns.possessive} way up your throat!`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} escapes from the gut of ${target.name}`)] ]) tickLines = new POVSolo([ [[POV.First], (user) => new LogLines(`Your stomach gurgles and churns`)], [[POV.Third], (user) => new LogLines(`${user.name.capital}'s gut snarls and gurgles`)] ]) digestLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`Your stomach overwhelms ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s stomach finishes you off`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name.capital}'s squirms fade, overwhelmed by the stomach of ${user.name}`)] ]) absorbLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] ]) disposeLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] ]) } export class Bowels extends NormalContainer { constructor (owner: Pred, capacity: number, damage: Damage) { super('Bowels', owner, new Set([VoreType.Anal]), capacity, damage) } consumeLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`You devour ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} munches you`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} munches ${target.name.capital}`)] ]) releaseLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`You hork up ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} horks you up`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} horks up ${target.name.capital}`)] ]) struggleLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`You claw your way out of ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} forces ${user.pronouns.possessive} way up your throat!`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} escapes from the gut of ${target.name}`)] ]) tickLines = new POVSolo([ [[POV.First], (user) => new LogLines(`Your stomach gurgles and churns!`)], [[POV.Third], (user) => new LogLines(`${user.name.capital}'s gut snarls and gurgles`)] ]) digestLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`Your stomach overwhelms ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s stomach finishes you off`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name.capital}'s squirms fade, overwhelmed by the stomach of ${user.name}`)] ]) absorbLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] ]) disposeLines = new POVPair([ [[POV.First, POV.Third], (user, target) => new LogLines(`Your guts completely absorb ${target.name}`)], [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s guts soak you up like water in a sponge`)], [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] ]) }