@@ -1,37 +1,47 @@
import { DamageType, Damage, Combatant, Stats, Action, Vigor, VoreStats, VoreStat, Stat, Side, GroupAction, Vigors, VisibleStatus, ImplicitStatus, StatusEffect } from './combat'
import { DamageType, Damage, Combatant, Stats, Action, Vigor, VoreStats, VoreStat, Stat, Side, GroupAction, Vigors, VisibleStatus, ImplicitStatus, StatusEffect } from './combat'
import { Noun, Pronoun, TextLike, POV } from './language'
import { Noun, Pronoun, TextLike, POV, PronounAsNoun, FirstPersonPronouns, SecondPersonPronouns } from './language'
import { LogEntry, LogLine, LogLines } from './interface'
import { LogEntry, LogLine, LogLines } from './interface'
import { Vore, VoreContainer, VoreType, Container } from './vore'
import { Vore, VoreContainer, VoreType, Container } from './vore'
import { Item } from './items'
import { Item } from './items'
import { PassAction } from './combat/actions'
import { PassAction } from './combat/actions'
export interface Entity {
name: Noun;
pronouns: Pronoun;
baseName: Noun;
basePronouns: Pronoun;
title: TextLike;
desc: TextLike;
perspective: POV;
export abstract class Entity {
get name (): Noun {
if (this.perspective === POV.First) {
return new PronounAsNoun(FirstPersonPronouns)
} else if (this.perspective === POV.Second) {
return new PronounAsNoun(SecondPersonPronouns)
} else {
return this.baseName
}
}
get pronouns (): Pronoun {
if (this.perspective === POV.First) {
return FirstPersonPronouns
} else if (this.perspective === POV.Second) {
return SecondPersonPronouns
} else {
return this.basePronouns
}
}
title: TextLike = "Some thing."
desc: TextLike = "It's a ting."
perspective: POV = POV.Third
constructor (public baseName: Noun, public kind: Noun, public basePronouns: Pronoun) {
}
}
}
export interface Mortal extends Entity {
kind: Noun;
vigors: {[key in Vigor]: number};
maxVigors: Readonly<{[key in Vigor]: number}>;
disabled: boolean;
resistances: Map<DamageType, number>;
takeDamage: (damage: Damage) => void;
export abstract class Mortal extends Entity {
abstract destroy (): LogEntry;
abstract effectiveDamage (damage: Damage): Damage
resistances: Map<DamageType, number> = new Map()
stats: Stats;
stats: Stats;
baseStats: Stats;
status: VisibleStatus[];
destroy: () => LogEntry;
}
export class Creature extends Vore implements Combatant {
title = "Lv. 1 Creature"
desc = "Some creature"
vigors = {
vigors: {[key in Vigor]: number} = {
[Vigor.Health]: 100,
[Vigor.Health]: 100,
[Vigor.Stamina]: 100,
[Vigor.Stamina]: 100,
[Vigor.Resolve]: 100
[Vigor.Resolve]: 100
@@ -45,111 +55,10 @@ export class Creature extends Vore implements Combatant {
}
}
}
}
baseStats: Stats
voreStats: VoreStats
side: Side
effects: Array<StatusEffect> = []
applyEffect (effect: StatusEffect): LogEntry {
this.effects.push(effect)
return effect.onApply(this)
}
removeEffect (effect: StatusEffect): LogEntry {
this.effects = this.effects.filter(eff => eff !== effect)
return effect.onRemove(this)
}
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)
}
}
get disabled (): boolean {
get disabled (): boolean {
return Object.values(this.vigors).some(val => val <= 0)
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 baseName: Noun, public kind: Noun, public basePronouns: Pronoun, public stats: Stats, public preyPrefs: Set<VoreType>, public predPrefs: Set<VoreType>, mass: number) {
super()
const containers = this.containers
this.actions.push(new PassAction())
Object.entries(this.maxVigors).forEach(([key, val]) => {
this.vigors[key as Vigor] = val
})
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] () {
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()
}
/**
* Determines how much damage an attack would do
*/
effectiveDamage (damage: Damage): Damage {
return this.effects.reduce((modifiedDamage: Damage, effect: StatusEffect) => {
return effect.preDamage(this, modifiedDamage)
}, damage)
}
takeDamage (damage: Damage): LogEntry {
takeDamage (damage: Damage): LogEntry {
// first, we record health to decide if the entity just died
// first, we record health to decide if the entity just died
const startHealth = this.vigors.Health
const startHealth = this.vigors.Health
@@ -183,6 +92,46 @@ export class Creature extends Vore implements Combatant {
}
}
}
}
toString (): string {
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 }, {})
}
}
export class Creature extends Vore implements Combatant {
title = "Lv. 1 Creature"
desc = "Some creature"
side: Side
effects: Array<StatusEffect> = []
applyEffect (effect: StatusEffect): LogEntry {
this.effects.push(effect)
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
*/
effectiveDamage (damage: Damage): Damage {
return this.effects.reduce((modifiedDamage: Damage, effect: StatusEffect) => {
return effect.preDamage(this, modifiedDamage)
}, damage)
}
get status (): Array<VisibleStatus> {
get status (): Array<VisibleStatus> {
const results: Array<VisibleStatus> = []
const results: Array<VisibleStatus> = []
@@ -205,6 +154,30 @@ 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)
@@ -232,8 +205,4 @@ export class Creature extends Vore implements Combatant {
return targets.some(target => action.allowed(this, target))
return targets.some(target => action.allowed(this, target))
})
})
}
}
destroy (): LogEntry {
return super.destroy()
}
}
}