浏览代码

Start enforcing member ordering

vintage
Fen Dweller 5 年前
父节点
当前提交
aed2d3f501
共有 6 个文件被更改,包括 229 次插入227 次删除
  1. +2
    -1
      .eslintrc.js
  2. +20
    -20
      src/components/Combat.vue
  3. +77
    -77
      src/game/combat/actions.ts
  4. +19
    -19
      src/game/creatures/cafat.ts
  5. +40
    -43
      src/game/entity.ts
  6. +71
    -67
      src/game/vore.ts

+ 2
- 1
.eslintrc.js 查看文件

@@ -17,6 +17,7 @@ module.exports = {
'no-useless-constructor': 'off', 'no-useless-constructor': 'off',
'@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'off',
'quotes': 'off', 'quotes': 'off',
'function-paren-newline': ['error', 'multiline-arguments']
'function-paren-newline': ['error', 'multiline-arguments'],
'@typescript-eslint/member-ordering': ['warn']
} }
} }

+ 20
- 20
src/components/Combat.vue 查看文件

@@ -97,17 +97,17 @@ export default class Combat extends Vue {


actionDescription = '' actionDescription = ''


created () {
this.$data.left = this.encounter.combatants.filter(x => x.side === Side.Heroes)[0]
this.$data.right = this.encounter.combatants.filter(x => x.side === Side.Monsters)[0]
this.$data.combatants = this.encounter.combatants
}

mounted () {
const leftStats = this.$el.querySelector("#left-stats")
@Emit("described")
described (entry: LogEntry) {
const actionDesc = document.querySelector("#action-desc")


if (leftStats !== null) {
leftStats.scrollTo(leftStats.getBoundingClientRect().width * 2, 0)
if (actionDesc !== null) {
const holder = document.createElement("div")
entry.render().forEach(element => {
holder.appendChild(element)
})
actionDesc.innerHTML = ''
actionDesc.appendChild(holder)
} }
} }


@@ -176,17 +176,17 @@ export default class Combat extends Vue {
}) })
} }


@Emit("described")
described (entry: LogEntry) {
const actionDesc = document.querySelector("#action-desc")
created () {
this.$data.left = this.encounter.combatants.filter(x => x.side === Side.Heroes)[0]
this.$data.right = this.encounter.combatants.filter(x => x.side === Side.Monsters)[0]
this.$data.combatants = this.encounter.combatants
}


if (actionDesc !== null) {
const holder = document.createElement("div")
entry.render().forEach(element => {
holder.appendChild(element)
})
actionDesc.innerHTML = ''
actionDesc.appendChild(holder)
mounted () {
const leftStats = this.$el.querySelector("#left-stats")

if (leftStats !== null) {
leftStats.scrollTo(leftStats.getBoundingClientRect().width * 2, 0)
} }
} }
} }


+ 77
- 77
src/game/combat/actions.ts 查看文件

@@ -7,6 +7,10 @@ import { VoreContainer, Container } from '../vore'
import { CapableCondition, UserDrainedVigorCondition, TogetherCondition, EnemyCondition, SoloCondition, PairCondition, ContainsCondition, ContainedByCondition } from './conditions' import { CapableCondition, UserDrainedVigorCondition, TogetherCondition, EnemyCondition, SoloCondition, PairCondition, ContainsCondition, ContainedByCondition } from './conditions'


export class PassAction extends Action { export class PassAction extends Action {
constructor () {
super("Pass", "Do nothing", [new SoloCondition()])
}

execute (user: Creature, target: Creature): LogEntry { execute (user: Creature, target: Creature): LogEntry {
return nilLog return nilLog
} }
@@ -14,24 +18,11 @@ export class PassAction extends Action {
describe (user: Creature, target: Creature): LogEntry { describe (user: Creature, target: Creature): LogEntry {
return new LogLine("Do nothing.") return new LogLine("Do nothing.")
} }

constructor () {
super("Pass", "Do nothing", [new SoloCondition()])
}
} }


export class AttackAction extends Action { export class AttackAction extends Action {
protected test: StatTest protected test: StatTest


protected successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLine(
`${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} for `,
target.effectiveDamage(args.damage).renderShort()
)

protected failLine: PairLine<Creature> = (user, target) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('miss', 'misses'))} ${target.name.objective}`
)

constructor (protected damage: DamageFormula, protected verb: Verb = new Verb('smack')) { constructor (protected damage: DamageFormula, protected verb: Verb = new Verb('smack')) {
super( super(
verb.root.capital, verb.root.capital,
@@ -60,14 +51,28 @@ export class AttackAction extends Action {
describe (user: Creature, target: Creature): LogEntry { describe (user: Creature, target: Creature): LogEntry {
return new LogLine(`Attack ${target.name}. `, this.damage.describe(user, target), '. ', this.test.explain(user, target)) return new LogLine(`Attack ${target.name}. `, this.damage.describe(user, target), '. ', this.test.explain(user, target))
} }

protected successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLine(
`${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} for `,
target.effectiveDamage(args.damage).renderShort()
)

protected failLine: PairLine<Creature> = (user, target) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('miss', 'misses'))} ${target.name.objective}`
)
} }


