| @@ -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'] | |||||
| } | } | ||||
| } | } | ||||
| @@ -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) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -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) | ||||
| @@ -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 { | ||||
| @@ -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) | ||||
| @@ -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 { | ||||