|
- import { Damage, DamageType, Actionable, Action, Vigor, DamageInstance, DamageFormula } from './combat'
- import { LogLines, LogEntry, LogLine, nilLog, RandomEntry } from './interface'
- import { Noun, ImproperNoun, Verb, RandomWord } from './language'
- import { RubAction, DevourAction, ReleaseAction, StruggleAction, TransferAction } from './combat/actions'
- import * as Words from './words'
- import { Creature } from './creature'
-
- export enum VoreType {
- Oral = "Oral Vore",
- Anal = "Anal Vore",
- Cock = "Cock Vore",
- Unbirth = "Unbirthing"
- }
-
- export const anyVore = new Set([
- VoreType.Oral,
- VoreType.Anal,
- VoreType.Cock,
- VoreType.Unbirth
- ])
-
- export interface Container extends Actionable {
- name: Noun;
- owner: Creature;
- voreTypes: Set<VoreType>;
-
- capacity: number;
- fullness: number;
-
- contents: Array<Creature>;
- describe: () => LogEntry;
-
- canTake: (prey: Creature) => boolean;
- consume: (prey: Creature) => LogEntry;
- release: (prey: Creature) => LogEntry;
- struggle: (prey: Creature) => LogEntry;
-
- consumeVerb: Verb;
- releaseVerb: Verb;
- struggleVerb: Verb;
-
- consumeLine (user: Creature, target: Creature): LogEntry;
-
- }
-
- export abstract class NormalContainer implements Container {
- public name: Noun
- contents: Array<Creature> = []
- actions: Array<Action> = []
-
- consumeVerb = new Verb('trap')
- releaseVerb = new Verb('release', 'releases', 'releasing', 'released')
- struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled')
-
- constructor (name: Noun, public owner: Creature, public voreTypes: Set<VoreType>, public capacityFactor: number) {
- this.name = name.all
- this.actions.push(new DevourAction(this))
- this.actions.push(new ReleaseAction(this))
- this.actions.push(new StruggleAction(this))
- }
-
- get capacity (): number {
- return this.capacityFactor * this.owner.voreStats.Mass
- }
-
- consumeLine (user: Creature, target: Creature): LogEntry {
- return new LogLine(`${user.name.capital} ${user.name.conjugate(this.consumeVerb)} ${target.name.objective} in ${user.pronouns.possessive} ${this.name}.`)
- }
-
- releaseLine (user: Creature, target: Creature): LogEntry {
- return new LogLine(`${user.name.capital} ${user.name.conjugate(this.releaseVerb)} ${target.name.objective} up from ${user.pronouns.possessive} ${this.name}.`)
- }
-
- struggleLine (user: Creature, target: Creature): LogEntry {
- return new LogLine(`${user.name.capital} ${user.name.conjugate(this.struggleVerb)} within ${target.name.possessive} ${this.name}.`)
- }
-
- get fullness (): number {
- return Array.from(this.contents.values()).reduce((total: number, prey: Creature) => total + prey.voreStats.Bulk, 0)
- }
-
- canTake (prey: Creature): boolean {
- const fits = this.capacity - this.fullness >= prey.voreStats.Bulk
-
- const permitted = Array.from(this.voreTypes).every(voreType => {
- return prey.preyPrefs.has(voreType)
- })
-
- return fits && permitted
- }
-
- consume (prey: Creature): LogEntry {
- if (prey.containedIn !== null) {
- prey.containedIn.contents = prey.containedIn.contents.filter(item => prey !== item)
- }
- this.contents.push(prey)
- prey.containedIn = this
- return this.consumeLine(this.owner, prey)
- }
-
- release (prey: Creature): LogEntry {
- prey.containedIn = this.owner.containedIn
- this.contents = this.contents.filter(victim => victim !== prey)
-
- if (this.owner.containedIn !== null) {
- this.owner.containedIn.contents.push(prey)
- }
- return this.releaseLine(this.owner, prey)
- }
-
- struggle (prey: Creature): LogEntry {
- return this.struggleLine(prey, this.owner)
- }
-
- describe (): LogEntry {
- const lines: Array<string> = []
-
- this.contents.forEach(prey => {
- lines.push(prey.toString())
- })
-
- return new LogLine(...lines)
- }
- }
-
- export class Hand extends NormalContainer {
- consumeVerb = new Verb("grab")
- constructor (owner: Creature, capacity: number) {
- super(
- new ImproperNoun('hand'),
- owner,
- new Set(),
- capacity
- )
- }
- }
-
- export abstract class InnerContainer extends NormalContainer {
- constructor (name: Noun, owner: Creature, voreTypes: Set<VoreType>, capacity: number, private escape: Container) {
- super(name, owner, voreTypes, capacity)
-
- this.actions = []
-
- this.actions.push(new StruggleAction(this))
- }
-
- release (prey: Creature): LogEntry {
- prey.containedIn = this.escape
- this.contents = this.contents.filter(victim => victim !== prey)
- return this.releaseLine(this.owner, prey)
- }
- }
-
- export interface VoreContainer extends Container {
- digested: Array<Creature>;
- tick: (dt: number) => LogEntry;
- digest: (preys: Creature[]) => LogEntry;
- absorb: (preys: Creature[]) => LogEntry;
- fluidColor: string;
-
- onDigest: (prey: Creature) => LogEntry;
- onAbsorb: (prey: Creature) => LogEntry;
- }
-
- export abstract class NormalVoreContainer extends NormalContainer implements VoreContainer {
- consumeVerb = new Verb('devour')
- releaseVerb = new Verb('release', 'releases', 'releasing', 'released')
- struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled')
- fluidColor = "#00ff0088"
-
- digested: Array<Creature> = []
- absorbed: Array<Creature> = []
-
- constructor (name: Noun, owner: Creature, voreTypes: Set<VoreType>, capacity: number, private damage: DamageFormula) {
- super(name, owner, voreTypes, capacity)
-
- this.name = name
-
- this.actions.push(new RubAction(this))
- }
-
- get fullness (): number {
- return Array.from(this.contents.concat(this.digested, this.absorbed).values()).reduce((total: number, prey: Creature) => total + prey.voreStats.Bulk, 0)
- }
-
- consumeLine (user: Creature, target: Creature) {
- return new RandomEntry(
- new LogLine(`${user.name.capital} ${user.name.conjugate(this.consumeVerb)} ${target.name.objective}, forcing ${target.pronouns.objective} into ${user.pronouns.possessive} ${this.name}.`),
- new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb("pounce"))} on ${target.name.objective} and ${user.name.conjugate(this.consumeVerb)} ${target.pronouns.objective}, ${Words.Force.present} ${target.pronouns.objective} into ${user.pronouns.possessive} ${this.name}.`)
- )
- }
-
- tickLine (user: Creature, target: Creature, args: { damage: Damage }): LogEntry {
- return new RandomEntry(
- new LogLine(`${user.name.capital} ${user.name.conjugate(Words.Churns)} ${target.name.objective} in ${user.pronouns.possessive} ${this.name} for `, args.damage.renderShort(), `.`),
- new LogLine(`${user.name.capital.possessive} ${this.name} ${Words.Churns}, stewing ${target.name.objective} for `, args.damage.renderShort(), `.`),
- new LogLine(`${target.name.capital} ${target.name.conjugate(new Verb("thrash", "thrashes"))} in ${user.name.possessive} ${Words.Slick} ${this.name} as it churns ${target.pronouns.objective} for `, args.damage.renderShort(), `.`)
- )
- }
-
- digestLine (user: Creature, target: Creature): LogEntry {
- return new LogLine(`${user.name.capital.possessive} ${this.name} ${this.name.conjugate(new Verb('finish', 'finishes'))} ${Words.Digests.present} ${target.name.objective} down, ${target.pronouns.possessive} ${Words.Struggles.singular} fading away.`)
- }
-
- absorbLine (user: Creature, target: Creature): LogEntry {
- return new LogLine(`${user.name.capital.possessive} ${this.name} ${this.name.conjugate(new Verb('finish', 'finishes'))} ${Words.Absorbs.present} ${target.name.objective}, fully claiming ${target.pronouns.objective}.`)
- }
-
- tick (dt: number): LogEntry {
- const justDigested: Array<Creature> = []
- const justAbsorbed: Array<Creature> = []
-
- const damageResults: Array<LogEntry> = []
-
- const tickedEntryList: LogEntry[] = []
-
- this.contents.forEach(prey => {
- const scaled = this.damage.calc(this.owner, prey).scale(dt / 60)
- tickedEntryList.push(this.tickLine(this.owner, prey, { damage: scaled }))
-
- damageResults.push(prey.takeDamage(scaled))
-
- if (prey.vigors[Vigor.Health] <= 0) {
- prey.destroyed = true
- this.digested.push(prey)
- justDigested.push(prey)
- damageResults.push(this.onDigest(prey))
- }
- })
-
- const tickedEntries = new LogLines(...tickedEntryList)
-
- this.digested.forEach(prey => {
- const scaled = this.damage.calc(this.owner, prey).scale(dt / 60)
- const damageTotal: number = prey.effectiveDamage(scaled).damages.filter(instance => instance.target === Vigor.Health).reduce(
- (total: number, instance: DamageInstance) => total + instance.amount,
- 0
- )
-
- const massStolen = Math.min(damageTotal / 100, prey.voreStats.Mass)
-
- prey.voreStats.Mass -= massStolen
- this.owner.voreStats.Mass += massStolen
-
- if (prey.voreStats.Mass === 0) {
- this.absorbed.push(prey)
- justAbsorbed.push(prey)
- damageResults.push(this.onAbsorb(prey))
- }
- })
-
- const digestedEntries = this.digest(justDigested)
- const absorbedEntries = this.absorb(justAbsorbed)
-
- this.contents = this.contents.filter(prey => {
- return prey.vigors[Vigor.Health] > 0
- })
-
- this.digested = this.digested.filter(prey => {
- return prey.voreStats.Mass > 0
- })
-
- return new LogLines(tickedEntries, new LogLines(...damageResults), digestedEntries, absorbedEntries)
- }
-
- absorb (preys: Creature[]): LogEntry {
- return new LogLines(...preys.map(prey => this.absorbLine(this.owner, prey)))
- }
-
- digest (preys: Creature[]): LogEntry {
- return new LogLines(...preys.map(prey => this.digestLine(this.owner, prey)))
- }
-
- onAbsorb (prey: Creature): LogEntry {
- return nilLog
- }
-
- onDigest (prey: Creature): LogEntry {
- return nilLog
- }
- }
-
- export abstract class InnerVoreContainer extends NormalVoreContainer {
- constructor (name: Noun, owner: Creature, voreTypes: Set<VoreType>, capacity: number, damage: DamageFormula, private escape: Container) {
- super(name, owner, voreTypes, capacity, damage)
-
- this.actions = []
-
- this.actions.push(new RubAction(this))
- this.actions.push(new StruggleAction(this))
- }
-
- release (prey: Creature): LogEntry {
- prey.containedIn = this.escape
- this.contents = this.contents.filter(victim => victim !== prey)
- this.escape.consume(prey)
- return this.releaseLine(this.owner, prey)
- }
- }
-
- export class Stomach extends NormalVoreContainer {
- constructor (owner: Creature, capacity: number, damage: DamageFormula) {
- super(new ImproperNoun('stomach', 'stomachs').all, owner, new Set([VoreType.Oral]), capacity, damage)
- }
-
- digest (preys: Creature[]): LogEntry {
- if (preys.length === 0) {
- return super.digest(preys)
- }
-
- const heal = new Damage(
- {
- amount: preys.reduce((total: number, next: Creature) => total + next.maxVigors.Health / 5, 0),
- type: DamageType.Heal,
- target: Vigor.Health
- }
- )
- this.owner.takeDamage(heal)
- return new LogLines(
- super.digest(preys),
- new LogLine(`${this.owner.name.capital} ${this.owner.name.conjugate(new Verb("heal"))} for `, this.owner.effectiveDamage(heal).renderShort())
- )
- }
- }
-
- export class InnerStomach extends InnerVoreContainer {
- consumeVerb = new Verb('swallow')
- releaseVerb = new Verb('hork')
- constructor (owner: Creature, capacity: number, damage: DamageFormula, escape: VoreContainer) {
- super(new ImproperNoun('inner stomach', 'inner stomachs').all, owner, new Set([VoreType.Oral]), capacity, damage, escape)
- }
- }
-
- export class Bowels extends NormalVoreContainer {
- constructor (owner: Creature, capacity: number, damage: DamageFormula) {
- super(new ImproperNoun('bowel', 'bowels').plural.all, owner, new Set([VoreType.Anal]), capacity, damage)
- }
-
- tickLine (user: Creature, target: Creature, args: { damage: Damage }) {
- return new RandomEntry(
- new LogLine(`${user.name.capital} ${user.name.conjugate(
- new RandomWord([
- new Verb('crush', 'crushes'),
- new Verb('clench', 'clenches')
- ])
- )} ${target.name.objective} in ${user.pronouns.possessive} ${this.name} for `, args.damage.renderShort(), `.`),
- super.tickLine(user, target, args)
- )
- }
- }
-
- export class Cock extends NormalVoreContainer {
- fluidColor = "#eeeeee66";
-
- constructor (owner: Creature, capacity: number, damage: DamageFormula) {
- super(
- new ImproperNoun('cock').all,
- owner,
- new Set([VoreType.Cock]),
- capacity,
- damage
- )
- }
-
- tickLine (user: Creature, target: Creature, args: { damage: Damage }): LogEntry {
- return new LogLine(`${user.name.capital} ${user.name.conjugate(
- new RandomWord([
- new Verb('crush', 'crushes'),
- new Verb('clench', 'clenches')
- ])
- )} ${target.name.objective} in ${user.pronouns.possessive} ${this.name}.`)
- }
- }
-
- export class Balls extends InnerVoreContainer {
- fluidColor = "#eeeeeecc";
-
- constructor (owner: Creature, capacity: number, damage: DamageFormula, escape: Container) {
- super(
- new ImproperNoun('ball', 'balls').all.plural,
- owner,
- new Set([VoreType.Cock]),
- capacity,
- damage,
- escape
- )
- }
- }
-
- export class Slit extends NormalVoreContainer {
- fluidColor = "#cccccc99";
-
- constructor (owner: Creature, capacity: number, damage: DamageFormula) {
- super(
- new ImproperNoun('slit').all,
- owner,
- new Set([VoreType.Unbirth]),
- capacity,
- damage
- )
- }
- }
-
- export class Womb extends InnerVoreContainer {
- fluidColor = "#ddddddbb";
-
- constructor (owner: Creature, capacity: number, damage: DamageFormula, escape: Container) {
- super(
- new ImproperNoun('womb').all,
- owner,
- new Set([VoreType.Unbirth]),
- capacity,
- damage,
- escape
- )
- }
- }
-
- export function biconnectContainers (outer: VoreContainer, inner: VoreContainer): void {
- outer.onDigest = (prey: Creature) => {
- outer.digested = outer.digested.filter(victim => victim !== prey)
- inner.digested.push(prey)
- return inner.consumeLine(inner.owner, prey)
- }
-
- outer.actions.push(
- new TransferAction(
- outer,
- inner
- )
- )
-
- inner.actions.push(
- new TransferAction(
- inner,
- outer
- )
- )
- }
|