| @@ -91,6 +91,7 @@ export interface CombatTest { | |||||
| test: (user: Creature, target: Creature) => boolean; | test: (user: Creature, target: Creature) => boolean; | ||||
| odds: (user: Creature, target: Creature) => number; | odds: (user: Creature, target: Creature) => number; | ||||
| explain: (user: Creature, target: Creature) => LogEntry; | explain: (user: Creature, target: Creature) => LogEntry; | ||||
| fail: (user: Creature, target: Creature) => LogEntry; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -347,9 +348,15 @@ export interface Combatant { | |||||
| * An Action is anything that can be done by a [[Creature]] to a [[Creature]]. | * An Action is anything that can be done by a [[Creature]] to a [[Creature]]. | ||||
| */ | */ | ||||
| export abstract class Action { | export abstract class Action { | ||||
| constructor (public name: TextLike, public desc: TextLike, public conditions: Array<Condition> = []) { | |||||
| constructor ( | |||||
| public name: TextLike, | |||||
| public desc: TextLike, | |||||
| public conditions: Array<Condition> = [], | |||||
| public tests: Array<CombatTest> = [] | |||||
| ) { | |||||
| } | } | ||||
| // TODO explain the tests in here | |||||
| allowed (user: Creature, target: Creature): boolean { | allowed (user: Creature, target: Creature): boolean { | ||||
| return this.conditions.every(cond => cond.allowed(user, target)) | return this.conditions.every(cond => cond.allowed(user, target)) | ||||
| @@ -359,34 +366,44 @@ export abstract class Action { | |||||
| return this.name.toString() | return this.name.toString() | ||||
| } | } | ||||
| abstract execute (user: Creature, target: Creature): LogEntry | |||||
| abstract describe (user: Creature, target: Creature): LogEntry | |||||
| } | |||||
| try (user: Creature, target: Creature): LogEntry { | |||||
| const failReason = this.tests.find(test => !test.test(user, target)) | |||||
| if (failReason !== undefined) { | |||||
| return failReason.fail(user, target) | |||||
| } else { | |||||
| return this.execute(user, target) | |||||
| } | |||||
| } | |||||
| describe (user: Creature, target: Creature): LogEntry { | |||||
| return new LogLines( | |||||
| ...this.tests.map(test => test.explain(user, target)) | |||||
| ) | |||||
| } | |||||
| export type TestBundle = { | |||||
| test: CombatTest; | |||||
| fail: PairLine<Creature>; | |||||
| abstract execute (user: Creature, target: Creature): LogEntry | |||||
| } | } | ||||
| export class CompositionAction extends Action { | export class CompositionAction extends Action { | ||||
| private consequences: Array<Consequence>; | private consequences: Array<Consequence>; | ||||
| private tests: Array<TestBundle>; | |||||
| constructor (name: TextLike, desc: TextLike, properties: { conditions?: Array<Condition>; consequences?: Array<Consequence>; tests?: Array<TestBundle> }) { | |||||
| super(name, desc, properties.conditions ?? []) | |||||
| constructor ( | |||||
| name: TextLike, | |||||
| desc: TextLike, | |||||
| properties: { | |||||
| conditions?: Array<Condition>; | |||||
| consequences?: Array<Consequence>; | |||||
| tests?: Array<CombatTest>; | |||||
| } | |||||
| ) { | |||||
| super(name, desc, properties.conditions ?? [], properties.tests ?? []) | |||||
| this.consequences = properties.consequences ?? [] | this.consequences = properties.consequences ?? [] | ||||
| this.tests = properties.tests ?? [] | |||||
| } | } | ||||
| execute (user: Creature, target: Creature): LogEntry { | execute (user: Creature, target: Creature): LogEntry { | ||||
| const failReason = this.tests.find(test => !test.test.test(user, target)) | |||||
| if (failReason !== undefined) { | |||||
| return failReason.fail(user, target) | |||||
| } else { | |||||
| return new LogLines( | |||||
| ...this.consequences.filter(consequence => consequence.applicable(user, target)).map(consequence => consequence.apply(user, target)) | |||||
| ) | |||||
| } | |||||
| return new LogLines( | |||||
| ...this.consequences.filter(consequence => consequence.applicable(user, target)).map(consequence => consequence.apply(user, target)) | |||||
| ) | |||||
| } | } | ||||
| describe (user: Creature, target: Creature): LogEntry { | describe (user: Creature, target: Creature): LogEntry { | ||||
| @@ -2,7 +2,7 @@ import { StatTest, StatVigorTest, StatVigorSizeTest } from './tests' | |||||
| import { DynText, LiveText, TextLike, Verb, PairLine, PairLineArgs } from '../language' | import { DynText, LiveText, TextLike, Verb, PairLine, PairLineArgs } from '../language' | ||||
| import { Entity } from '../entity' | import { Entity } from '../entity' | ||||
| import { Creature } from "../creature" | import { Creature } from "../creature" | ||||
| import { Damage, DamageFormula, Stat, Vigor, Action, Condition } from '../combat' | |||||
| import { Damage, DamageFormula, Stat, Vigor, Action, Condition, CombatTest } from '../combat' | |||||
| import { LogLine, LogLines, LogEntry, nilLog } from '../interface' | import { LogLine, LogLines, LogEntry, nilLog } from '../interface' | ||||
| import { VoreContainer, Container } from '../vore' | import { VoreContainer, Container } from '../vore' | ||||
| import { CapableCondition, UserDrainedVigorCondition, TogetherCondition, EnemyCondition, SoloCondition, PairCondition, ContainsCondition, ContainedByCondition, HasRoomCondition } from './conditions' | import { CapableCondition, UserDrainedVigorCondition, TogetherCondition, EnemyCondition, SoloCondition, PairCondition, ContainsCondition, ContainedByCondition, HasRoomCondition } from './conditions' | ||||
| @@ -28,35 +28,33 @@ export class PassAction extends Action { | |||||
| * A generic action that causes damage. | * A generic action that causes damage. | ||||
| */ | */ | ||||
| export abstract class DamageAction extends Action { | export abstract class DamageAction extends Action { | ||||
| protected test: StatTest | |||||
| abstract successLine: PairLineArgs<Creature, { damage: Damage }> | abstract successLine: PairLineArgs<Creature, { damage: Damage }> | ||||
| abstract failLine: PairLine<Creature> | |||||
| constructor (name: TextLike, desc: TextLike, protected damage: DamageFormula, conditions: Condition[] = []) { | |||||
| constructor (name: TextLike, desc: TextLike, protected damage: DamageFormula, tests: CombatTest[], conditions: Condition[] = []) { | |||||
| super( | super( | ||||
| name, | name, | ||||
| desc, | desc, | ||||
| [new CapableCondition(), new EnemyCondition()].concat(conditions) | |||||
| [new CapableCondition(), new EnemyCondition()].concat(conditions), | |||||
| tests | |||||
| ) | ) | ||||
| this.test = new StatTest(Stat.Power, 10) | |||||
| } | } | ||||
| execute (user: Creature, target: Creature): LogEntry { | |||||
| try (user: Creature, target: Creature): LogEntry { | |||||
| const effectResults = target.effects.map(effect => effect.preAttack(target, user)) | const effectResults = target.effects.map(effect => effect.preAttack(target, user)) | ||||
| if (effectResults.some(result => result.prevented)) { | if (effectResults.some(result => result.prevented)) { | ||||
| return new LogLines(...effectResults.map(result => result.log)) | return new LogLines(...effectResults.map(result => result.log)) | ||||
| } | |||||
| if (this.test.test(user, target)) { | |||||
| const damage = this.damage.calc(user, target) | |||||
| const targetResult = target.takeDamage(damage) | |||||
| const ownResult = this.successLine(user, target, { damage: damage }) | |||||
| return new LogLines(ownResult, targetResult) | |||||
| } else { | } else { | ||||
| return this.failLine(user, target) | |||||
| return super.try(user, target) | |||||
| } | } | ||||
| } | } | ||||
| execute (user: Creature, target: Creature): LogEntry { | |||||
| const damage = this.damage.calc(user, target) | |||||
| const targetResult = target.takeDamage(damage) | |||||
| const ownResult = this.successLine(user, target, { damage: damage }) | |||||
| return new LogLines(ownResult, targetResult) | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -64,11 +62,23 @@ export abstract class DamageAction extends Action { | |||||
| */ | */ | ||||
| export class AttackAction extends DamageAction { | export class AttackAction extends DamageAction { | ||||
| constructor (damage: DamageFormula, protected verb: Verb = new Verb('smack')) { | constructor (damage: DamageFormula, protected verb: Verb = new Verb('smack')) { | ||||
| super(verb.root.capital, 'Attack the enemy', damage, [new TogetherCondition()]) | |||||
| super( | |||||
| verb.root.capital, | |||||
| 'Attack the enemy', | |||||
| damage, | |||||
| [new StatTest( | |||||
| Stat.Power, | |||||
| 10, | |||||
| (user, target) => new LogLine( | |||||
| `${user.name.capital} ${user.name.conjugate(new Verb('miss', 'misses'))} ${target.name.objective}!` | |||||
| ) | |||||
| )], | |||||
| [new TogetherCondition()] | |||||
| ) | |||||
| } | } | ||||
| 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), '. ', super.describe(user, target)) | |||||
| } | } | ||||
| successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLine( | successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLine( | ||||
| @@ -85,15 +95,17 @@ export class AttackAction extends DamageAction { | |||||
| * Devours the target. | * Devours the target. | ||||
| */ | */ | ||||
| export class DevourAction extends Action { | export class DevourAction extends Action { | ||||
| private test: StatVigorSizeTest | |||||
| constructor (protected container: Container) { | constructor (protected container: Container) { | ||||
| super( | super( | ||||
| new DynText(new LiveText(container, x => x.consumeVerb.capital), ' (', new LiveText(container, x => x.name.all), ')'), | 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 LiveText(container, x => `Try to ${x.consumeVerb} your foe`), | ||||
| [new CapableCondition(), new TogetherCondition(), new HasRoomCondition(container)] | |||||
| [new CapableCondition(), new TogetherCondition(), new HasRoomCondition(container)], | |||||
| [new StatVigorSizeTest( | |||||
| Stat.Power, | |||||
| 10, | |||||
| (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${container.consumeVerb} ${target.name.objective}.`) | |||||
| )] | |||||
| ) | ) | ||||
| this.test = new StatVigorSizeTest(Stat.Power) | |||||
| } | } | ||||
| allowed (user: Creature, target: Creature): boolean { | allowed (user: Creature, target: Creature): boolean { | ||||
| @@ -109,20 +121,12 @@ export class DevourAction extends Action { | |||||
| } | } | ||||
| describe (user: Creature, target: Creature): LogEntry { | 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)) | |||||
| return new LogLine(`Try to ${this.container.consumeVerb} your opponent, sending them to your ${this.container.name}. `, super.describe(user, target)) | |||||
| } | } | ||||
| execute (user: Creature, target: Creature): LogEntry { | execute (user: Creature, target: Creature): LogEntry { | ||||
| if (this.test.test(user, target)) { | |||||
| return this.container.consume(target) | |||||
| } else { | |||||
| return this.failLine(user, target, { container: this.container }) | |||||
| } | |||||
| return this.container.consume(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}.` | |||||
| ) | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -171,40 +175,34 @@ export class FeedAction extends Action { | |||||
| * Tries to escape from the target's container | * Tries to escape from the target's container | ||||
| */ | */ | ||||
| export class StruggleAction extends Action { | export class StruggleAction extends Action { | ||||
| private test: StatVigorSizeTest | |||||
| constructor (public container: Container) { | constructor (public container: Container) { | ||||
| super( | super( | ||||
| new DynText('Struggle (', new LiveText(container, x => x.name.all), ')'), | new DynText('Struggle (', new LiveText(container, x => x.name.all), ')'), | ||||
| 'Try to escape from your foe', | 'Try to escape from your foe', | ||||
| [new CapableCondition(), new PairCondition(), new ContainedByCondition(container)] | |||||
| [new CapableCondition(), new PairCondition(), new ContainedByCondition(container)], | |||||
| [new StatVigorSizeTest( | |||||
| Stat.Power, | |||||
| 0, | |||||
| (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to escape from ${target.name.possessive} ${container.name}.`) | |||||
| )] | |||||
| ) | ) | ||||
| this.test = new StatVigorSizeTest(Stat.Power) | |||||
| } | } | ||||
| execute (user: Creature, target: Creature): LogEntry { | execute (user: Creature, target: Creature): LogEntry { | ||||
| if (user.containedIn !== null) { | if (user.containedIn !== null) { | ||||
| if (this.test.test(user, target)) { | |||||
| return new LogLines(this.successLine(user, target, { container: this.container }), user.containedIn.release(user)) | |||||
| } else { | |||||
| return this.failLine(user, target, { container: this.container }) | |||||
| } | |||||
| return new LogLines(this.successLine(user, target, { container: this.container }), user.containedIn.release(user)) | |||||
| } else { | } else { | ||||
| return new LogLine("Vore's bugged!") | return new LogLine("Vore's bugged!") | ||||
| } | } | ||||
| } | } | ||||
| 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}. `, super.describe(user, target)) | |||||
| } | } | ||||
| protected successLine: PairLineArgs<Entity, { container: Container }> = (prey, pred, args) => new LogLine( | 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}.` | `${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 class DigestAction extends Action { | export class DigestAction extends Action { | ||||
| @@ -1,6 +1,6 @@ | |||||
| import { CombatTest, Stat, Vigor } from '../combat' | import { CombatTest, Stat, Vigor } from '../combat' | ||||
| import { Creature } from "../creature" | import { Creature } from "../creature" | ||||
| import { LogEntry, LogLines, PropElem, LogLine } from '../interface' | |||||
| import { LogEntry, LogLines, PropElem, LogLine, nilLog } from '../interface' | |||||
| function logistic (x0: number, L: number, k: number): (x: number) => number { | function logistic (x0: number, L: number, k: number): (x: number) => number { | ||||
| return (x: number) => { | return (x: number) => { | ||||
| @@ -11,6 +11,10 @@ function logistic (x0: number, L: number, k: number): (x: number) => number { | |||||
| // TODO this will need to be able to return a LogEntry at some point | // TODO this will need to be able to return a LogEntry at some point | ||||
| abstract class RandomTest implements CombatTest { | abstract class RandomTest implements CombatTest { | ||||
| constructor (public fail: (user: Creature, target: Creature) => LogEntry) { | |||||
| } | |||||
| test (user: Creature, target: Creature): boolean { | test (user: Creature, target: Creature): boolean { | ||||
| const userFail = user.effects.map(effect => effect.failTest(user, target)) | const userFail = user.effects.map(effect => effect.failTest(user, target)) | ||||
| if (userFail.some(result => result.failed)) { | if (userFail.some(result => result.failed)) { | ||||
| @@ -32,8 +36,8 @@ export class StatVigorSizeTest extends RandomTest { | |||||
| private f: (x: number) => number | private f: (x: number) => number | ||||
| private k = 0.1 | private k = 0.1 | ||||
| constructor (public readonly stat: Stat, private bias = 0) { | |||||
| super() | |||||
| constructor (public readonly stat: Stat, private bias = 0, fail: (user: Creature, target: Creature) => LogEntry) { | |||||
| super(fail) | |||||
| this.f = logistic(0, 1, this.k) | this.f = logistic(0, 1, this.k) | ||||
| } | } | ||||
| @@ -57,10 +61,9 @@ export class StatVigorSizeTest extends RandomTest { | |||||
| userPercent *= 4 | userPercent *= 4 | ||||
| } | } | ||||
| userPercent *= Math.sqrt(user.voreStats.Mass) | |||||
| targetPercent *= Math.sqrt(target.voreStats.Mass) | |||||
| const sizeOffset = Math.log2(user.voreStats.Mass / target.voreStats.Mass) | |||||
| return this.f(this.bias + user.stats[this.stat] * userPercent - target.stats[this.stat] * targetPercent) | |||||
| return this.f(this.bias + sizeOffset * 5 + user.stats[this.stat] * userPercent - target.stats[this.stat] * targetPercent) | |||||
| } | } | ||||
| explain (user: Creature, target: Creature): LogEntry { | explain (user: Creature, target: Creature): LogEntry { | ||||
| @@ -84,11 +87,12 @@ export class StatVigorSizeTest extends RandomTest { | |||||
| if (targetPercent === 0) { | if (targetPercent === 0) { | ||||
| userPercent *= 4 | userPercent *= 4 | ||||
| } | } | ||||
| userPercent *= Math.sqrt(user.voreStats.Mass) | |||||
| targetPercent *= Math.sqrt(target.voreStats.Mass) | |||||
| const sizeOffset = Math.log2(user.voreStats.Mass / target.voreStats.Mass) | |||||
| const userMod = user.stats[this.stat] * userPercent | const userMod = user.stats[this.stat] * userPercent | ||||
| const targetMod = target.stats[this.stat] * targetPercent | const targetMod = target.stats[this.stat] * targetPercent | ||||
| const delta = userMod - targetMod | |||||
| const delta = userMod - targetMod + sizeOffset * 5 | |||||
| if (delta === 0) { | if (delta === 0) { | ||||
| result = new LogLine('You and the target have the same effective', new PropElem(this.stat), '.') | result = new LogLine('You and the target have the same effective', new PropElem(this.stat), '.') | ||||
| @@ -108,8 +112,8 @@ export class StatVigorTest extends RandomTest { | |||||
| private f: (x: number) => number | private f: (x: number) => number | ||||
| private k = 0.1 | private k = 0.1 | ||||
| constructor (public readonly stat: Stat, private bias = 0) { | |||||
| super() | |||||
| constructor (public readonly stat: Stat, private bias = 0, fail: (user: Creature, target: Creature) => LogEntry) { | |||||
| super(fail) | |||||
| this.f = logistic(0, 1, this.k) | this.f = logistic(0, 1, this.k) | ||||
| } | } | ||||
| @@ -179,8 +183,8 @@ export class StatTest extends RandomTest { | |||||
| private f: (x: number) => number | private f: (x: number) => number | ||||
| private k = 0.1 | private k = 0.1 | ||||
| constructor (public readonly stat: Stat, private bias = 0) { | |||||
| super() | |||||
| constructor (public readonly stat: Stat, private bias = 0, fail: (user: Creature, target: Creature) => LogEntry) { | |||||
| super(fail) | |||||
| this.f = logistic(0, 1, this.k) | this.f = logistic(0, 1, this.k) | ||||
| } | } | ||||
| @@ -207,8 +211,8 @@ export class StatTest extends RandomTest { | |||||
| } | } | ||||
| export class ChanceTest extends RandomTest { | export class ChanceTest extends RandomTest { | ||||
| constructor (public readonly chance: number) { | |||||
| super() | |||||
| constructor (public readonly chance: number, fail: (user: Creature, target: Creature) => LogEntry) { | |||||
| super(fail) | |||||
| } | } | ||||
| odds (user: Creature, target: Creature): number { | odds (user: Creature, target: Creature): number { | ||||
| @@ -86,7 +86,7 @@ export class Creature extends Vore implements Combatant { | |||||
| if (blocking.length > 0) { | if (blocking.length > 0) { | ||||
| return new LogLines(...blocking.map(result => result.log)) | return new LogLines(...blocking.map(result => result.log)) | ||||
| } else { | } else { | ||||
| return action.execute(this, target) | |||||
| return action.try(this, target) | |||||
| } | } | ||||
| } | } | ||||
| @@ -61,12 +61,12 @@ export class Geta extends Creature { | |||||
| new ContainsCondition(cock) | new ContainsCondition(cock) | ||||
| ], | ], | ||||
| tests: [ | tests: [ | ||||
| { | |||||
| test: new ChanceTest(0.5), | |||||
| fail: (user, target) => new LogLine( | |||||
| `${user.name.capital.possessive} cock clenches hard around ${target.name.objective}, but ${target.pronouns.subjective} ${target.name.conjugate(new Verb("avoid"))} being crushed.` | |||||
| new ChanceTest( | |||||
| 0.5, | |||||
| (user, target) => new LogLine( | |||||
| `${user.name.capital.possessive} cock clenches hard around ${target.name.objective}, but ${target.pronouns.subjective} ${target.name.conjugate(new Verb("avoid"))} being crushed.` | |||||
| ) | ) | ||||
| } | |||||
| ) | |||||
| ], | ], | ||||
| consequences: [ | consequences: [ | ||||
| new LogConsequence( | new LogConsequence( | ||||
| @@ -4,7 +4,6 @@ import { VoreType, Stomach } from '../vore' | |||||
| import { Side, Damage, DamageType, Vigor, StatDamageFormula, Stat, VoreStat, DamageFormula } from '../combat' | import { Side, Damage, DamageType, Vigor, StatDamageFormula, Stat, VoreStat, DamageFormula } from '../combat' | ||||
| import { AttackAction, DevourAction } from '../combat/actions' | import { AttackAction, DevourAction } from '../combat/actions' | ||||
| import { LogEntry, LogLines } from '../interface' | import { LogEntry, LogLines } from '../interface' | ||||
| import { StatTest } from '../combat/tests' | |||||
| import { StunEffect, PredatorCounterEffect } from '../combat/effects' | import { StunEffect, PredatorCounterEffect } from '../combat/effects' | ||||
| class StompAttack extends AttackAction { | class StompAttack extends AttackAction { | ||||
| @@ -13,19 +12,14 @@ class StompAttack extends AttackAction { | |||||
| damage, | damage, | ||||
| verb | verb | ||||
| ) | ) | ||||
| this.test = new StatTest(Stat.Power) | |||||
| } | } | ||||
| execute (user: Creature, target: Creature): LogEntry { | execute (user: Creature, target: Creature): LogEntry { | ||||
| if (this.test.test(user, target)) { | |||||
| const damage = this.damage.calc(user, target) | |||||
| const targetResult = target.takeDamage(damage) | |||||
| const ownResult = this.successLine(user, target, { damage: damage }) | |||||
| const effResult = target.applyEffect(new StunEffect(3)) | |||||
| return new LogLines(ownResult, targetResult, effResult) | |||||
| } else { | |||||
| return this.failLine(user, target) | |||||
| } | |||||
| const damage = this.damage.calc(user, target) | |||||
| const targetResult = target.takeDamage(damage) | |||||
| const ownResult = this.successLine(user, target, { damage: damage }) | |||||
| const effResult = target.applyEffect(new StunEffect(3)) | |||||
| return new LogLines(ownResult, targetResult, effResult) | |||||
| } | } | ||||
| } | } | ||||
| export class Kenzie extends Creature { | export class Kenzie extends Creature { | ||||
| @@ -8,20 +8,18 @@ import { ContainsCondition, CapableCondition, EnemyCondition, TargetDrainedVigor | |||||
| import { StatTest } from '../combat/tests' | import { StatTest } from '../combat/tests' | ||||
| export class TrappedAction extends DamageAction { | export class TrappedAction extends DamageAction { | ||||
| protected test: StatTest | |||||
| constructor (name: TextLike, desc: TextLike, protected verb: Verb, protected damage: DamageFormula, container: Container, conditions: Condition[] = []) { | constructor (name: TextLike, desc: TextLike, protected verb: Verb, protected damage: DamageFormula, container: Container, conditions: Condition[] = []) { | ||||
| super( | super( | ||||
| name, | name, | ||||
| desc, | desc, | ||||
| damage, | damage, | ||||
| [], | |||||
| [new CapableCondition(), new ContainsCondition(container), new EnemyCondition()].concat(conditions) | [new CapableCondition(), new ContainsCondition(container), new EnemyCondition()].concat(conditions) | ||||
| ) | ) | ||||
| this.test = new StatTest(Stat.Power) | |||||
| } | } | ||||
| describe (user: Creature, target: Creature): LogEntry { | describe (user: Creature, target: Creature): LogEntry { | ||||
| return new LogLine(`Chew on ${target.name}. `, this.damage.describe(user, target), '. ', this.test.explain(user, target)) | |||||
| return new LogLine(`Chew on ${target.name}. `, this.damage.describe(user, target), '. ') | |||||
| } | } | ||||
| successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLine( | successLine: PairLineArgs<Creature, { damage: Damage }> = (user, target, args) => new LogLine( | ||||
| @@ -262,15 +262,12 @@ class StompAllyAction extends Action { | |||||
| } | } | ||||
| class DevourAllAction extends GroupAction { | class DevourAllAction extends GroupAction { | ||||
| private test: CombatTest | |||||
| constructor (private container: VoreContainer) { | constructor (private container: VoreContainer) { | ||||
| super('Devour All', 'GULP!', [ | super('Devour All', 'GULP!', [ | ||||
| new TogetherCondition(), | new TogetherCondition(), | ||||
| new EnemyCondition(), | new EnemyCondition(), | ||||
| new CapableCondition() | new CapableCondition() | ||||
| ]) | ]) | ||||
| this.test = new StatVigorTest(Stat.Power) | |||||
| } | } | ||||
| line = (user: Creature, target: Creature) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('scoop'))} ${target.name} up!`) | line = (user: Creature, target: Creature) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('scoop'))} ${target.name} up!`) | ||||
| @@ -287,7 +284,7 @@ class DevourAllAction extends GroupAction { | |||||
| } | } | ||||
| executeGroup (user: Creature, targets: Array<Creature>): LogEntry { | executeGroup (user: Creature, targets: Array<Creature>): LogEntry { | ||||
| return new LogLines(...targets.filter(target => this.test.test(user, target)).map(target => this.execute(user, target)).concat( | |||||
| return new LogLines(...targets.map(target => this.execute(user, target)).concat( | |||||
| [ | [ | ||||
| new Newline(), | new Newline(), | ||||
| this.groupLine(user, { count: targets.length }) | this.groupLine(user, { count: targets.length }) | ||||