| @@ -10,7 +10,8 @@ export enum DamageType { | |||
| Crush = "Crush", | |||
| Acid = "Acid", | |||
| Seduction = "Seduction", | |||
| Dominance = "Dominance" | |||
| Dominance = "Dominance", | |||
| Heal = "Heal" | |||
| } | |||
| export interface DamageInstance { | |||
| @@ -147,10 +148,11 @@ export class Damage { | |||
| const vigorTotals: Vigors = Object.keys(Vigor).reduce((total: any, key) => { total[key] = 0; return total }, {}) | |||
| const statTotals: Stats = Object.keys(Stat).reduce((total: any, key) => { total[key] = 0; return total }, {}) | |||
| this.damages.forEach(instance => { | |||
| const factor = instance.type === DamageType.Heal ? -1 : 1 | |||
| if (instance.target in Vigor) { | |||
| vigorTotals[instance.target as Vigor] += instance.amount | |||
| vigorTotals[instance.target as Vigor] += factor * instance.amount | |||
| } else if (instance.target in Stat) { | |||
| statTotals[instance.target as Stat] += instance.amount | |||
| statTotals[instance.target as Stat] += factor * instance.amount | |||
| } | |||
| }) | |||
| @@ -213,13 +215,28 @@ export class UniformRandomDamageFormula implements DamageFormula { | |||
| export class StatDamageFormula implements DamageFormula { | |||
| calc (user: Creature, target: Creature): Damage { | |||
| const instances: Array<DamageInstance> = this.factors.map(factor => ( | |||
| { | |||
| amount: factor.fraction * user.stats[factor.stat], | |||
| target: factor.target, | |||
| type: factor.type | |||
| const instances: Array<DamageInstance> = this.factors.map(factor => { | |||
| if (factor.stat in Stat) { | |||
| return { | |||
| amount: factor.fraction * user.stats[factor.stat as Stat], | |||
| target: factor.target, | |||
| type: factor.type | |||
| } | |||
| } else if (factor.stat in VoreStat) { | |||
| return { | |||
| amount: factor.fraction * user.voreStats[factor.stat as VoreStat], | |||
| target: factor.target, | |||
| type: factor.type | |||
| } | |||
| } else { | |||
| // should be impossible; .stat is Stat|VoreStat | |||
| return { | |||
| amount: 0, | |||
| target: Vigor.Health, | |||
| type: DamageType.Heal | |||
| } | |||
| } | |||
| )) | |||
| }) | |||
| return new Damage(...instances) | |||
| } | |||
| @@ -244,7 +261,7 @@ export class StatDamageFormula implements DamageFormula { | |||
| ) | |||
| } | |||
| constructor (private factors: Array<{ stat: Stat; fraction: number; type: DamageType; target: Vigor|Stat }>) { | |||
| constructor (private factors: Array<{ stat: Stat|VoreStat; fraction: number; type: DamageType; target: Vigor|Stat }>) { | |||
| } | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| import { StatTest, StatVigorTest } from './tests' | |||
| import { POVPairArgs, POVPair, DynText, LiveText, TextLike } from '../language' | |||
| import { POVPairArgs, POVPair, DynText, LiveText, TextLike, Verb } from '../language' | |||
| import { Entity, POV, Creature } from '../entity' | |||
| import { Damage, DamageFormula, Stat, Vigor, Action } from '../combat' | |||
| import { LogLine, LogLines, LogEntry, CompositeLog } from '../interface' | |||
| @@ -11,28 +11,28 @@ export class AttackAction extends Action { | |||
| protected successLines: POVPairArgs<Entity, Entity, { damage: Damage }> = new POVPairArgs([ | |||
| [[POV.First, POV.Third], (user, target, args) => new LogLine( | |||
| `You smack ${target.name} for `, | |||
| `You ${this.verb} ${target.name} for `, | |||
| args.damage.renderShort() | |||
| )], | |||
| [[POV.Third, POV.First], (user, target, args) => new LogLine( | |||
| `${user.name.capital} smacks you for `, | |||
| `${user.name.capital} ${this.verb.singular} you for `, | |||
| args.damage.renderShort() | |||
| )], | |||
| [[POV.Third, POV.Third], (user, target, args) => new LogLine( | |||
| `${user.name.capital} smacks ${target.name} for `, | |||
| `${user.name.capital} ${this.verb.singular} ${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.First, POV.Third], (user, target) => new LogLine(`You try to ${this.verb.present} ${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) { | |||
| constructor (protected damage: DamageFormula, protected verb: Verb = new Verb('smack')) { | |||
| super( | |||
| 'Attack', | |||
| verb.root.capital, | |||
| 'Attack the enemy', | |||
| [new CapableCondition(), new TogetherCondition(), new EnemyCondition()] | |||
| ) | |||
| @@ -23,10 +23,5 @@ export class Human extends Creature { | |||
| this.title = "Snack" | |||
| this.desc = "Definitely going on an adventure" | |||
| this.actions.push(new AttackAction(new ConstantDamageFormula( | |||
| new Damage( | |||
| { amount: 20, target: Vigor.Health, type: DamageType.Slash } | |||
| ) | |||
| ))) | |||
| } | |||
| } | |||
| @@ -1,9 +1,9 @@ | |||
| import { Creature, POV } from '../entity' | |||
| import { ProperNoun, ImproperNoun, FemalePronouns, POVPairArgs, POVPair } from '../language' | |||
| import { ProperNoun, ImproperNoun, FemalePronouns, POVPairArgs, POVPair, Verb } from '../language' | |||
| import { VoreType, Stomach, Vore } from '../vore' | |||
| import { Side, Damage, DamageType, Vigor, UniformRandomDamageFormula } from '../combat' | |||
| import { Side, Damage, DamageType, Vigor, UniformRandomDamageFormula, ConstantDamageFormula, StatDamageFormula, Stat, VoreStat } from '../combat' | |||
| import { LogLine } from '../interface' | |||
| import { FeedAction, TransferAction } from '../combat/actions' | |||
| import { FeedAction, TransferAction, AttackAction } from '../combat/actions' | |||
| import * as Words from '../words' | |||
| export class Kenzie extends Creature { | |||
| @@ -30,5 +30,15 @@ export class Kenzie extends Creature { | |||
| )) | |||
| this.containers.push(stomach) | |||
| 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('crush', 'crushes', 'crushing', 'crushed') | |||
| ) | |||
| ) | |||
| } | |||
| } | |||
| @@ -116,7 +116,10 @@ const huge = new RandomWord([ | |||
| class BiteAction extends AttackAction { | |||
| constructor () { | |||
| super(new ConstantDamageFormula(new Damage({ amount: 50, type: DamageType.Slash, target: Vigor.Health }))) | |||
| super( | |||
| new ConstantDamageFormula(new Damage({ amount: 50, type: DamageType.Slash, target: Vigor.Health })), | |||
| new Verb('bite', 'bites', 'biting', 'bit') | |||
| ) | |||
| this.name = "Bite" | |||
| } | |||
| } | |||
| @@ -30,158 +30,165 @@ export interface Mortal extends Entity { | |||
| export class Creature extends Vore implements Combatant { | |||
| title = "Lv. 1 Creature" | |||
| desc = "Some creature" | |||
| vigors = { | |||
| [Vigor.Health]: 100, | |||
| [Vigor.Stamina]: 100, | |||
| [Vigor.Resolve]: 100 | |||
| vigors = { | |||
| [Vigor.Health]: 100, | |||
| [Vigor.Stamina]: 100, | |||
| [Vigor.Resolve]: 100 | |||
| } | |||
| maxVigors = { | |||
| [Vigor.Health]: 100, | |||
| [Vigor.Stamina]: 100, | |||
| [Vigor.Resolve]: 100 | |||
| } | |||
| baseStats: Stats | |||
| voreStats: VoreStats | |||
| side: Side | |||
| get disabled (): boolean { | |||
| return Object.values(this.vigors).some(val => val <= 0) | |||
| } | |||
| resistances: Map<DamageType, number> = new Map() | |||
| perspective: POV = POV.Third | |||
| containers: Array<VoreContainer> = [] | |||
| otherContainers: Array<Container> = [] | |||
| actions: Array<Action> = [] | |||
| groupActions: Array<GroupAction> = [] | |||
| otherActions: Array<Action> = [] | |||
| items: Array<Item> = [] | |||
| get bulk (): number { | |||
| return this.voreStats.Mass + this.containers.reduce((total, conatiner) => { return total + conatiner.contents.reduce((total, prey) => total + prey.voreStats.Bulk, 0) }, 0) | |||
| } | |||
| containedIn: VoreContainer|null = null; | |||
| constructor (public name: Noun, public kind: Noun, public pronouns: Pronoun, public stats: Stats, public preyPrefs: Set<VoreType>, public predPrefs: Set<VoreType>, mass: number) { | |||
| super() | |||
| const containers = this.containers | |||
| this.vigors.Health = this.maxVigors.Health = stats.Toughness * 10 + stats.Power * 5 | |||
| this.vigors.Stamina = this.maxVigors.Stamina = stats.Toughness * 3 + stats.Speed * 10 + stats.Willpower * 3 | |||
| this.vigors.Resolve = this.maxVigors.Resolve = stats.Willpower * 10 + stats.Charm * 5 | |||
| this.baseStats = Object.keys(Stat).reduce((base: any, key) => { base[key] = stats[key as Stat]; return base }, {}) | |||
| this.side = Side.Heroes | |||
| this.voreStats = { | |||
| get [VoreStat.Bulk] () { | |||
| console.log(containers) | |||
| return containers.reduce( | |||
| (total: number, container: VoreContainer) => { | |||
| return total + container.contents.reduce( | |||
| (total: number, prey: Vore) => { | |||
| return total + prey.voreStats.Bulk | |||
| }, | |||
| 0 | |||
| ) + container.digested.reduce( | |||
| (total: number, prey: Vore) => { | |||
| return total + prey.voreStats.Bulk | |||
| }, | |||
| 0 | |||
| ) | |||
| }, | |||
| this.Mass | |||
| ) | |||
| }, | |||
| [VoreStat.Mass]: mass, | |||
| get [VoreStat.PreyCount] () { | |||
| return containers.reduce( | |||
| (total: number, container: VoreContainer) => { | |||
| return total + container.contents.reduce( | |||
| (total: number, prey: Vore) => { | |||
| return total + 1 + prey.voreStats[VoreStat.PreyCount] | |||
| }, | |||
| 0 | |||
| ) | |||
| }, | |||
| 0 | |||
| ) | |||
| } | |||
| } | |||
| } | |||
| toString (): string { | |||
| return this.name.toString() | |||
| } | |||
| takeDamage (damage: Damage): LogEntry { | |||
| const startHealth = this.vigors.Health | |||
| damage.damages.forEach(instance => { | |||
| const factor = instance.type === DamageType.Heal ? -1 : 1 | |||
| const resistance: number|undefined = this.resistances.get(instance.type) | |||
| if (resistance !== undefined) { | |||
| if (instance.target in Vigor) { | |||
| this.vigors[instance.target as Vigor] -= instance.amount * factor * resistance | |||
| } else if (instance.target in Stat) { | |||
| this.stats[instance.target as Stat] -= instance.amount * factor * resistance | |||
| } | |||
| } else { | |||
| if (instance.target in Vigor) { | |||
| this.vigors[instance.target as Vigor] -= instance.amount * factor | |||
| } else if (instance.target in Stat) { | |||
| this.stats[instance.target as Stat] -= instance.amount * factor | |||
| } | |||
| } | |||
| }) | |||
| maxVigors = { | |||
| [Vigor.Health]: 100, | |||
| [Vigor.Stamina]: 100, | |||
| [Vigor.Resolve]: 100 | |||
| if (this.vigors.Health <= 0 && startHealth > 0) { | |||
| return this.destroy() | |||
| } else { | |||
| return new LogLine() | |||
| } | |||
| } | |||
| baseStats: Stats | |||
| voreStats: VoreStats | |||
| side: Side | |||
| get disabled (): boolean { | |||
| return Object.values(this.vigors).some(val => val <= 0) | |||
| get status (): string { | |||
| if (this.vigors[Vigor.Health] <= 0) { | |||
| return "Dead" | |||
| } | |||
| resistances: Map<DamageType, number> = new Map() | |||
| perspective: POV = POV.Third | |||
| containers: Array<VoreContainer> = [] | |||
| otherContainers: Array<Container> = [] | |||
| actions: Array<Action> = [] | |||
| groupActions: Array<GroupAction> = [] | |||
| otherActions: Array<Action> = [] | |||
| items: Array<Item> = [] | |||
| get bulk (): number { | |||
| return this.voreStats.Mass + this.containers.reduce((total, conatiner) => { return total + conatiner.contents.reduce((total, prey) => total + prey.voreStats.Bulk, 0) }, 0) | |||
| if (this.vigors[Vigor.Stamina] <= 0) { | |||
| return "Unconscious" | |||
| } | |||
| containedIn: VoreContainer|null = null; | |||
| constructor (public name: Noun, public kind: Noun, public pronouns: Pronoun, public stats: Stats, public preyPrefs: Set<VoreType>, public predPrefs: Set<VoreType>, mass: number) { | |||
| super() | |||
| const containers = this.containers | |||
| this.baseStats = Object.keys(Stat).reduce((base: any, key) => { base[key] = stats[key as Stat]; return base }, {}) | |||
| this.side = Side.Heroes | |||
| this.voreStats = { | |||
| get [VoreStat.Bulk] () { | |||
| console.log(containers) | |||
| return containers.reduce( | |||
| (total: number, container: VoreContainer) => { | |||
| return total + container.contents.reduce( | |||
| (total: number, prey: Vore) => { | |||
| return total + prey.voreStats.Bulk | |||
| }, | |||
| 0 | |||
| ) + container.digested.reduce( | |||
| (total: number, prey: Vore) => { | |||
| return total + prey.voreStats.Bulk | |||
| }, | |||
| 0 | |||
| ) | |||
| }, | |||
| this.Mass | |||
| ) | |||
| }, | |||
| [VoreStat.Mass]: mass, | |||
| get [VoreStat.PreyCount] () { | |||
| return containers.reduce( | |||
| (total: number, container: VoreContainer) => { | |||
| return total + container.contents.reduce( | |||
| (total: number, prey: Vore) => { | |||
| return total + 1 + prey.voreStats[VoreStat.PreyCount] | |||
| }, | |||
| 0 | |||
| ) | |||
| }, | |||
| 0 | |||
| ) | |||
| } | |||
| } | |||
| if (this.vigors[Vigor.Resolve] <= 0) { | |||
| return "Broken" | |||
| } | |||
| toString (): string { | |||
| return this.name.toString() | |||
| if (this.containedIn !== null) { | |||
| return `${this.containedIn.consumeVerb.past.capital} by ${this.containedIn.owner.name}` | |||
| } | |||
| takeDamage (damage: Damage): LogEntry { | |||
| const startHealth = this.vigors.Health | |||
| damage.damages.forEach(instance => { | |||
| const resistance: number|undefined = this.resistances.get(instance.type) | |||
| if (resistance !== undefined) { | |||
| if (instance.target in Vigor) { | |||
| this.vigors[instance.target as Vigor] -= instance.amount * resistance | |||
| } else if (instance.target in Stat) { | |||
| this.stats[instance.target as Stat] -= instance.amount * resistance | |||
| } | |||
| } else { | |||
| if (instance.target in Vigor) { | |||
| this.vigors[instance.target as Vigor] -= instance.amount | |||
| } else if (instance.target in Stat) { | |||
| this.stats[instance.target as Stat] -= instance.amount | |||
| } | |||
| } | |||
| }) | |||
| return "Normal" | |||
| } | |||
| if (this.vigors.Health <= 0 && startHealth > 0) { | |||
| return this.destroy() | |||
| } else { | |||
| return new LogLine() | |||
| } | |||
| } | |||
| get status (): string { | |||
| if (this.vigors[Vigor.Health] <= 0) { | |||
| return "Dead" | |||
| } | |||
| if (this.vigors[Vigor.Stamina] <= 0) { | |||
| return "Unconscious" | |||
| } | |||
| if (this.vigors[Vigor.Resolve] <= 0) { | |||
| return "Broken" | |||
| } | |||
| if (this.containedIn !== null) { | |||
| return `${this.containedIn.consumeVerb.past.capital} by ${this.containedIn.owner.name}` | |||
| } | |||
| return "Normal" | |||
| } | |||
| validActions (target: Creature): Array<Action> { | |||
| let choices = this.actions.concat( | |||
| this.containers.flatMap(container => container.actions)).concat( | |||
| target.otherActions.concat( | |||
| this.otherContainers.flatMap(container => container.actions).concat( | |||
| this.items.flatMap(item => item.actions) | |||
| ) | |||
| validActions (target: Creature): Array<Action> { | |||
| let choices = this.actions.concat( | |||
| this.containers.flatMap(container => container.actions) | |||
| ).concat( | |||
| target.otherActions.concat( | |||
| this.otherContainers.flatMap(container => container.actions).concat( | |||
| this.items.flatMap(item => item.actions) | |||
| ) | |||
| ) | |||
| ) | |||
| if (this.containedIn !== null) { | |||
| choices = choices.concat(this.containedIn.actions) | |||
| } | |||
| return choices.filter(action => { | |||
| return action.allowed(this, target) | |||
| }) | |||
| } | |||
| validGroupActions (targets: Array<Creature>): Array<GroupAction> { | |||
| const choices = this.groupActions | |||
| return choices.filter(action => { | |||
| return targets.some(target => action.allowed(this, target)) | |||
| }) | |||
| } | |||
| destroy (): LogEntry { | |||
| return super.destroy() | |||
| if (this.containedIn !== null) { | |||
| choices = choices.concat(this.containedIn.actions) | |||
| } | |||
| return choices.filter(action => { | |||
| return action.allowed(this, target) | |||
| }) | |||
| } | |||
| validGroupActions (targets: Array<Creature>): Array<GroupAction> { | |||
| const choices = this.groupActions | |||
| return choices.filter(action => { | |||
| return targets.some(target => action.allowed(this, target)) | |||
| }) | |||
| } | |||
| destroy (): LogEntry { | |||
| return super.destroy() | |||
| } | |||
| } | |||
| @@ -154,7 +154,7 @@ export class PropElem implements LogEntry { | |||
| cls = StatIcons[this.prop as Stat] | |||
| } else if (this.prop in Vigor) { | |||
| cls = VigorIcons[this.prop as Vigor] | |||
| } else if (this.prop in Vigor) { | |||
| } else if (this.prop in VoreStat) { | |||
| cls = VoreStatIcons[this.prop as VoreStat] | |||
| } else { | |||
| // this shouldn't be possible, given the typing... | |||
| @@ -184,8 +184,8 @@ export class PropElem implements LogEntry { | |||
| } | |||
| if (this.value !== null) { | |||
| const numText = Math.round(this.value).toFixed(0) === this.value.toFixed(0) ? this.value.toFixed(0) : this.value.toFixed(1) | |||
| span.textContent = numText + ' ' | |||
| const numText = Math.round(this.value).toFixed(0) === this.value.toFixed(0) ? Math.abs(this.value).toFixed(0) : Math.abs(this.value).toFixed(1) | |||
| span.textContent = (this.value < 0 ? '+' : '') + numText + ' ' | |||
| } | |||
| const icon = new FAElem(cls).render()[0] | |||
| @@ -1,4 +1,4 @@ | |||
| import { TextLike, LiveText, DynText, Word, ImproperNoun } from './language' | |||
| import { TextLike, LiveText, DynText, Word, ImproperNoun, Verb } from './language' | |||
| import { Actionable, Action, DamageFormula, ConstantDamageFormula, Damage, DamageType, Vigor, StatDamageFormula, Stat } from './combat' | |||
| import { AttackAction } from './combat/actions' | |||
| @@ -10,8 +10,8 @@ export interface Item extends Actionable { | |||
| export class Weapon implements Actionable { | |||
| actions: Array<Action> = [] | |||
| constructor (public name: Word, public desc: TextLike, damageFormula: DamageFormula) { | |||
| const attack = new AttackAction(damageFormula) | |||
| constructor (public name: Word, public desc: TextLike, damageFormula: DamageFormula, verb: Verb) { | |||
| const attack = new AttackAction(damageFormula, verb) | |||
| attack.desc = new DynText(`Attack with your `, this.name.all) | |||
| this.actions.push(attack) | |||
| } | |||
| @@ -23,7 +23,8 @@ export const Sword = new Weapon( | |||
| new StatDamageFormula([ | |||
| { fraction: 0.35, stat: Stat.Power, target: Vigor.Health, type: DamageType.Slash }, | |||
| { fraction: 0.25, stat: Stat.Power, target: Vigor.Health, type: DamageType.Pierce } | |||
| ]) | |||
| ]), | |||
| new Verb('slash', 'slashes') | |||
| ) | |||
| export const Dagger = new Weapon( | |||
| @@ -32,7 +33,8 @@ export const Dagger = new Weapon( | |||
| new StatDamageFormula([ | |||
| { fraction: 0.50, stat: Stat.Speed, target: Vigor.Health, type: DamageType.Pierce }, | |||
| { fraction: 0.05, stat: Stat.Speed, target: Vigor.Health, type: DamageType.Slash } | |||
| ]) | |||
| ]), | |||
| new Verb('stab', 'stabs', 'stabbing', 'stabbed') | |||
| ) | |||
| export const Wand = new Weapon( | |||
| @@ -41,7 +43,8 @@ export const Wand = new Weapon( | |||
| new StatDamageFormula([ | |||
| { fraction: 0.25, stat: Stat.Charm, target: Vigor.Health, type: DamageType.Crush }, | |||
| { fraction: 0.25, stat: Stat.Willpower, target: Vigor.Health, type: DamageType.Crush } | |||
| ]) | |||
| ]), | |||
| new Verb('zap', 'zaps', 'zapping', 'zapped') | |||
| ) | |||
| export const Mace = new Weapon( | |||
| @@ -50,5 +53,6 @@ export const Mace = new Weapon( | |||
| new StatDamageFormula([ | |||
| { fraction: 0.4, stat: Stat.Power, target: Vigor.Health, type: DamageType.Crush }, | |||
| { fraction: 0.2, stat: Stat.Power, target: Vigor.Health, type: DamageType.Pierce } | |||
| ]) | |||
| ]), | |||
| new Verb('bash', 'bashes', 'bashing', 'bashed') | |||
| ) | |||
| @@ -138,8 +138,8 @@ export abstract class NormalContainer implements Container { | |||
| export interface VoreContainer extends Container { | |||
| digested: Array<Vore>; | |||
| tick: (dt: number) => LogEntry; | |||
| digest: (prey: Vore) => LogEntry; | |||
| absorb: (prey: Vore) => LogEntry; | |||
| digest: (preys: Vore[]) => LogEntry; | |||
| absorb: (preys: Vore[]) => LogEntry; | |||
| dispose: (preys: Vore[]) => LogEntry; | |||
| } | |||
| @@ -172,7 +172,7 @@ export abstract class NormalVoreContainer extends NormalContainer implements Vor | |||
| }) | |||
| const tickedEntries = new LogLines(...this.contents.map(prey => this.tickLines.run(this.owner, prey, { damage: scaled }))) | |||
| const digestedEntries = new LogLines(...justDigested.map(prey => this.digest(prey))) | |||
| const digestedEntries = this.digest(justDigested) | |||
| this.contents = this.contents.filter(prey => { | |||
| return prey.vigors[Vigor.Health] > 0 | |||
| @@ -181,16 +181,16 @@ export abstract class NormalVoreContainer extends NormalContainer implements Vor | |||
| return new LogLines(tickedEntries, new LogLines(...damageResults), digestedEntries) | |||
| } | |||
| digest (prey: Vore): LogEntry { | |||
| return this.digestLines.run(this.owner, prey) | |||
| digest (preys: Vore[]): LogEntry { | |||
| return new LogLines(...preys.map(prey => this.digestLines.run(this.owner, prey))) | |||
| } | |||
| absorb (prey: Vore): LogEntry { | |||
| return this.absorbLines.run(this.owner, prey) | |||
| absorb (preys: Vore[]): LogEntry { | |||
| return new LogLines(...preys.map(prey => this.absorbLines.run(this.owner, prey))) | |||
| } | |||
| dispose (preys: Vore[]): LogEntry { | |||
| return new CompositeLog(...preys.map(prey => this.disposeLines.run(this.owner, prey))) | |||
| return new LogLines(...preys.map(prey => this.disposeLines.run(this.owner, prey))) | |||
| } | |||
| constructor (name: Noun, owner: Vore, voreTypes: Set<VoreType>, capacity: number, private damage: Damage) { | |||
| @@ -265,6 +265,25 @@ export class Stomach extends NormalVoreContainer { | |||
| [[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}`)] | |||
| ]) | |||
| digest (preys: Vore[]): LogEntry { | |||
| if (preys.length === 0) { | |||
| return super.digest(preys) | |||
| } | |||
| const heal = new Damage( | |||
| { | |||
| amount: preys.reduce((total: number, next: Vore) => 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} heals for `, heal.renderShort()) | |||
| ) | |||
| } | |||
| } | |||
| export class InnerStomach extends InnerContainer { | |||