export class DevourAction extends Action { export class DevourAction extends Action {
private test: StatVigorTest private test: StatVigorTest


protected failLine: PairLineArgs<Entity, { container: Container }> = (user, target, args) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${args.container.consumeVerb} ${target.name.objective}.`
)
constructor (protected container: Container) {
super(
new DynText(new LiveText(container, x => x.consumeVerb.capital), ' (', new LiveText(container, x => x.name.all), ')'),
new LiveText(container, x => `Try to ${x.consumeVerb} your foe`),
[new CapableCondition(), new TogetherCondition()]
)
this.test = new StatVigorTest(Stat.Power)
}


allowed (user: Creature, target: Creature): boolean { allowed (user: Creature, target: Creature): boolean {
const owner = this.container.owner === user const owner = this.container.owner === user
@@ -81,13 +86,8 @@ export class DevourAction extends Action {
} }
} }


constructor (protected container: Container) {
super(
new DynText(new LiveText(container, x => x.consumeVerb.capital), ' (', new LiveText(container, x => x.name.all), ')'),
new LiveText(container, x => `Try to ${x.consumeVerb} your foe`),
[new CapableCondition(), new TogetherCondition()]
)
this.test = new StatVigorTest(Stat.Power)
describe (user: Creature, target: Creature): LogEntry {
return new LogLine(`Try to ${this.container.consumeVerb} your opponent, sending them to your ${this.container.name}. `, this.test.explain(user, target))
} }


execute (user: Creature, target: Creature): LogEntry { execute (user: Creature, target: Creature): LogEntry {
@@ -98,19 +98,20 @@ export class DevourAction extends Action {
} }
} }


describe (user: Creature, target: Creature): LogEntry {
return new LogLine(`Try to ${this.container.consumeVerb} your opponent, sending them to your ${this.container.name}. `, this.test.explain(user, target))
}
protected failLine: PairLineArgs<Entity, { container: Container }> = (user, target, args) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${args.container.consumeVerb} ${target.name.objective}.`
)
} }


export class FeedAction extends Action { export class FeedAction extends Action {
protected successLine: PairLine<Entity> = (user, target) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('feed'))} ${user.pronouns.reflexive} to ${target.name}. `
)

protected failLine: PairLine<Entity> = (user, target) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to feed ${user.pronouns.reflexive} to ${target.name}. `
)
constructor (protected container: Container) {
super(
'Feed',
'Feed yourself to your opponent',
[new UserDrainedVigorCondition(Vigor.Resolve), new TogetherCondition()]
)
this.name += ` (${container.name})`
}


allowed (user: Creature, target: Creature): boolean { allowed (user: Creature, target: Creature): boolean {
const owner = this.container.owner === target const owner = this.container.owner === target
@@ -124,15 +125,6 @@ export class FeedAction extends Action {
} }
} }


constructor (protected container: Container) {
super(
'Feed',
'Feed yourself to your opponent',
[new UserDrainedVigorCondition(Vigor.Resolve), new TogetherCondition()]
)
this.name += ` (${container.name})`
}

execute (user: Creature, target: Creature): LogEntry { execute (user: Creature, target: Creature): LogEntry {
return new LogLines(this.successLine(user, target), this.container.consume(user)) return new LogLines(this.successLine(user, target), this.container.consume(user))
} }
@@ -140,18 +132,18 @@ export class FeedAction extends Action {
describe (user: Creature, target: Creature): LogEntry { 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}...`) 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 Action {
private test: StatVigorTest

protected successLine: PairLineArgs<Entity, { container: Container }> = (prey, pred, args) => new LogLine(
`${prey.name.capital} ${prey.name.conjugate(new Verb('escape'))} from ${pred.name.possessive} ${args.container.name}.`
protected successLine: PairLine<Entity> = (user, target) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('feed'))} ${user.pronouns.reflexive} to ${target.name}. `
) )


