| @@ -7,6 +7,7 @@ | |||
| <link rel="icon" href="https://crux.sexy/images/feast.ico"> | |||
| <link rel="stylesheet" href="./reset.css"></link> | |||
| <title><%= htmlWebpackPlugin.options.title %></title> | |||
| <script src="https://kit.fontawesome.com/10a16c6083.js" crossorigin="anonymous"></script> | |||
| </head> | |||
| <body> | |||
| <noscript> | |||
| @@ -32,7 +32,7 @@ export default class App extends Vue { | |||
| <style> | |||
| body, html { | |||
| background: #111; | |||
| background: #181818; | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| @@ -45,6 +45,8 @@ body, html { | |||
| color: #ddd; | |||
| background: #111; | |||
| width: 100%; | |||
| max-width: 1000pt; | |||
| margin: auto; | |||
| height: 100%; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,39 @@ | |||
| <template> | |||
| <button class="action-button" @click="execute"> | |||
| {{ action.name }} | |||
| </button> | |||
| </template> | |||
| <script lang="ts"> | |||
| import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' | |||
| import { Action } from '@/game/combat' | |||
| import { Creature } from '@/game/entity' | |||
| @Component({}) | |||
| export default class ActionButton extends Vue { | |||
| @Prop() | |||
| action!: Action | |||
| @Prop() | |||
| user!: Creature | |||
| @Prop() | |||
| target!: Creature | |||
| @Emit("execute") | |||
| execute () { | |||
| this.$emit('executed', this.action.execute(this.user, this.target)) | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| .action-button { | |||
| width: 100px; | |||
| height: 100px; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,237 @@ | |||
| <template> | |||
| <div class="combat-layout"> | |||
| <Statblock class="player-stats" :subject="player" /> | |||
| <Statblock class="enemy-stats" :subject="enemy" /> | |||
| <div id="log"> | |||
| </div> | |||
| <div class="player-actions"> | |||
| <h2>Your moves</h2> | |||
| <div class="vert-display"> | |||
| <ActionButton @executed="executed" v-for="action in player.validActions(enemy)" :key="'player' + action.name" :action="action" :user="player" :target="enemy" /> | |||
| <ActionButton @executed="executed" v-for="action in player.validActions(player)" :key="'player' + action.name" :action="action" :user="player" :target="enemy" /> | |||
| </div> | |||
| <div>{{actionDescription}}</div> | |||
| </div> | |||
| <div class="enemy-actions"> | |||
| <h2>Enemy moves</h2> | |||
| <div class="vert-display"> | |||
| <ActionButton @executed="executedEnemy" v-for="action in enemy.validActions(player)" :key="'player' + action.name" :action="action" :user="enemy" :target="player" /> | |||
| <ActionButton @executed="executedEnemy" v-for="action in enemy.validActions(enemy)" :key="'player' + action.name" :action="action" :user="enemy" :target="player" /> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script lang="ts"> | |||
| import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' | |||
| import { Creature, POV } from '@/game/entity' | |||
| import { LogEntry } from '@/game/interface' | |||
| import Statblock from './Statblock.vue' | |||
| import ActionButton from './ActionButton.vue' | |||
| @Component( | |||
| { | |||
| components: { Statblock, ActionButton } | |||
| } | |||
| ) | |||
| export default class Combat extends Vue { | |||
| @Prop({ type: Creature, required: true }) | |||
| player!: Creature | |||
| @Prop({ type: Creature, required: true }) | |||
| enemy!: Creature | |||
| actionDescription = '' | |||
| constructor () { | |||
| super() | |||
| } | |||
| @Emit("executed") | |||
| executed (entry: LogEntry) { | |||
| const log = document.querySelector("#log") | |||
| if (log !== null) { | |||
| const holder = document.createElement("div") | |||
| entry.render().forEach(element => { | |||
| holder.appendChild(element) | |||
| }) | |||
| holder.classList.add("player-move") | |||
| log.appendChild(holder) | |||
| log.scrollTo({ top: 10000000000, left: 0 }) | |||
| } | |||
| } | |||
| @Emit("executedEnemy") | |||
| executedEnemy (entry: LogEntry) { | |||
| const log = document.querySelector("#log") | |||
| if (log !== null) { | |||
| const holder = document.createElement("div") | |||
| entry.render().forEach(element => { | |||
| holder.appendChild(element) | |||
| }) | |||
| holder.classList.add("enemy-move") | |||
| log.appendChild(holder) | |||
| log.scrollTo({ top: 10000000000, left: 0 }) | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <!-- Add "scoped" attribute to limit CSS to this component only --> | |||
| <style scoped> | |||
| .combat-layout { | |||
| display: grid; | |||
| grid-template-rows: 20% [main-row-start] 30% 30% [main-row-end] 20%; | |||
| grid-template-columns: 20% [main-col-start] 60% [main-col-end] 20%; | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .player-stats { | |||
| grid-area: 1 / 1 / 2 / 2 | |||
| } | |||
| .enemy-stats { | |||
| grid-area: 1 / 3 / 2 / 4; | |||
| } | |||
| #log { | |||
| grid-area: main-row-start / main-col-start / main-row-end / main-col-end; | |||
| overflow-y: auto; | |||
| font-size: 16pt; | |||
| width: 100%; | |||
| max-height: 100%; | |||
| align-self: end; | |||
| } | |||
| .player-actions { | |||
| grid-area: 3 / 1 / 4 / 2; | |||
| } | |||
| .enemy-actions { | |||
| grid-area: 3 / 3 / 4 / 4; | |||
| } | |||
| h3 { | |||
| margin: 40px 0 0; | |||
| } | |||
| ul { | |||
| list-style-type: none; | |||
| padding: 0; | |||
| } | |||
| li { | |||
| display: inline-block; | |||
| margin: 0 10px; | |||
| } | |||
| a { | |||
| color: #42b983; | |||
| } | |||
| .horiz-display { | |||
| display: flex; | |||
| justify-content: center; | |||
| } | |||
| .vert-display { | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| } | |||
| </style> | |||
| <style> | |||
| .log-damage { | |||
| font-weight: bold; | |||
| } | |||
| #log > div { | |||
| color: #888; | |||
| padding-top: 8pt; | |||
| padding-bottom: 8pt; | |||
| } | |||
| div.player-move, | |||
| div.enemy-move { | |||
| color: #888; | |||
| } | |||
| div.player-move { | |||
| text-align: start; | |||
| margin-left: 48pt; | |||
| } | |||
| div.enemy-move { | |||
| text-align: end; | |||
| margin-right: 48pt; | |||
| } | |||
| #log > div.enemy-move:nth-last-child(7) { | |||
| color: #988; | |||
| } | |||
| #log > div.enemy-move:nth-last-child(6) { | |||
| padding-top: 8pt; | |||
| color: #a88; | |||
| } | |||
| #log > div.enemy-move:nth-last-child(5) { | |||
| padding-top: 16pt; | |||
| color: #b88; | |||
| } | |||
| #log > div.enemy-move:nth-last-child(4) { | |||
| padding-top: 24pt; | |||
| color: #c88; | |||
| } | |||
| #log > div.enemy-move:nth-last-child(3) { | |||
| padding-top: 32pt; | |||
| color: #d88; | |||
| } | |||
| #log > div.enemy-move:nth-last-child(2) { | |||
| padding-top: 40pt; | |||
| color: #e88; | |||
| } | |||
| #log > div.enemy-move:nth-last-child(1) { | |||
| padding-top: 48pt; | |||
| color: #f88; | |||
| } | |||
| #log > div.player-move:nth-last-child(7) { | |||
| color: #898; | |||
| } | |||
| #log > div.player-move:nth-last-child(6) { | |||
| padding-top: 8pt; | |||
| color: #8a8; | |||
| } | |||
| #log > div.player-move:nth-last-child(5) { | |||
| padding-top: 16pt; | |||
| color: #8b8; | |||
| } | |||
| #log > div.player-move:nth-last-child(4) { | |||
| padding-top: 24pt; | |||
| color: #8c8; | |||
| } | |||
| #log > div.player-move:nth-last-child(3) { | |||
| padding-top: 32pt; | |||
| color: #8d8; | |||
| } | |||
| #log > div.player-move:nth-last-child(2) { | |||
| padding-top: 40pt; | |||
| color: #8e8; | |||
| } | |||
| #log > div.player-move:nth-last-child(1) { | |||
| padding-top: 48pt; | |||
| color: #8f8; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,42 @@ | |||
| <template> | |||
| <div v-if="container.fullness > 0" class="statblock"> | |||
| <h3>{{container.name}}</h3> | |||
| <div>Fullness: {{container.fullness}} / {{container.capacity}}</div> | |||
| <div v-for="(prey, index) in container.contents" :key="'prey-' + index">{{prey.name}}</div> | |||
| </div> | |||
| </template> | |||
| <script lang="ts"> | |||
| import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' | |||
| import { Creature, POV } from '@/game/entity' | |||
| import { Stats, Stat } from '@/game/combat' | |||
| import { Container } from '@/game/vore' | |||
| @Component | |||
| export default class ContainerView extends Vue { | |||
| @Prop({ required: true }) | |||
| container!: Container | |||
| constructor () { | |||
| super() | |||
| } | |||
| } | |||
| </script> | |||
| <!-- Add "scoped" attribute to limit CSS to this component only --> | |||
| <style scoped> | |||
| h3 { | |||
| margin: 40px 0 0; | |||
| } | |||
| ul { | |||
| list-style-type: none; | |||
| padding: 0; | |||
| } | |||
| li { | |||
| display: inline-block; | |||
| margin: 0 10px; | |||
| } | |||
| a { | |||
| color: #42b983; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,29 @@ | |||
| <template> | |||
| <div id="header"> | |||
| <div> | |||
| This is the (extremely early alpha of the) new Feast. If you're looking for the old version, <a href="https://classic.feast.crux.sexy">go here!</a> | |||
| </div> | |||
| <div>Version: {{version}}</div> | |||
| </div> | |||
| </template> | |||
| <script lang="ts"> | |||
| import { Component, Vue, Prop } from 'vue-property-decorator' | |||
| @Component({}) | |||
| export default class Header extends Vue { | |||
| @Prop() version!: string | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| #header { | |||
| width: 100%; | |||
| background: #222; | |||
| top: 0%; | |||
| padding-top: 32pt; | |||
| padding-bottom: 32pt; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,54 @@ | |||
| <template> | |||
| <div class="statblock"> | |||
| <h2 v-if="subject.perspective === firstperson">You</h2> | |||
| <h2 v-if="subject.perspective !== firstperson">{{subject.name.all.capital}}</h2> | |||
| <div>Health: {{subject.health.toFixed(0)}} / {{subject.maxHealth.toFixed(0)}}</div> | |||
| <div v-for="stat in Object.keys(subject.stats)" v-bind:key="stat">{{stat}}: {{subject.stats[stat]}}</div> | |||
| <div>Status: {{subject.status}}</div> | |||
| <ContainerView v-for="container in subject.containers" :key="container.name" :container="container" /> | |||
| </div> | |||
| </template> | |||
| <script lang="ts"> | |||
| import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' | |||
| import { Creature, POV } from '@/game/entity' | |||
| import { Stats, Stat } from '@/game/combat' | |||
| import ContainerView from './ContainerView.vue' | |||
| @Component({ | |||
| components: { | |||
| ContainerView | |||
| } | |||
| }) | |||
| export default class Statblock extends Vue { | |||
| @Prop({ type: Creature, required: true }) | |||
| subject!: Creature | |||
| firstperson: POV = POV.First | |||
| constructor () { | |||
| super() | |||
| } | |||
| } | |||
| </script> | |||
| <!-- Add "scoped" attribute to limit CSS to this component only --> | |||
| <style scoped> | |||
| h2 { | |||
| margin-bottom: 16pt; | |||
| font-size: 200%; | |||
| } | |||
| ul { | |||
| list-style-type: none; | |||
| padding: 0; | |||
| } | |||
| li { | |||
| display: inline-block; | |||
| margin: 0 10px; | |||
| } | |||
| a { | |||
| color: #42b983; | |||
| } | |||
| .statblock { | |||
| margin: 16px; | |||
| } | |||
| </style> | |||
| @@ -2,8 +2,11 @@ | |||
| <div class="statblock"> | |||
| <h2 v-if="subject.perspective === firstperson">You</h2> | |||
| <h2 v-if="subject.perspective !== firstperson">{{subject.name.all.capital}}</h2> | |||
| <div>Health: {{subject.health.toFixed(0)}} / {{subject.maxHealth.toFixed(0)}}</div> | |||
| <div v-for="stat in Object.keys(subject.stats)" v-bind:key="stat">{{stat}}: {{subject.stats[stat]}}</div> | |||
| <div class="stat-line"><i class="fas fa-heart" /> {{ subject.vigors[vigor.Health].toFixed(0) }}</div> | |||
| <div class="stat-line"><i class="fas fa-bolt" /> {{ subject.vigors[vigor.Stamina].toFixed(0) }}</div> | |||
| <div class="stat-line"><i class="fas fa-brain" /> {{ subject.vigors[vigor.Willpower].toFixed(0) }}</div> | |||
| <br> | |||
| <div class="stat-line" v-for="stat in Object.keys(subject.stats)" v-bind:key="stat"><i :class="statIcons[stat]" />: {{subject.stats[stat]}}</div> | |||
| <div>Status: {{subject.status}}</div> | |||
| <ContainerView v-for="container in subject.containers" :key="container.name" :container="container" /> | |||
| </div> | |||
| @@ -12,7 +15,7 @@ | |||
| <script lang="ts"> | |||
| import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' | |||
| import { Creature, POV } from '@/game/entity' | |||
| import { Stats, Stat } from '@/game/combat' | |||
| import { Stats, Stat, StatIcons, Vigor } from '@/game/combat' | |||
| import ContainerView from './ContainerView.vue' | |||
| @Component({ | |||
| @@ -24,6 +27,9 @@ export default class Statblock extends Vue { | |||
| @Prop({ type: Creature, required: true }) | |||
| subject!: Creature | |||
| private statIcons = StatIcons | |||
| private vigor = Vigor | |||
| firstperson: POV = POV.First | |||
| constructor () { | |||
| super() | |||
| @@ -51,4 +57,9 @@ a { | |||
| .statblock { | |||
| margin: 16px; | |||
| } | |||
| .stat-line { | |||
| font-size: 24pt; | |||
| padding-top: 4pt; | |||
| padding-bottom: 4pt; | |||
| } | |||
| </style> | |||
| @@ -75,8 +75,9 @@ export enum DamageType { | |||
| Acid = "Acid"} | |||
| export interface DamageInstance { | |||
| type: DamageType; | |||
| amount: number; | |||
| type: DamageType; | |||
| amount: number; | |||
| target: Vigor; | |||
| } | |||
| export class Damage { | |||
| @@ -92,7 +93,8 @@ export class Damage { | |||
| this.damages.forEach(damage => { | |||
| results.push({ | |||
| type: damage.type, | |||
| amount: damage.amount * factor | |||
| amount: damage.amount * factor, | |||
| target: damage.target | |||
| }) | |||
| }) | |||
| @@ -104,6 +106,12 @@ export class Damage { | |||
| } | |||
| } | |||
| export enum Vigor { | |||
| Health, | |||
| Stamina, | |||
| Willpower | |||
| } | |||
| export enum Stat { | |||
| STR = 'Strength', | |||
| DEX = 'Dexterity', | |||
| @@ -112,6 +120,12 @@ export enum Stat { | |||
| export type Stats = {[key in Stat]: number} | |||
| export const StatIcons: {[key in Stat]: string} = { | |||
| [Stat.STR]: 'fas fa-fist-raised', | |||
| [Stat.DEX]: 'fas fa-feather', | |||
| [Stat.CON]: 'fas fa-heartbeat' | |||
| } | |||
| export interface Combatant { | |||
| actions: Array<Action>; | |||
| } | |||
| @@ -1,18 +1,18 @@ | |||
| import { Creature, POV } from '../entity' | |||
| import { ProperNoun, TheyPronouns } from '../language' | |||
| import { Stat, Damage, AttackAction, DamageType } from '../combat' | |||
| import { Stat, Damage, AttackAction, DamageType, Vigor } from '../combat' | |||
| import { Stomach, Bowels, VoreType } from '../vore' | |||
| export class Player extends Creature { | |||
| constructor () { | |||
| super(new ProperNoun('The Dude'), TheyPronouns, { [Stat.STR]: 20, [Stat.DEX]: 20, [Stat.CON]: 20 }, new Set([VoreType.Oral]), new Set([VoreType.Oral, VoreType.Anal]), 50) | |||
| this.actions.push(new AttackAction(new Damage({ type: DamageType.Pierce, amount: 20 }))) | |||
| this.actions.push(new AttackAction(new Damage({ type: DamageType.Pierce, amount: 20, target: Vigor.Health }))) | |||
| const stomach = new Stomach(this, 100, new Damage({ amount: 100000000000, type: DamageType.Acid }, { amount: 10, type: DamageType.Crush })) | |||
| const stomach = new Stomach(this, 100, new Damage({ amount: 100000000000, type: DamageType.Acid, target: Vigor.Health }, { amount: 10, type: DamageType.Crush, target: Vigor.Health })) | |||
| this.containers.push(stomach) | |||
| const bowels = new Bowels(this, 100, new Damage({ amount: 20, type: DamageType.Crush })) | |||
| const bowels = new Bowels(this, 100, new Damage({ amount: 20, type: DamageType.Crush, target: Vigor.Health })) | |||
| this.containers.push(bowels) | |||
| this.perspective = POV.First | |||
| @@ -1,11 +1,11 @@ | |||
| import { Creature, POV } from '../entity' | |||
| import { Stat, Damage, DamageType, AttackAction, StruggleAction, TransferAction } from '../combat' | |||
| import { Stat, Damage, DamageType, AttackAction, TransferAction, Vigor } from '../combat' | |||
| import { MalePronouns, ImproperNoun } from '../language' | |||
| import { VoreType, Stomach, Bowels } from '../vore' | |||
| class BiteAction extends AttackAction { | |||
| constructor () { | |||
| super(new Damage({ amount: 10, type: DamageType.Slash })) | |||
| super(new Damage({ amount: 10, type: DamageType.Slash, target: Vigor.Health })) | |||
| } | |||
| } | |||
| @@ -14,10 +14,10 @@ export class Wolf extends Creature { | |||
| super(new ImproperNoun('wolf', 'wolves'), MalePronouns, { [Stat.STR]: 10, [Stat.DEX]: 10, [Stat.CON]: 10 }, new Set([VoreType.Oral, VoreType.Anal]), new Set([VoreType.Oral]), 25) | |||
| this.actions.push(new BiteAction()) | |||
| const stomach = new Stomach(this, 50, new Damage({ amount: 50, type: DamageType.Acid }, { amount: 500, type: DamageType.Crush })) | |||
| const stomach = new Stomach(this, 50, new Damage({ amount: 50, type: DamageType.Acid, target: Vigor.Health }, { amount: 500, type: DamageType.Crush, target: Vigor.Health })) | |||
| this.containers.push(stomach) | |||
| const bowels = new Bowels(this, 50, new Damage({ amount: 50, type: DamageType.Acid }, { amount: 500, type: DamageType.Crush })) | |||
| const bowels = new Bowels(this, 50, new Damage({ amount: 50, type: DamageType.Acid, target: Vigor.Health }, { amount: 500, type: DamageType.Crush, target: Vigor.Health })) | |||
| this.containers.push(bowels) | |||
| @@ -1,4 +1,4 @@ | |||
| import { DamageType, Damage, Combatant, Stats, Action } from './combat' | |||
| import { DamageType, Damage, Combatant, Stats, Action, Vigor } from './combat' | |||
| import { Noun, Pronoun } from './language' | |||
| import { Pred, Prey, Container, VoreType } from './vore' | |||
| @@ -12,17 +12,28 @@ export interface Entity { | |||
| } | |||
| export interface Mortal extends Entity { | |||
| health: number; | |||
| maxHealth: number; | |||
| resistances: Map<DamageType, number>; | |||
| takeDamage: (damage: Damage) => void; | |||
| stats: Stats; | |||
| status: string; | |||
| vigors: {[key in Vigor]: number}; | |||
| maxVigors: {[key in Vigor]: number}; | |||
| resistances: Map<DamageType, number>; | |||
| takeDamage: (damage: Damage) => void; | |||
| stats: Stats; | |||
| status: string; | |||
| } | |||
| export class Creature implements Mortal, Pred, Prey, Combatant { | |||
| health = 100 | |||
| maxHealth = 100 | |||
| vigors = { | |||
| [Vigor.Health]: 100, | |||
| [Vigor.Stamina]: 100, | |||
| [Vigor.Willpower]: 100 | |||
| } | |||
| maxVigors = { | |||
| [Vigor.Health]: 100, | |||
| [Vigor.Stamina]: 100, | |||
| [Vigor.Willpower]: 100 | |||
| } | |||
| resistances: Map<DamageType, number> = new Map() | |||
| perspective: POV = POV.Third | |||
| containers: Array<Container> = [] | |||
| @@ -40,24 +51,30 @@ export class Creature implements Mortal, Pred, Prey, Combatant { | |||
| } | |||
| toString (): string { | |||
| return this.name + ': ' + this.health + ' HP' | |||
| return this.name.toString() | |||
| } | |||
| takeDamage (damage: Damage): void { | |||
| damage.damages.forEach(instance => { | |||
| const resistance: number|undefined = this.resistances.get(instance.type) | |||
| if (resistance !== undefined) { | |||
| this.health -= instance.amount * resistance | |||
| this.vigors[instance.target] -= instance.amount * resistance | |||
| } else { | |||
| this.health -= instance.amount | |||
| this.vigors[instance.target] -= instance.amount | |||
| } | |||
| }) | |||
| } | |||
| get status (): string { | |||
| if (this.health < 0) { | |||
| if (this.vigors[Vigor.Health] < 0) { | |||
| return "DEAD" | |||
| } | |||
| if (this.vigors[Vigor.Stamina] < 0) { | |||
| return "Unconscious" | |||
| } | |||
| if (this.vigors[Vigor.Willpower] < 0) { | |||
| return "Too horny" | |||
| } | |||
| if (this.containedIn !== null) { | |||
| return "Devoured" | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| import { Entity, Mortal, POV } from './entity' | |||
| import { Damage, Actionable, Action, DevourAction, DigestAction, ReleaseAction, StruggleAction } from './combat' | |||
| import { Damage, Actionable, Action, DevourAction, DigestAction, ReleaseAction, StruggleAction, Vigor } from './combat' | |||
| import { LogLines, LogEntry, CompositeLog } from './interface' | |||
| import { POVSolo, POVPair, POVPairArgs } from './language' | |||
| @@ -86,9 +86,9 @@ abstract class NormalContainer implements Container { | |||
| const absorbed: Array<Prey> = [] | |||
| this.contents.forEach(prey => { | |||
| const start = prey.health | |||
| const start = prey.vigors[Vigor.Health] | |||
| prey.takeDamage(this.damage.scale(dt / 3600)) | |||
| const end = prey.health | |||
| const end = prey.vigors[Vigor.Health] | |||
| if (start > 0 && end <= 0) { | |||
| digested.push(prey) | |||
| @@ -103,7 +103,7 @@ abstract class NormalContainer implements Container { | |||
| const absorbedEntries = new CompositeLog(...absorbed.map(prey => this.absorb(prey))) | |||
| this.contents = this.contents.filter(prey => { | |||
| return prey.health > -100 | |||
| return prey.vigors[Vigor.Health] > -100 | |||
| }) | |||
| return new CompositeLog(this.tickLines.run(this.owner), digestedEntries, absorbedEntries) | |||