|  |  | @@ -72,7 +72,10 @@ export enum DamageType { | 
		
	
		
			
			|  |  |  | Pierce = "Pierce", | 
		
	
		
			
			|  |  |  | Slash = "Slash", | 
		
	
		
			
			|  |  |  | Crush = "Crush", | 
		
	
		
			
			|  |  |  | Acid = "Acid"} | 
		
	
		
			
			|  |  |  | Acid = "Acid", | 
		
	
		
			
			|  |  |  | Seduction = "Seduction", | 
		
	
		
			
			|  |  |  | Dominance = "Dominance" | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | export interface DamageInstance { | 
		
	
		
			
			|  |  |  | type: DamageType; | 
		
	
	
		
			
				|  |  | @@ -155,10 +158,13 @@ export interface Combatant { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | export abstract class Action { | 
		
	
		
			
			|  |  |  | abstract allowed (user: Creature, target: Creature): boolean | 
		
	
		
			
			|  |  |  | allowed (user: Creature, target: Creature): boolean { | 
		
	
		
			
			|  |  |  | return this.conditions.every(cond => cond.allowed(user, target)) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | abstract execute(user: Creature, target: Creature): LogEntry | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (public name: string, public desc: string) { | 
		
	
		
			
			|  |  |  | constructor (public name: string, public desc: string, private conditions: Array<Condition> = []) { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -167,19 +173,56 @@ export abstract class Action { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | export interface Condition { | 
		
	
		
			
			|  |  |  | allowed: (user: Creature, target: Creature) => boolean; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | class InverseCondition implements Condition { | 
		
	
		
			
			|  |  |  | allowed (user: Creature, target: Creature): boolean { | 
		
	
		
			
			|  |  |  | return !this.condition.allowed(user, target) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (private condition: Condition) { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | class CapableCondition implements Condition { | 
		
	
		
			
			|  |  |  | allowed (user: Creature, target: Creature): boolean { | 
		
	
		
			
			|  |  |  | return !user.disabled | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | class DrainedVigorCondition implements Condition { | 
		
	
		
			
			|  |  |  | allowed (user: Creature, target: Creature): boolean { | 
		
	
		
			
			|  |  |  | return user.vigors[this.vigor] <= 0 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (private vigor: Vigor) { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | export interface Actionable { | 
		
	
		
			
			|  |  |  | actions: Array<Action>; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | abstract class SelfAction extends Action { | 
		
	
		
			
			|  |  |  | allowed (user: Creature, target: Creature) { | 
		
	
		
			
			|  |  |  | return user === target | 
		
	
		
			
			|  |  |  | if (user === target) { | 
		
	
		
			
			|  |  |  | return super.allowed(user, target) | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | return false | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | abstract class PairAction extends Action { | 
		
	
		
			
			|  |  |  | allowed (user: Creature, target: Creature) { | 
		
	
		
			
			|  |  |  | return user !== target | 
		
	
		
			
			|  |  |  | if (user !== target) { | 
		
	
		
			
			|  |  |  | return super.allowed(user, target) | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | return false | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -194,7 +237,7 @@ abstract class TogetherAction extends PairAction { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | export class AttackAction extends TogetherAction { | 
		
	
		
			
			|  |  |  | private test: StatTest | 
		
	
		
			
			|  |  |  | protected test: StatTest | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | protected successLines: POVPairArgs<Entity, Entity, { damage: Damage }> = new POVPairArgs([ | 
		
	
		
			
			|  |  |  | [[POV.First, POV.Third], (user, target, args) => new LogLine( | 
		
	
	
		
			
				|  |  | @@ -218,7 +261,7 @@ export class AttackAction extends TogetherAction { | 
		
	
		
			
			|  |  |  | ]) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (protected damage: Damage) { | 
		
	
		
			
			|  |  |  | super('Attack', 'Attack the enemy') | 
		
	
		
			
			|  |  |  | super('Attack', 'Attack the enemy', [new CapableCondition()]) | 
		
	
		
			
			|  |  |  | this.test = new StatTest(Stat.STR) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -254,7 +297,7 @@ export class DevourAction extends TogetherAction { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (protected container: Container) { | 
		
	
		
			
			|  |  |  | super('Devour', 'Try to consume your foe') | 
		
	
		
			
			|  |  |  | super('Devour', 'Try to consume your foe', [new CapableCondition()]) | 
		
	
		
			
			|  |  |  | this.name += ` (${container.name})` | 
		
	
		
			
			|  |  |  | this.test = new StatTest(Stat.STR) | 
		
	
		
			
			|  |  |  | } | 
		
	
	
		
			
				|  |  | @@ -268,6 +311,42 @@ export class DevourAction extends TogetherAction { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | export class FeedAction extends TogetherAction { | 
		
	
		
			
			|  |  |  | private test: StatTest | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | protected failLines: POVPair<Entity, Entity> = new POVPair([ | 
		
	
		
			
			|  |  |  | [[POV.First, POV.Third], (user, target) => new LogLines(`You fail to feed yourself to ${target.name}`)], | 
		
	
		
			
			|  |  |  | [[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} tries to feed ${user.pronouns.possessive} to you, but fails`)], | 
		
	
		
			
			|  |  |  | [[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name} unsuccessfully tries to feed ${user.pronouns.possessive} to ${target.name}`)] | 
		
	
		
			
			|  |  |  | ]) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | allowed (user: Creature, target: Creature): boolean { | 
		
	
		
			
			|  |  |  | const owner = this.container.owner === target | 
		
	
		
			
			|  |  |  | const predOk = Array.from(this.container.voreTypes).every(pref => user.predPrefs.has(pref)) | 
		
	
		
			
			|  |  |  | const preyOk = Array.from(this.container.voreTypes).every(pref => target.preyPrefs.has(pref)) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (owner && predOk && preyOk) { | 
		
	
		
			
			|  |  |  | return super.allowed(user, target) | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | return false | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (protected container: Container) { | 
		
	
		
			
			|  |  |  | super('Feed', 'Feed yourself to your opponent', [new DrainedVigorCondition(Vigor.Willpower)]) | 
		
	
		
			
			|  |  |  | this.name += ` (${container.name})` | 
		
	
		
			
			|  |  |  | this.test = new StatTest(Stat.STR) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | execute (user: Creature, target: Creature): LogEntry { | 
		
	
		
			
			|  |  |  | if (this.test.test(user, target)) { | 
		
	
		
			
			|  |  |  | return this.container.consume(user) | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | return this.failLines.run(user, target) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | export class StruggleAction extends PairAction { | 
		
	
		
			
			|  |  |  | private test: StatTest | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -286,7 +365,7 @@ export class StruggleAction extends PairAction { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (public container: Container) { | 
		
	
		
			
			|  |  |  | super('Struggle', 'Try to escape your predator') | 
		
	
		
			
			|  |  |  | super('Struggle', 'Try to escape your predator', [new CapableCondition()]) | 
		
	
		
			
			|  |  |  | this.test = new StatTest(Stat.STR) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -315,7 +394,7 @@ export class DigestAction extends SelfAction { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (protected container: Container) { | 
		
	
		
			
			|  |  |  | super('Digest', 'Digest all of your current prey') | 
		
	
		
			
			|  |  |  | super('Digest', 'Digest all of your current prey', [new CapableCondition()]) | 
		
	
		
			
			|  |  |  | this.name += ` (${container.name})` | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -356,7 +435,7 @@ export class TransferAction extends PairAction { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | constructor (protected from: Container, protected to: Container) { | 
		
	
		
			
			|  |  |  | super('Transfer', `Shove your prey from your ${from.name} to your ${to.name}`) | 
		
	
		
			
			|  |  |  | super('Transfer', `Shove your prey from your ${from.name} to your ${to.name}`, [new CapableCondition()]) | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | execute (user: Creature, target: Creature): LogEntry { | 
		
	
	
		
			
				|  |  | 
 |