protected failLine: PairLineArgs<Entity, { container: Container }> = (prey, pred, args) => new LogLine(
`${prey.name.capital} ${prey.name.conjugate(new Verb('fail'))} to escape from ${pred.name.possessive} ${args.container.name}.`
protected failLine: PairLine<Entity> = (user, target) => new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to feed ${user.pronouns.reflexive} to ${target.name}. `
) )
}

export class StruggleAction extends Action {
private test: StatVigorTest


constructor (public container: Container) { constructor (public container: Container) {
super( super(
@@ -177,17 +169,17 @@ export class StruggleAction extends Action {
describe (user: Creature, target: Creature): LogEntry { describe (user: Creature, target: Creature): LogEntry {
return new LogLine(`Try to escape from ${target.name}'s ${this.container.name}. `, this.test.explain(user, target)) return new LogLine(`Try to escape from ${target.name}'s ${this.container.name}. `, this.test.explain(user, target))
} }

protected successLine: PairLineArgs<Entity, { container: Container }> = (prey, pred, args) => new LogLine(
`${prey.name.capital} ${prey.name.conjugate(new Verb('escape'))} from ${pred.name.possessive} ${args.container.name}.`
)

protected failLine: PairLineArgs<Entity, { container: Container }> = (prey, pred, args) => new LogLine(
`${prey.name.capital} ${prey.name.conjugate(new Verb('fail'))} to escape from ${pred.name.possessive} ${args.container.name}.`
)
} }


export abstract class EatenAction extends Action { export abstract class EatenAction extends Action {
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) { constructor (public container: Container, name: TextLike, desc: string) {
super( super(
new DynText(name, ' (', new LiveText(container, x => x.name.all), ')'), new DynText(name, ' (', new LiveText(container, x => x.name.all), ')'),
@@ -195,17 +187,17 @@ export abstract class EatenAction extends Action {
[new CapableCondition(), new PairCondition()] [new CapableCondition(), new PairCondition()]
) )
} }
}


export class DigestAction extends Action {
allowed (user: Creature, target: Creature) { allowed (user: Creature, target: Creature) {
if (this.container.owner === user && this.container.contents.length > 0) {
if (target.containedIn === this.container) {
return super.allowed(user, target) return super.allowed(user, target)
} else { } else {
return false return false
} }
} }
}


export class DigestAction extends Action {
constructor (protected container: VoreContainer) { constructor (protected container: VoreContainer) {
super( super(
new DynText('Digest (', new LiveText(container, container => container.name.all), ')'), new DynText('Digest (', new LiveText(container, container => container.name.all), ')'),
@@ -214,6 +206,14 @@ export class DigestAction extends Action {
) )
} }


allowed (user: Creature, target: Creature) {
if (this.container.owner === user && this.container.contents.length > 0) {
return super.allowed(user, target)
} else {
return false
}
}

execute (user: Creature, target: Creature): LogEntry { execute (user: Creature, target: Creature): LogEntry {
const results = this.container.tick(60) const results = this.container.tick(60)
return new CompositeLog(results) return new CompositeLog(results)
@@ -225,14 +225,6 @@ export class DigestAction extends Action {
} }


export class ReleaseAction extends Action { export class ReleaseAction extends Action {
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) { constructor (protected container: Container) {
super( super(
new DynText('Release (', new LiveText(container, x => x.name.all), ')'), new DynText('Release (', new LiveText(container, x => x.name.all), ')'),
@@ -241,6 +233,14 @@ export class ReleaseAction extends Action {
) )
} }


allowed (user: Creature, target: Creature) {
if (target.containedIn === this.container && this.container.contents.indexOf(target) >= 0) {
return super.allowed(user, target)
} else {
return false
}
}

execute (user: Creature, target: Creature): LogEntry { execute (user: Creature, target: Creature): LogEntry {
return this.container.release(target) return this.container.release(target)
} }
@@ -253,6 +253,14 @@ export class ReleaseAction extends Action {
export class TransferAction extends Action { export class TransferAction extends Action {
verb: Verb = new Verb('send') verb: Verb = new Verb('send')


constructor (protected from: Container, protected to: Container, name = 'Transfer') {
super(
name,
`${from.name.all.capital} to ${to.name.all}`,
[new CapableCondition(), new PairCondition()]
)
}

line: PairLineArgs<Creature, { from: Container; to: Container }> = (user, target, args) => new LogLine( line: PairLineArgs<Creature, { from: Container; to: Container }> = (user, target, args) => new LogLine(
`${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} from ${user.pronouns.possessive} ${args.from.name} to ${user.pronouns.possessive} ${args.to.name}` `${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} from ${user.pronouns.possessive} ${args.from.name} to ${user.pronouns.possessive} ${args.to.name}`
) )
@@ -265,14 +273,6 @@ export class TransferAction extends Action {
} }
} }


constructor (protected from: Container, protected to: Container, name = 'Transfer') {
super(
name,
`${from.name.all.capital} to ${to.name.all}`,
[new CapableCondition(), new PairCondition()]
)
}

execute (user: Creature, target: Creature): LogEntry { execute (user: Creature, target: Creature): LogEntry {
this.from.release(target) this.from.release(target)
this.to.consume(target) this.to.consume(target)


+ 19
- 19
src/game/creatures/cafat.ts 查看文件

@@ -8,11 +8,6 @@ import { InstantKillEffect } from '../combat/effects'
import * as Words from '../words' import * as Words from '../words'


class BellyCrushAction extends AttackAction { class BellyCrushAction extends AttackAction {
successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLines(new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('crush', 'crushes'))} on ${target.name.objective} with ${user.pronouns.possessive} belly for `,
target.effectiveDamage(args.damage).renderShort()
), new ImgElem('./media/cafat/images/belly-crush.webp'))

