@@ -1,37 +1,47 @@  
		
	
		
			
			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 { Vore, VoreContainer, VoreType, Container } from './vore'  
		
	
		
			
			import { Item } from './items'  
		
	
		
			
			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;  
		
	
		
			
			  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.Stamina]: 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 {  
		
	
		
			
			    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 {  
		
	
		
			
			    // first, we record health to decide if the entity just died  
		
	
		
			
			    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> {  
		
	
		
			
			    const results: Array<VisibleStatus> = []  
		
	
		
			
			 
		
	
	
		
			
				
				
				
				
					 
			
			@@ -205,6 +154,30 @@ export class Creature extends Vore implements Combatant {  
		
	
		
			
			    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> {  
		
	
		
			
			    let choices = this.actions.concat(  
		
	
		
			
			      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))  
		
	
		
			
			    })  
		
	
		
			
			  }  
		
	
		
			
			 
		
	
		
			
			  destroy (): LogEntry {  
		
	
		
			
			    return super.destroy()  
		
	
		
			
			  }  
		
	
		
			
			}