| @@ -71,6 +71,12 @@ export interface CombatTest { | |||||
| explain: (user: Creature, target: Creature) => LogEntry; | explain: (user: Creature, target: Creature) => LogEntry; | ||||
| } | } | ||||
| export interface Effect { | |||||
| name: string; | |||||
| desc: string; | |||||
| apply: (target: Creature) => LogEntry; | |||||
| } | |||||
| export class Damage { | export class Damage { | ||||
| readonly damages: DamageInstance[] | readonly damages: DamageInstance[] | ||||
| @@ -172,36 +178,11 @@ export interface Condition { | |||||
| allowed: (user: Creature, target: Creature) => boolean; | allowed: (user: Creature, target: Creature) => boolean; | ||||
| } | } | ||||
| class InverseCondition implements Condition { | |||||
| allowed (user: Creature, target: Creature): boolean { | |||||
| return !this.condition.allowed(user, target) | |||||
| } | |||||
| constructor (private condition: Condition) { | |||||
| } | |||||
| } | |||||
| class CapableCondition implements Condition { | |||||
| allowed (user: Creature, target: Creature): boolean { | |||||
| return !user.disabled | |||||
| } | |||||
| } | |||||
| class DrainedVigorCondition implements Condition { | |||||
| allowed (user: Creature, target: Creature): boolean { | |||||
| return user.vigors[this.vigor] <= 0 | |||||
| } | |||||
| constructor (private vigor: Vigor) { | |||||
| } | |||||
| } | |||||
| export interface Actionable { | export interface Actionable { | ||||
| actions: Array<Action>; | actions: Array<Action>; | ||||
| } | } | ||||
| abstract class SelfAction extends Action { | |||||
| export abstract class SelfAction extends Action { | |||||
| allowed (user: Creature, target: Creature) { | allowed (user: Creature, target: Creature) { | ||||
| if (user === target) { | if (user === target) { | ||||
| return super.allowed(user, target) | return super.allowed(user, target) | ||||
| @@ -211,7 +192,7 @@ abstract class SelfAction extends Action { | |||||
| } | } | ||||
| } | } | ||||
| abstract class PairAction extends Action { | |||||
| export abstract class PairAction extends Action { | |||||
| allowed (user: Creature, target: Creature) { | allowed (user: Creature, target: Creature) { | ||||
| if (user !== target) { | if (user !== target) { | ||||
| return super.allowed(user, target) | return super.allowed(user, target) | ||||
| @@ -221,7 +202,7 @@ abstract class PairAction extends Action { | |||||
| } | } | ||||
| } | } | ||||
| abstract class TogetherAction extends PairAction { | |||||
| export abstract class TogetherAction extends PairAction { | |||||
| allowed (user: Creature, target: Creature) { | allowed (user: Creature, target: Creature) { | ||||
| if (user.containedIn === target.containedIn) { | if (user.containedIn === target.containedIn) { | ||||
| return super.allowed(user, target) | return super.allowed(user, target) | ||||
| @@ -230,254 +211,3 @@ abstract class TogetherAction extends PairAction { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| export class AttackAction extends TogetherAction { | |||||
| protected test: StatTest | |||||
| protected successLines: POVPairArgs<Entity, Entity, { damage: Damage }> = 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<Entity, Entity> = new POVPair([ | |||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You try to smack ${target.name}, but you miss`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} misses you`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} misses ${target.name}`)] | |||||
| ]) | |||||
| constructor (protected damage: DamageFormula) { | |||||
| super('Attack', 'Attack the enemy', [new CapableCondition()]) | |||||
| 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 TogetherAction { | |||||
| private test: StatVigorTest | |||||
| protected failLines: POVPair<Entity, Entity> = new POVPair([ | |||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You fail to make a meal out of ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} tries to devour you, but fails`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} unsuccessfully tries to swallow ${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('Devour (', new LiveText(container, x => x.name.all), ')'), 'Try to consume your foe', [new CapableCondition()]) | |||||
| 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) | |||||
| } | |||||
| } | |||||
| describe (user: Creature, target: Creature): LogEntry { | |||||
| return new LogLine(`Try to consume your opponent, sending them to your ${this.container.name}. `, this.test.explain(user, target)) | |||||
| } | |||||
| } | |||||
| export class FeedAction extends TogetherAction { | |||||
| private test: StatTest | |||||
| protected failLines: POVPair<Entity, Entity> = new POVPair([ | |||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You fail to feed yourself to ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} tries to feed ${user.pronouns.possessive} to you, but fails`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${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)]) | |||||
| 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 PairAction { | |||||
| private test: StatVigorTest | |||||
| protected failLines: POVPair<Entity, Entity> = new POVPair([ | |||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You fail to escape from ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} tries to escape from you, but fails`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} unsuccessfully struggles within ${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()]) | |||||
| 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 LogLines("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 PairAction { | |||||
| protected lines: POVPair<Entity, Entity> = 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()]) | |||||
| } | |||||
| } | |||||
| export class DigestAction extends SelfAction { | |||||
| protected lines: POVPair<Entity, Entity> = 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: Container) { | |||||
| super(new DynText('Digest (', new LiveText(container, container => container.name.all), ')'), 'Digest your prey', [new CapableCondition()]) | |||||
| } | |||||
| 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 PairAction { | |||||
| 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()]) | |||||
| } | |||||
| 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 PairAction { | |||||
| lines: POVPairArgs<Entity, Entity, { from: Container; to: Container }> = 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} to ${user.pronouns.possessive} ${args.to.name}`)] | |||||
| ]) | |||||
| allowed (user: Creature, target: Creature) { | |||||
| if (target.containedIn === this.from) { | |||||
| return super.allowed(user, target) | |||||
| } else { | |||||
| return false | |||||
| } | |||||
| } | |||||
| constructor (protected from: Container, protected to: Container) { | |||||
| super('Transfer', `Move from your ${from.name} to your ${to.name}`, [new CapableCondition()]) | |||||
| } | |||||
| 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}`) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,258 @@ | |||||
| import { StatTest, StatVigorTest } from './tests' | |||||
| import { POVPairArgs, POVPair, DynText, LiveText, TextLike } from '../language' | |||||
| import { Entity, POV, Creature } from '../entity' | |||||
| import { Damage, DamageFormula, Stat, Vigor, TogetherAction, PairAction, SelfAction } from '../combat' | |||||
| import { LogLine, LogLines, LogEntry, CompositeLog } from '../interface' | |||||
| import { Container } from '../vore' | |||||
| import { CapableCondition, DrainedVigorCondition } from './conditions' | |||||
| export class AttackAction extends TogetherAction { | |||||
| protected test: StatTest | |||||
| protected successLines: POVPairArgs<Entity, Entity, { damage: Damage }> = 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<Entity, Entity> = 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()]) | |||||
| 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 TogetherAction { | |||||
| private test: StatVigorTest | |||||
| protected failLines: POVPair<Entity, Entity> = new POVPair([ | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You fail to make a meal out of ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} tries to devour you, but fails`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} unsuccessfully tries to swallow ${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('Devour (', new LiveText(container, x => x.name.all), ')'), 'Try to consume your foe', [new CapableCondition()]) | |||||
| 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) | |||||
| } | |||||
| } | |||||
| describe (user: Creature, target: Creature): LogEntry { | |||||
| return new LogLine(`Try to consume your opponent, sending them to your ${this.container.name}. `, this.test.explain(user, target)) | |||||
| } | |||||
| } | |||||
| export class FeedAction extends TogetherAction { | |||||
| private test: StatTest | |||||
| protected failLines: POVPair<Entity, Entity> = 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)]) | |||||
| 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 PairAction { | |||||
| private test: StatVigorTest | |||||
| protected failLines: POVPair<Entity, Entity> = 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 within ${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()]) | |||||
| 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 PairAction { | |||||
| protected lines: POVPair<Entity, Entity> = 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()]) | |||||
| } | |||||
| } | |||||
| export class DigestAction extends SelfAction { | |||||
| protected lines: POVPair<Entity, Entity> = 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: Container) { | |||||
| super(new DynText('Digest (', new LiveText(container, container => container.name.all), ')'), 'Digest your prey', [new CapableCondition()]) | |||||
| } | |||||
| 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 PairAction { | |||||
| 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()]) | |||||
| } | |||||
| 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 PairAction { | |||||
| lines: POVPairArgs<Entity, Entity, { from: Container; to: Container }> = 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} to ${user.pronouns.possessive} ${args.to.name}`)] | |||||
| ]) | |||||
| allowed (user: Creature, target: Creature) { | |||||
| if (target.containedIn === this.from) { | |||||
| return super.allowed(user, target) | |||||
| } else { | |||||
| return false | |||||
| } | |||||
| } | |||||
| constructor (protected from: Container, protected to: Container) { | |||||
| super('Transfer', `Move from your ${from.name} to your ${to.name}`, [new CapableCondition()]) | |||||
| } | |||||
| 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}`) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,27 @@ | |||||
| import { Condition, Vigor } from "../combat" | |||||
| import { Creature } from "../entity" | |||||
| export class InverseCondition implements Condition { | |||||
| allowed (user: Creature, target: Creature): boolean { | |||||
| return !this.condition.allowed(user, target) | |||||
| } | |||||
| constructor (private condition: Condition) { | |||||
| } | |||||
| } | |||||
| export class CapableCondition implements Condition { | |||||
| allowed (user: Creature, target: Creature): boolean { | |||||
| return !user.disabled | |||||
| } | |||||
| } | |||||
| export class DrainedVigorCondition implements Condition { | |||||
| allowed (user: Creature, target: Creature): boolean { | |||||
| return user.vigors[this.vigor] <= 0 | |||||
| } | |||||
| constructor (private vigor: Vigor) { | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| import { Creature, POV } from '../entity' | |||||
| import { LogEntry, LogLine, FAElem } from '../interface' | |||||
| import { Effect } from '../combat' | |||||
| import { POVSolo } from '../language' | |||||
| export class InstantKill implements Effect { | |||||
| lines = new POVSolo<Creature>([ | |||||
| [[POV.First], (target: Creature) => new LogLine(`You're killed instantly! `, new FAElem('fas fa-skull'))], | |||||
| [[POV.Third], (target: Creature) => new LogLine(`${target.name.capital} is killed instantly! `, new FAElem('fas fa-skull'))] | |||||
| ]) | |||||
| name = "Instant Kill" | |||||
| desc = "Instantly kills its victim" | |||||
| apply (target: Creature): LogEntry { | |||||
| target.vigors.Health = Math.min(0, target.vigors.Health) | |||||
| return this.lines.run(target) | |||||
| } | |||||
| } | |||||
| @@ -128,6 +128,6 @@ export class ChanceTest extends RandomTest { | |||||
| } | } | ||||
| explain (user: Creature, target: Creature): LogEntry { | explain (user: Creature, target: Creature): LogEntry { | ||||
| return new LogLines('You have a flat ' + (100 * this.chance) + '% chance.') | |||||
| return new LogLine('You have a flat ' + (100 * this.chance) + '% chance.') | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,8 +1,10 @@ | |||||
| import { Creature, POV, Entity } from '../entity' | import { Creature, POV, Entity } from '../entity' | ||||
| import { Stat, Damage, DamageType, TransferAction, Vigor, FeedAction, EatenAction, AttackAction, ConstantDamageFormula } from '../combat' | |||||
| import { Stat, Damage, DamageType, Vigor, ConstantDamageFormula } from '../combat' | |||||
| import { ProperNoun, TheyPronouns, ImproperNoun, POVPair, FemalePronouns, POVPairArgs } from '../language' | import { ProperNoun, TheyPronouns, ImproperNoun, POVPair, FemalePronouns, POVPairArgs } from '../language' | ||||
| import { VoreType, Stomach, InnerStomach, Container } from '../vore' | import { VoreType, Stomach, InnerStomach, Container } from '../vore' | ||||
| import { LogLine, LogLines, LogEntry, FAElem, CompositeLog, ImgElem } from '../interface' | import { LogLine, LogLines, LogEntry, FAElem, CompositeLog, ImgElem } from '../interface' | ||||
| import { AttackAction, EatenAction, TransferAction, FeedAction } from '../combat/actions' | |||||
| import { InstantKill } from '../combat/effects' | |||||
| class BellyCrushAction extends AttackAction { | class BellyCrushAction extends AttackAction { | ||||
| successLines = new POVPairArgs<Entity, Entity, { damage: Damage }>([ | successLines = new POVPairArgs<Entity, Entity, { damage: Damage }>([ | ||||
| @@ -56,25 +58,21 @@ class BelchAction extends AttackAction { | |||||
| this.desc = 'Drain your foe\'s willpower with a solid BELCH' | this.desc = 'Drain your foe\'s willpower with a solid BELCH' | ||||
| } | } | ||||
| } | } | ||||
| class CrushAction extends EatenAction { | class CrushAction extends EatenAction { | ||||
| lines: POVPair<Entity, Entity> = new POVPair([ | lines: POVPair<Entity, Entity> = new POVPair([ | ||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You crush ${target.name} `, new FAElem('fas fa-skull'))], | |||||
| [[POV.Third, POV.First], (user) => new CompositeLog(new LogLine(`${user.name.capital} crushes you; ${user.pronouns.subjective} ${user.pronouns.isPlural ? 'belch' : 'belches'} as ${user.pronouns.possessive} gut lets out a fatal CRUNCH `, new FAElem('fas fa-skull')), new ImgElem('./media/cafat/images/crunch.webp'))], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} crushes ${target.name}; ${user.pronouns.subjective} ${user.pronouns.isPlural ? 'belch' : 'belches'} as ${user.pronouns.possessive} gut lets out a fatal CRUNCH `, new FAElem('fas fa-skull'))] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You crush ${target.name} `)], | |||||
| [[POV.Third, POV.First], (user) => new CompositeLog(new LogLine(`${user.name.capital} crushes you; ${user.pronouns.subjective} ${user.pronouns.isPlural ? 'belch' : 'belches'} as ${user.pronouns.possessive} gut lets out a fatal CRUNCH `), new ImgElem('./media/cafat/images/crunch.webp'))], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} crushes ${target.name}; ${user.pronouns.subjective} ${user.pronouns.isPlural ? 'belch' : 'belches'} as ${user.pronouns.possessive} gut lets out a fatal CRUNCH `)] | |||||
| ]) | ]) | ||||
| private damage: Damage = new Damage( | |||||
| { amount: 99, type: DamageType.Crush, target: Vigor.Health } | |||||
| ) | |||||
| constructor (container: Container) { | constructor (container: Container) { | ||||
| super(container, "Crush", "Crush 'em!") | super(container, "Crush", "Crush 'em!") | ||||
| this.desc = "Crush somebody in your gut" | this.desc = "Crush somebody in your gut" | ||||
| } | } | ||||
| execute (user: Creature, target: Creature): LogEntry { | execute (user: Creature, target: Creature): LogEntry { | ||||
| target.takeDamage(this.damage) | |||||
| return this.lines.run(user, target) | |||||
| return new LogLines(this.lines.run(user, target), new InstantKill().apply(target)) | |||||
| } | } | ||||
| describe (user: Creature, target: Creature): LogEntry { | describe (user: Creature, target: Creature): LogEntry { | ||||
| @@ -118,9 +116,9 @@ export class Cafat extends Creature { | |||||
| lowerStomach.name = new ImproperNoun("lower stomach", "lower stomachs").all | lowerStomach.name = new ImproperNoun("lower stomach", "lower stomachs").all | ||||
| stomach.consumeLines = new POVPair([ | stomach.consumeLines = new POVPair([ | ||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You devour ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user) => new CompositeLog(new LogLines(`${user.name.capital} devours you`), new ImgElem('./media/cafat/images/stomach.webp'))], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} munches ${target.name.capital}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You devour ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user) => new CompositeLog(new LogLine(`${user.name.capital} devours you`), new ImgElem('./media/cafat/images/stomach.webp'))], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} munches ${target.name.capital}`)] | |||||
| ]) | ]) | ||||
| const crush = new CrushAction(lowerStomach) | const crush = new CrushAction(lowerStomach) | ||||
| @@ -1,7 +1,8 @@ | |||||
| import { Creature, POV } from '../entity' | import { Creature, POV } from '../entity' | ||||
| import { ProperNoun, TheyPronouns } from '../language' | import { ProperNoun, TheyPronouns } from '../language' | ||||
| import { Stat, Damage, AttackAction, DamageType, Vigor, ConstantDamageFormula } from '../combat' | |||||
| import { Stat, Damage, DamageType, Vigor, ConstantDamageFormula } from '../combat' | |||||
| import { Stomach, Bowels, VoreType } from '../vore' | import { Stomach, Bowels, VoreType } from '../vore' | ||||
| import { AttackAction } from '../combat/actions' | |||||
| export class Player extends Creature { | export class Player extends Creature { | ||||
| constructor () { | constructor () { | ||||
| @@ -1,9 +1,10 @@ | |||||
| import { Creature, POV, Entity } from '../entity' | import { Creature, POV, Entity } from '../entity' | ||||
| import { Stat, Damage, DamageType, AttackAction, TransferAction, Vigor, FeedAction, ConstantDamageFormula } from '../combat' | |||||
| import { Stat, Damage, DamageType, ConstantDamageFormula, Vigor } from '../combat' | |||||
| import { MalePronouns, ImproperNoun, POVPair, POVPairArgs } from '../language' | import { MalePronouns, ImproperNoun, POVPair, POVPairArgs } from '../language' | ||||
| import { LogLine, LogLines } from '../interface' | import { LogLine, LogLines } from '../interface' | ||||
| import { VoreType, Stomach, Bowels } from '../vore' | import { VoreType, Stomach, Bowels } from '../vore' | ||||
| import { StatTest } from '../combat/tests' | import { StatTest } from '../combat/tests' | ||||
| import { AttackAction, TransferAction, FeedAction } from '../combat/actions' | |||||
| class BiteAction extends AttackAction { | class BiteAction extends AttackAction { | ||||
| constructor () { | constructor () { | ||||
| @@ -29,9 +30,9 @@ class HypnoAction extends AttackAction { | |||||
| ]) | ]) | ||||
| protected failLines: POVPair<Entity, Entity> = new POVPair([ | protected failLines: POVPair<Entity, Entity> = new POVPair([ | ||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You try to hypnotize ${target.name}, but you miss`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} misses you`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name} misses ${target.name}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You try to hypnotize ${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(`${target.name} misses ${target.name}`)] | |||||
| ]) | ]) | ||||
| constructor () { | constructor () { | ||||
| @@ -5,18 +5,28 @@ export interface LogEntry { | |||||
| } | } | ||||
| export class LogLines implements LogEntry { | export class LogLines implements LogEntry { | ||||
| lines: string[] | |||||
| private parts: Array<string|LogEntry> | |||||
| constructor (...lines: string[]) { | |||||
| this.lines = lines | |||||
| constructor (...parts: Array<string|LogEntry>) { | |||||
| this.parts = parts | |||||
| } | } | ||||
| render (): HTMLElement[] { | render (): HTMLElement[] { | ||||
| return this.lines.map(line => { | |||||
| const div = document.createElement("div") | |||||
| div.innerText = line | |||||
| return div | |||||
| const div = document.createElement("div") | |||||
| this.parts.forEach(part => { | |||||
| if (typeof part === "string") { | |||||
| const partDiv = document.createElement("span") | |||||
| partDiv.innerText = part | |||||
| div.appendChild(partDiv) | |||||
| } else { | |||||
| (part as LogEntry).render().forEach(logPart => { | |||||
| div.appendChild(logPart) | |||||
| }) | |||||
| } | |||||
| }) | }) | ||||
| return [div] | |||||
| } | } | ||||
| } | } | ||||
| @@ -114,8 +124,11 @@ export class PropElem implements LogEntry { | |||||
| const span = document.createElement("span") | const span = document.createElement("span") | ||||
| span.classList.add("stat-entry") | span.classList.add("stat-entry") | ||||
| span.dataset.tooltip = this.prop | |||||
| if (this.prop in Stat) { | |||||
| span.dataset.tooltip = this.prop | |||||
| } else if (this.prop in Vigor) { | |||||
| span.dataset.tooltip = this.prop | |||||
| } | |||||
| if (this.prop in Stat) { | if (this.prop in Stat) { | ||||
| span.dataset.tooltipFull = StatDescs[this.prop as Stat] | span.dataset.tooltipFull = StatDescs[this.prop as Stat] | ||||
| } else if (this.prop in Vigor) { | } else if (this.prop in Vigor) { | ||||
| @@ -1,12 +1,12 @@ | |||||
| import { Entity, POV } from './entity' | import { Entity, POV } from './entity' | ||||
| import { LogEntry, LogLines } from './interface' | |||||
| import { LogEntry, LogLines, LogLine } from './interface' | |||||
| export class POVPair<K extends Entity, V extends Entity> { | export class POVPair<K extends Entity, V extends Entity> { | ||||
| run (user: K, target: V): LogEntry { | run (user: K, target: V): LogEntry { | ||||
| const choice = this.options.find(element => element[0][0] === user.perspective && element[0][1] === target.perspective) | const choice = this.options.find(element => element[0][0] === user.perspective && element[0][1] === target.perspective) | ||||
| if (choice === undefined) { | if (choice === undefined) { | ||||
| return new LogLines("Fen didn't write any text for this...") | |||||
| return new LogLine("Fen didn't write any text for this...") | |||||
| } else { | } else { | ||||
| return choice[1](user, target) | return choice[1](user, target) | ||||
| } | } | ||||
| @@ -22,7 +22,7 @@ export class POVPairArgs<K extends Entity, V extends Entity, U> { | |||||
| const choice = this.options.find(element => element[0][0] === user.perspective && element[0][1] === target.perspective) | const choice = this.options.find(element => element[0][0] === user.perspective && element[0][1] === target.perspective) | ||||
| if (choice === undefined) { | if (choice === undefined) { | ||||
| return new LogLines("Fen didn't write any text for this...") | |||||
| return new LogLine("Fen didn't write any text for this...") | |||||
| } else { | } else { | ||||
| return choice[1](user, target, args) | return choice[1](user, target, args) | ||||
| } | } | ||||
| @@ -37,7 +37,7 @@ export class POVSolo<K extends Entity> { | |||||
| const choice = this.options.find(element => element[0][0] === user.perspective) | const choice = this.options.find(element => element[0][0] === user.perspective) | ||||
| if (choice === undefined) { | if (choice === undefined) { | ||||
| return new LogLines("Fen didn't write any text for this...") | |||||
| return new LogLine("Fen didn't write any text for this...") | |||||
| } else { | } else { | ||||
| return choice[1](user, args) | return choice[1](user, args) | ||||
| } | } | ||||
| @@ -1,7 +1,8 @@ | |||||
| import { Entity, Mortal, POV, Creature } from './entity' | import { Entity, Mortal, POV, Creature } from './entity' | ||||
| import { Damage, DamageType, Stats, Actionable, Action, DevourAction, FeedAction, DigestAction, ReleaseAction, StruggleAction, Vigor } from './combat' | |||||
| import { Damage, DamageType, Stats, Actionable, Action, Vigor } from './combat' | |||||
| import { LogLines, LogEntry, CompositeLog, LogLine } from './interface' | import { LogLines, LogEntry, CompositeLog, LogLine } from './interface' | ||||
| import { Noun, Pronoun, POVPair, POVPairArgs, ImproperNoun } from './language' | import { Noun, Pronoun, POVPair, POVPairArgs, ImproperNoun } from './language' | ||||
| import { DigestAction, DevourAction, ReleaseAction, StruggleAction } from './combat/actions' | |||||
| export enum VoreType { | export enum VoreType { | ||||
| Oral = "Oral Vore", | Oral = "Oral Vore", | ||||
| @@ -142,7 +143,7 @@ abstract class NormalContainer implements Container { | |||||
| lines.push(prey.toString()) | lines.push(prey.toString()) | ||||
| }) | }) | ||||
| return new LogLines(...lines) | |||||
| return new LogLine(...lines) | |||||
| } | } | ||||
| digest (prey: Vore): LogEntry { | digest (prey: Vore): LogEntry { | ||||
| @@ -196,21 +197,21 @@ export class Stomach extends NormalContainer { | |||||
| } | } | ||||
| consumeLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You devour ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} munches you`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} munches ${target.name}`)] | |||||
| ]) | ]) | ||||
| releaseLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You hork up ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} horks you up`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} horks up ${target.name}`)] | |||||
| ]) | ]) | ||||
| struggleLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You claw your way out of ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} forces ${user.pronouns.possessive} way up your throat!`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} escapes from the gut of ${target.name}`)] | |||||
| ]) | ]) | ||||
| tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([ | tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([ | ||||
| @@ -220,21 +221,21 @@ export class Stomach extends NormalContainer { | |||||
| ]) | ]) | ||||
| digestLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your stomach overwhelms ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s stomach finishes you off`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${target.name.capital}'s squirms fade, overwhelmed by the stomach of ${user.name}`)] | |||||
| ]) | ]) | ||||
| absorbLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your guts completely absorb ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s guts soak you up like water in a sponge`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] | |||||
| ]) | ]) | ||||
| disposeLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your guts completely absorb ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s guts soak you up like water in a sponge`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] | |||||
| ]) | ]) | ||||
| } | } | ||||
| @@ -244,21 +245,21 @@ export class InnerStomach extends InnerContainer { | |||||
| } | } | ||||
| consumeLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You devour ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} munches you`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} munches ${target.name.capital}`)] | |||||
| ]) | ]) | ||||
| releaseLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You hork up ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} horks you up`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} horks up ${target.name.capital}`)] | |||||
| ]) | ]) | ||||
| struggleLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You claw your way out of ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} forces ${user.pronouns.possessive} way up your throat!`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} escapes from the gut of ${target.name}`)] | |||||
| ]) | ]) | ||||
| tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([ | tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([ | ||||
| @@ -268,21 +269,21 @@ export class InnerStomach extends InnerContainer { | |||||
| ]) | ]) | ||||
| digestLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your stomach overwhelms ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s stomach finishes you off`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${target.name.capital}'s squirms fade, overwhelmed by the stomach of ${user.name}`)] | |||||
| ]) | ]) | ||||
| absorbLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your guts completely absorb ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s guts soak you up like water in a sponge`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] | |||||
| ]) | ]) | ||||
| disposeLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your guts completely absorb ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s guts soak you up like water in a sponge`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] | |||||
| ]) | ]) | ||||
| } | } | ||||
| @@ -292,21 +293,21 @@ export class Bowels extends NormalContainer { | |||||
| } | } | ||||
| consumeLines = new POVPair([ | consumeLines = new POVPair([ | ||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You force ${target.name} into your bowels`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} works you into ${user.pronouns.possessive} ass`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} anal-vores ${target.name.capital}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You force ${target.name} into your bowels`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} works you into ${user.pronouns.possessive} ass`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} anal-vores ${target.name.capital}`)] | |||||
| ]) | ]) | ||||
| releaseLines = new POVPair([ | releaseLines = new POVPair([ | ||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`You let out ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} lets you out `)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} lets out ${target.name.capital}`)] | |||||
| [[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.capital}`)] | |||||
| ]) | ]) | ||||
| struggleLines = new POVPair([ | 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 out your rump!`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${user.name.capital} escapes from the bowels of ${target.name}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`You claw your way out of ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital} forces ${user.pronouns.possessive} way out your rump!`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} escapes from the bowels of ${target.name}`)] | |||||
| ]) | ]) | ||||
| tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([ | tickLines = new POVPairArgs<Vore, Vore, { damage: Damage }>([ | ||||
| @@ -316,20 +317,20 @@ export class Bowels extends NormalContainer { | |||||
| ]) | ]) | ||||
| digestLines = new POVPair([ | digestLines = new POVPair([ | ||||
| [[POV.First, POV.Third], (user, target) => new LogLines(`Your bowels overwhelm ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital}'s bowels finish you off`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name.capital}'s squirms fade, overwhelmed by the bowels of ${user.name}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your bowels overwhelm ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s bowels finish you off`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${target.name.capital}'s squirms fade, overwhelmed by the bowels of ${user.name}`)] | |||||
| ]) | ]) | ||||
| absorbLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your guts completely absorb ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s guts soak you up like water in a sponge`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] | |||||
| ]) | ]) | ||||
| disposeLines = new POVPair([ | 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}`)] | |||||
| [[POV.First, POV.Third], (user, target) => new LogLine(`Your guts completely absorb ${target.name}`)], | |||||
| [[POV.Third, POV.First], (user, target) => new LogLine(`${user.name.capital}'s guts soak you up like water in a sponge`)], | |||||
| [[POV.Third, POV.Third], (user, target) => new LogLine(`${user.name.capital} finishes absorbing the remains of ${target.name}`)] | |||||
| ]) | ]) | ||||
| } | } | ||||