constructor (_damage: Damage) { constructor (_damage: Damage) {
super({ super({
calc (user) { return _damage.scale(user.voreStats.Bulk / 25) }, calc (user) { return _damage.scale(user.voreStats.Bulk / 25) },
@@ -26,9 +21,20 @@ class BellyCrushAction extends AttackAction {
describe (user: Creature, target: Creature): LogEntry { describe (user: Creature, target: Creature): LogEntry {
return new LogLine(`Crush ${target.name} under your gut. `, this.damage.describe(user, target)) return new LogLine(`Crush ${target.name} under your gut. `, this.damage.describe(user, target))
} }

successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLines(new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('crush', 'crushes'))} on ${target.name.objective} with ${user.pronouns.possessive} belly for `,
target.effectiveDamage(args.damage).renderShort()
), new ImgElem('./media/cafat/images/belly-crush.webp'))
} }


class BelchAction extends AttackAction { class BelchAction extends AttackAction {
constructor (damage: Damage) {
super(new ConstantDamageFormula(damage))
this.name = 'Belch'
this.desc = 'Drain your foe\'s stats with a solid BELCH'
}

successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLines( successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLines(
new LogLine( new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb('belch', 'belches'))} on ${target.name.objective} for `, `${user.name.capital} ${user.name.conjugate(new Verb('belch', 'belches'))} on ${target.name.objective} for `,
@@ -36,32 +42,26 @@ class BelchAction extends AttackAction {
), ),
new ImgElem('./media/cafat/images/belch.webp') new ImgElem('./media/cafat/images/belch.webp')
) )

constructor (damage: Damage) {
super(new ConstantDamageFormula(damage))
this.name = 'Belch'
this.desc = 'Drain your foe\'s stats with a solid BELCH'
}
} }


class CrushAction extends EatenAction { class CrushAction extends EatenAction {
line: PairLineArgs<Creature, { container: VoreContainer }> = (user, target, args) => new LogLine(
`${user.name.capital.possessive} ${args.container.name} ${Words.Brutally} ${user.name.conjugate(new Verb('crush', 'crushes'))} ${target.name.objective}; ${user.pronouns.subjective} ${user.pronouns.conjugate(new Verb('belch', 'belches'))} as ${user.pronouns.possessive} gut lets out a fatal CRUNCH `,
new ImgElem('./media/cafat/images/crunch.webp')
)

constructor (private _container: VoreContainer) { constructor (private _container: VoreContainer) {
super(_container, "Crush", "Crush 'em!") super(_container, "Crush", "Crush 'em!")
this.desc = "Crush somebody in your gut" this.desc = "Crush somebody in your gut"
} }


describe (user: Creature, target: Creature): LogEntry {
return new LogLine(`Crush ${target.name} in your ${this.container.name} for massive, unavoidable damage.`)
}

execute (user: Creature, target: Creature): LogEntry { execute (user: Creature, target: Creature): LogEntry {
return new LogLines(this.line(user, target, { container: this._container }), target.applyEffect(new InstantKillEffect())) return new LogLines(this.line(user, target, { container: this._container }), target.applyEffect(new InstantKillEffect()))
} }


describe (user: Creature, target: Creature): LogEntry {
return new LogLine(`Crush ${target.name} in your ${this.container.name} for massive, unavoidable damage.`)
}
line: PairLineArgs<Creature, { container: VoreContainer }> = (user, target, args) => new LogLine(
`${user.name.capital.possessive} ${args.container.name} ${Words.Brutally} ${user.name.conjugate(new Verb('crush', 'crushes'))} ${target.name.objective}; ${user.pronouns.subjective} ${user.pronouns.conjugate(new Verb('belch', 'belches'))} as ${user.pronouns.possessive} gut lets out a fatal CRUNCH `,
new ImgElem('./media/cafat/images/crunch.webp')
)
} }


export class Cafat extends Creature { export class Cafat extends Creature {


+ 40
- 43
src/game/entity.ts 查看文件

@@ -26,9 +26,9 @@ export abstract class Entity {
} }
} }


title: TextLike = "Some thing."
desc: TextLike = "It's a ting." desc: TextLike = "It's a ting."
perspective: POV = POV.Third perspective: POV = POV.Third
title: TextLike = "Some thing."


constructor (public baseName: Noun, public kind: Noun, public basePronouns: Pronoun) { constructor (public baseName: Noun, public kind: Noun, public basePronouns: Pronoun) {


@@ -36,17 +36,23 @@ export abstract class Entity {
} }


export abstract class Mortal extends Entity { export abstract class Mortal extends Entity {
abstract destroy (): LogEntry;
abstract effectiveDamage (damage: Damage): Damage
resistances: Map<DamageType, number> = new Map() resistances: Map<DamageType, number> = new Map()
stats: Stats; stats: Stats;

vigors: {[key in Vigor]: number} = { vigors: {[key in Vigor]: number} = {
[Vigor.Health]: 100, [Vigor.Health]: 100,
[Vigor.Stamina]: 100, [Vigor.Stamina]: 100,
[Vigor.Resolve]: 100 [Vigor.Resolve]: 100
} }


constructor (name: Noun, kind: Noun, pronouns: Pronoun, public baseStats: Stats) {
super(name, kind, pronouns)
Object.entries(this.maxVigors).forEach(([key, val]) => {
this.vigors[key as Vigor] = val
})

this.stats = Object.keys(Stat).reduce((base: any, key) => { base[key] = baseStats[key as Stat]; return base }, {})
}

get maxVigors (): Readonly<Vigors> { get maxVigors (): Readonly<Vigors> {
return { return {
Health: this.stats.Toughness * 10 + this.stats.Power * 5, Health: this.stats.Toughness * 10 + this.stats.Power * 5,
@@ -96,33 +102,33 @@ export abstract class Mortal extends Entity {
return this.name.toString() return this.name.toString()
} }


constructor (name: Noun, kind: Noun, pronouns: Pronoun, public baseStats: Stats) {
super(name, kind, pronouns)
Object.entries(this.maxVigors).forEach(([key, val]) => {
this.vigors[key as Vigor] = val
})

this.stats = Object.keys(Stat).reduce((base: any, key) => { base[key] = baseStats[key as Stat]; return base }, {})
}
abstract destroy (): LogEntry;
abstract effectiveDamage (damage: Damage): Damage
} }


export class Creature extends Vore implements Combatant { export class Creature extends Vore implements Combatant {
title = "Lv. 1 Creature"
actions: Array<Action> = []
containedIn: VoreContainer|null = null;
desc = "Some creature" desc = "Some creature"
effects: Array<StatusEffect> = []
groupActions: Array<GroupAction> = []
items: Array<Item> = []
otherActions: Array<Action> = []
side: Side side: Side
title = "Lv. 1 Creature"


effects: Array<StatusEffect> = []
constructor (name: Noun, kind: Noun, pronouns: Pronoun, stats: Stats, preyPrefs: Set<VoreType>, predPrefs: Set<VoreType>, mass: number) {
super(name, kind, pronouns, stats, preyPrefs, predPrefs, mass)

this.actions.push(new PassAction())
this.side = Side.Heroes
}


applyEffect (effect: StatusEffect): LogEntry { applyEffect (effect: StatusEffect): LogEntry {
this.effects.push(effect) this.effects.push(effect)
return effect.onApply(this) return effect.onApply(this)
} }


removeEffect (effect: StatusEffect): LogEntry {
this.effects = this.effects.filter(eff => eff !== effect)
return effect.onRemove(this)
}

/** /**
* Determines how much damage an attack would do * Determines how much damage an attack would do
*/ */
@@ -132,6 +138,21 @@ export class Creature extends Vore implements Combatant {
}, damage) }, damage)
} }


executeAction (action: Action, target: Creature): LogEntry {
const effectResults = this.effects.map(effect => effect.preAction(this))
const blocking = effectResults.filter(result => result.prevented)
if (blocking.length > 0) {
return new LogLines(...blocking.map(result => result.log))
} else {
return action.execute(this, target)
}
}

removeEffect (effect: StatusEffect): LogEntry {
this.effects = this.effects.filter(eff => eff !== effect)
return effect.onRemove(this)
}

get status (): Array<VisibleStatus> { get status (): Array<VisibleStatus> {
const results: Array<VisibleStatus> = [] const results: Array<VisibleStatus> = []


@@ -154,30 +175,6 @@ export class Creature extends Vore implements Combatant {
return results return results
} }


executeAction (action: Action, target: Creature): LogEntry {
const effectResults = this.effects.map(effect => effect.preAction(this))
const blocking = effectResults.filter(result => result.prevented)
if (blocking.length > 0) {
return new LogLines(...blocking.map(result => result.log))
} else {
return action.execute(this, target)
}
}

actions: Array<Action> = []
groupActions: Array<GroupAction> = []
otherActions: Array<Action> = []
items: Array<Item> = []

containedIn: VoreContainer|null = null;

constructor (name: Noun, kind: Noun, pronouns: Pronoun, stats: Stats, preyPrefs: Set<VoreType>, predPrefs: Set<VoreType>, mass: number) {
super(name, kind, pronouns, stats, preyPrefs, predPrefs, mass)

this.actions.push(new PassAction())
this.side = Side.Heroes
}

validActions (target: Creature): Array<Action> { validActions (target: Creature): Array<Action> {
let choices = this.actions.concat( let choices = this.actions.concat(
this.containers.flatMap(container => container.actions) this.containers.flatMap(container => container.actions)


+ 71
- 67
src/game/vore.ts 查看文件

@@ -13,46 +13,13 @@ export enum VoreType {
} }


export abstract class Vore extends Mortal { export abstract class Vore extends Mortal {
destroyed = false;
voreStats: VoreStats

containedIn: Container | null = null
containers: Array<VoreContainer> = [] containers: Array<VoreContainer> = []
otherContainers: Array<Container> = [] otherContainers: Array<Container> = []


destroy (): LogEntry {
const line: SoloLine<Vore> = (victim) => new LogLine(
`${victim.name.capital} ${victim.name.conjugate(new Verb('die'))}`
)

const released: Array<Vore> = this.containers.flatMap(container => {
return container.contents.map(prey => {
prey.containedIn = this.containedIn
if (this.containedIn !== null) {
this.containedIn.contents.push(prey)
}
return prey
})
})

const names = released.reduce((list: Array<string>, prey: Vore) => list.concat([prey.name.toString()]), []).joinGeneral(", ", " and ").join("")
containedIn: Container | null = null
destroyed = false;


if (released.length > 0) {
if (this.containedIn === null) {
return new LogLines(
line(this),
new LogLine(names + ` spill out!`)
)
} else {
return new LogLines(
line(this),
new LogLine(names + ` spill out into ${this.containedIn.owner.name}'s ${this.containedIn.name}!`)
)
}
} else {
return line(this)
}
}
voreStats: VoreStats


constructor (name: Noun, kind: Noun, pronouns: Pronoun, baseStats: Stats, public preyPrefs: Set<VoreType>, public predPrefs: Set<VoreType>, public mass: number) { constructor (name: Noun, kind: Noun, pronouns: Pronoun, baseStats: Stats, public preyPrefs: Set<VoreType>, public predPrefs: Set<VoreType>, public mass: number) {
super(name, kind, pronouns, baseStats) super(name, kind, pronouns, baseStats)
@@ -94,20 +61,57 @@ export abstract class Vore extends Mortal {
} }
} }
} }

destroy (): LogEntry {
const line: SoloLine<Vore> = (victim) => new LogLine(
`${victim.name.capital} ${victim.name.conjugate(new Verb('die'))}`
)

const released: Array<Vore> = this.containers.flatMap(container => {
return container.contents.map(prey => {
prey.containedIn = this.containedIn
if (this.containedIn !== null) {
this.containedIn.contents.push(prey)
}
return prey
})
})

const names = released.reduce((list: Array<string>, prey: Vore) => list.concat([prey.name.toString()]), []).joinGeneral(", ", " and ").join("")

if (released.length > 0) {
if (this.containedIn === null) {
return new LogLines(
line(this),
new LogLine(names + ` spill out!`)
)
} else {
return new LogLines(
line(this),
new LogLine(names + ` spill out into ${this.containedIn.owner.name}'s ${this.containedIn.name}!`)
)
}
} else {
return line(this)
}
}
} }


export interface Container extends Actionable { export interface Container extends Actionable {
name: Noun; name: Noun;
owner: Vore; owner: Vore;
voreTypes: Set<VoreType>; voreTypes: Set<VoreType>;
contents: Array<Vore>;
capacity: number; capacity: number;
fullness: number; fullness: number;

contents: Array<Vore>;
describe: () => LogEntry;

canTake: (prey: Vore) => boolean; canTake: (prey: Vore) => boolean;
consume: (prey: Vore) => LogEntry; consume: (prey: Vore) => LogEntry;
release: (prey: Vore) => LogEntry; release: (prey: Vore) => LogEntry;
struggle: (prey: Vore) => LogEntry; struggle: (prey: Vore) => LogEntry;
describe: () => LogEntry;


consumeVerb: Verb; consumeVerb: Verb;
releaseVerb: Verb; releaseVerb: Verb;
@@ -119,6 +123,17 @@ export abstract class NormalContainer implements Container {
contents: Array<Vore> = [] contents: Array<Vore> = []
actions: Array<Action> = [] actions: Array<Action> = []


abstract consumeVerb: Verb
abstract releaseVerb: Verb
abstract struggleVerb: Verb

constructor (name: Noun, public owner: Vore, public voreTypes: Set<VoreType>, public capacity: number) {
this.name = name.all
this.actions.push(new DevourAction(this))
this.actions.push(new ReleaseAction(this))
this.actions.push(new StruggleAction(this))
}

consumeLine: PairLineArgs<Vore, { container: Container }> = (user, target, args) => { consumeLine: PairLineArgs<Vore, { container: Container }> = (user, target, args) => {
return new LogLine(`${user.name.capital} ${user.name.conjugate(this.consumeVerb)} ${target.name.objective} in ${user.pronouns.possessive} ${args.container.name}.`) return new LogLine(`${user.name.capital} ${user.name.conjugate(this.consumeVerb)} ${target.name.objective} in ${user.pronouns.possessive} ${args.container.name}.`)
} }
@@ -131,10 +146,6 @@ export abstract class NormalContainer implements Container {
return new LogLine(`${user.name.capital} ${user.name.conjugate(this.struggleVerb)} within ${target.name.possessive} ${args.container.name}.`) return new LogLine(`${user.name.capital} ${user.name.conjugate(this.struggleVerb)} within ${target.name.possessive} ${args.container.name}.`)
} }


abstract consumeVerb: Verb
abstract releaseVerb: Verb
abstract struggleVerb: Verb

get fullness (): number { get fullness (): number {
return Array.from(this.contents.values()).reduce((total: number, prey: Vore) => total + prey.voreStats.Bulk, 0) return Array.from(this.contents.values()).reduce((total: number, prey: Vore) => total + prey.voreStats.Bulk, 0)
} }
@@ -181,13 +192,6 @@ export abstract class NormalContainer implements Container {


return new LogLine(...lines) return new LogLine(...lines)
} }

constructor (name: Noun, public owner: Vore, public voreTypes: Set<VoreType>, public capacity: number) {
this.name = name.all
this.actions.push(new DevourAction(this))
this.actions.push(new ReleaseAction(this))
this.actions.push(new StruggleAction(this))
}
} }


export interface VoreContainer extends Container { export interface VoreContainer extends Container {
@@ -197,8 +201,20 @@ export interface VoreContainer extends Container {
} }


export abstract class NormalVoreContainer extends NormalContainer implements VoreContainer { export abstract class NormalVoreContainer extends NormalContainer implements VoreContainer {
consumeVerb = new Verb('devour')
releaseVerb = new Verb('release', 'releases', 'releasing', 'released')
struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled')

digested: Array<Vore> = [] digested: Array<Vore> = []


constructor (name: Noun, owner: Vore, voreTypes: Set<VoreType>, capacity: number, private damage: Damage) {
super(name, owner, voreTypes, capacity)

this.name = name

this.actions.push(new DigestAction(this))
}

consumeLine: PairLineArgs<Vore, { container: Container }> = (user, target, args) => { consumeLine: PairLineArgs<Vore, { container: Container }> = (user, target, args) => {
return new LogLine(`${user.name.capital} ${user.name.conjugate(this.consumeVerb)} ${target.name.objective}, forcing ${target.pronouns.objective} into ${user.pronouns.possessive} ${args.container.name}.`) return new LogLine(`${user.name.capital} ${user.name.conjugate(this.consumeVerb)} ${target.name.objective}, forcing ${target.pronouns.objective} into ${user.pronouns.possessive} ${args.container.name}.`)
} }
@@ -211,10 +227,6 @@ export abstract class NormalVoreContainer extends NormalContainer implements Vor
return new LogLine(`${user.name.capital.possessive} ${args.container.name} finishes ${Words.Digests.present} ${target.name.objective} down, ${target.pronouns.possessive} ${Words.Struggles.singular} fading away.`) return new LogLine(`${user.name.capital.possessive} ${args.container.name} finishes ${Words.Digests.present} ${target.name.objective} down, ${target.pronouns.possessive} ${Words.Struggles.singular} fading away.`)
} }


consumeVerb = new Verb('devour')
releaseVerb = new Verb('release', 'releases', 'releasing', 'released')
struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled')

tick (dt: number): LogEntry { tick (dt: number): LogEntry {
const justDigested: Array<Vore> = [] const justDigested: Array<Vore> = []


@@ -246,23 +258,9 @@ export abstract class NormalVoreContainer extends NormalContainer implements Vor
digest (preys: Vore[]): LogEntry { digest (preys: Vore[]): LogEntry {
return new LogLines(...preys.map(prey => this.digestLine(this.owner, prey, { container: this }))) return new LogLines(...preys.map(prey => this.digestLine(this.owner, prey, { container: this })))
} }

constructor (name: Noun, owner: Vore, voreTypes: Set<VoreType>, capacity: number, private damage: Damage) {
super(name, owner, voreTypes, capacity)

this.name = name

this.actions.push(new DigestAction(this))
}
} }


abstract class InnerContainer extends NormalVoreContainer { abstract class InnerContainer extends NormalVoreContainer {
release (prey: Vore): LogEntry {
prey.containedIn = this.escape
this.contents = this.contents.filter(victim => victim !== prey)
return this.releaseLine(this.owner, prey, { container: this })
}

constructor (name: Noun, owner: Vore, voreTypes: Set<VoreType>, capacity: number, damage: Damage, private escape: VoreContainer) { constructor (name: Noun, owner: Vore, voreTypes: Set<VoreType>, capacity: number, damage: Damage, private escape: VoreContainer) {
super(name, owner, voreTypes, capacity, damage) super(name, owner, voreTypes, capacity, damage)


@@ -271,6 +269,12 @@ abstract class InnerContainer extends NormalVoreContainer {
this.actions.push(new DigestAction(this)) this.actions.push(new DigestAction(this))
this.actions.push(new StruggleAction(this)) this.actions.push(new StruggleAction(this))
} }

release (prey: Vore): LogEntry {
prey.containedIn = this.escape
this.contents = this.contents.filter(victim => victim !== prey)
return this.releaseLine(this.owner, prey, { container: this })
}
} }


export class Stomach extends NormalVoreContainer { export class Stomach extends NormalVoreContainer {


正在加载...
取消
保存