diff --git a/src/App.vue b/src/App.vue index 1e27cec..e37ccf1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -52,10 +52,19 @@ export default class App extends Vue { Charm: 60 } }) + const cleric = new Creatures.Human(new ProperNoun('Cleric'), FemalePronouns, { + stats: { + Toughness: 35, + Power: 40, + Speed: 25, + Willpower: 90, + Charm: 50 + } + }) this.left = fighter this.right = new Creatures.Withers() - this.combatants = [this.left, this.right, wizard, rogue] + this.combatants = [this.left, this.right, wizard, rogue, cleric] console.log(this.left) console.log(this.right) } diff --git a/src/game/creatures/human.ts b/src/game/creatures/human.ts index 0b64ae2..c99f749 100644 --- a/src/game/creatures/human.ts +++ b/src/game/creatures/human.ts @@ -1,22 +1,25 @@ -import { Creature, POV, Entity } from '../entity' -import { Stat, Damage, DamageType, ConstantDamageFormula, Vigor, Stats } from '../combat' -import { MalePronouns, ImproperNoun, POVPair, POVPairArgs, Noun, Pronoun } from '../language' -import { LogLine, LogLines } from '../interface' -import { VoreType, Stomach, Bowels } from '../vore' -import { StatTest } from '../combat/tests' -import { AttackAction, TransferAction, FeedAction } from '../combat/actions' +import { Creature } from '../entity' +import { Damage, DamageType, ConstantDamageFormula, Vigor, Stats, Vigors } from '../combat' +import { MalePronouns, Noun, Pronoun } from '../language' +import { VoreType } from '../vore' +import { AttackAction } from '../combat/actions' export class Human extends Creature { constructor (name: Noun, pronouns: Pronoun, options: { + vigors?: Vigor; stats?: Stats; } = {}) { - let stats + let vigors: Vigors + let stats: Stats + if (options.vigors === undefined) { + vigors = { Health: 100, Stamina: 100, Resolve: 100 } + } if (options.stats === undefined) { stats = { Toughness: 20, Power: 20, Speed: 20, Willpower: 20, Charm: 20 } } else { stats = options.stats } - super(name, MalePronouns, stats, new Set([VoreType.Oral, VoreType.Anal]), new Set([VoreType.Oral, VoreType.Anal]), 25) + super(name, pronouns, stats, new Set([VoreType.Oral, VoreType.Anal]), new Set([VoreType.Oral, VoreType.Anal]), 25) this.actions.push(new AttackAction(new ConstantDamageFormula( new Damage( { amount: 20, target: Vigor.Health, type: DamageType.Slash } diff --git a/src/game/creatures/withers.ts b/src/game/creatures/withers.ts index 887ed39..a2fbf02 100644 --- a/src/game/creatures/withers.ts +++ b/src/game/creatures/withers.ts @@ -1,6 +1,6 @@ import { Creature, POV, Entity } from '../entity' import { Stat, Damage, DamageType, ConstantDamageFormula, Vigor, Side, PairAction, CombatTest, GroupAction } from '../combat' -import { MalePronouns, ImproperNoun, POVPair, POVPairArgs, ProperNoun, TheyPronouns, FemalePronouns } from '../language' +import { MalePronouns, ImproperNoun, POVPair, POVPairArgs, ProperNoun, TheyPronouns, FemalePronouns, RandomWord, Adjective } from '../language' import { LogLine, LogLines, LogEntry } from '../interface' import { VoreType, Stomach, Bowels, Container } from '../vore' import { StatTest } from '../combat/tests' @@ -8,6 +8,15 @@ import { AttackAction, TransferAction, FeedAction } from '../combat/actions' import { TogetherCondition } from '../combat/conditions' import { InstantKill } from '../combat/effects' +const huge = new RandomWord([ + new Adjective('massive'), + new Adjective('colossal'), + new Adjective('big ol\''), + new Adjective('heavy'), + new Adjective('crushing'), + new Adjective('huge') +]) + class BiteAction extends AttackAction { constructor () { super(new ConstantDamageFormula(new Damage({ amount: 50, type: DamageType.Slash, target: Vigor.Health }))) @@ -18,8 +27,8 @@ class BiteAction extends AttackAction { class StompAction extends GroupAction { lines: POVPair = new POVPair([ [[POV.First, POV.Third], (user: Creature, target: Creature) => new LogLine(`You flatten ${target.name} under your foot!`)], - [[POV.Third, POV.First], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens you under ${user.pronouns.possessive} foot!`)], - [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens ${target.name} under ${user.pronouns.possessive} foot!`)] + [[POV.Third, POV.First], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens you under ${user.pronouns.possessive} ${huge} foot!`)], + [[POV.Third, POV.Third], (user: Creature, target: Creature) => new LogLine(`${user.name.capital} flattens ${target.name} under ${user.pronouns.possessive} ${huge} foot!`)] ]) execute (user: Creature, target: Creature): LogEntry { diff --git a/src/game/language.ts b/src/game/language.ts index 969ec78..9a2619c 100644 --- a/src/game/language.ts +++ b/src/game/language.ts @@ -73,6 +73,15 @@ interface WordOptions { count: boolean; } +const emptyConfig: WordOptions = { + capital: false, + count: false, + kind: NounKind.Specific, + plural: false, + proper: false, + vowel: VowelSound.Default +} + export type TextLike = { toString: () => string } // updates as needed @@ -96,61 +105,98 @@ export class DynText { return (this.parts.map(part => part.toString())).join('') } } -export class Noun implements Pluralizable { - constructor (private singularNoun: string, private pluralNoun: string|null = null, private options: WordOptions = { plural: false, capital: false, proper: false, kind: NounKind.Specific, vowel: VowelSound.Default, count: true }) { + +export abstract class Word { + constructor (public opt: WordOptions = emptyConfig) { } - get capital (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + abstract configure (opts: WordOptions): Word; + abstract toString (): string; + + // These functions are pure; they don't mutate the original object. + // This is necessary to avoid causing chaos. + + get capital (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.capital = true - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) } - get plural (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + get plural (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.plural = true - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) } - get proper (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + get proper (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.proper = true - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) } - get improper (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + get improper (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.proper = false - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) } - get specific (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + get specific (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.kind = NounKind.Specific - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) } - get nonspecific (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + get nonspecific (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.kind = NounKind.Nonspecific - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) } - get all (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + get all (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.kind = NounKind.All - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) } - get uncountable (): Noun { - const opts: WordOptions = Object.assign({}, this.options) + get uncountable (): Word { + const opts: WordOptions = Object.assign({}, this.opt) opts.count = false - return new Noun(this.singularNoun, this.pluralNoun, opts) + return this.configure(opts) + } +} + +export class RandomWord extends Word { + private last: number + + constructor (public choices: Array, opt: WordOptions = emptyConfig) { + super(opt) + this.last = -1 + } + + configure (opts: WordOptions): Word { + return new RandomWord(this.choices, opts) + } + + toString (): string { + let choice + + do { + choice = Math.floor(Math.random() * this.choices.length) + } while (choice === this.last) + + this.last = choice + return this.choices[choice].configure(this.opt).toString() + } +} + +export class Noun extends Word { + constructor (private singularNoun: string, private pluralNoun: string|null = null, private options: WordOptions = emptyConfig) { + super(options) } - get isPlural (): boolean { - return this.options.plural + configure (opts: WordOptions): Word { + return new Noun(this.singularNoun, this.pluralNoun, opts) } toString (): string { @@ -208,6 +254,20 @@ export class ProperNoun extends Noun { } } +export class Adjective extends Word { + constructor (private adjective: string, opt: WordOptions = emptyConfig) { + super(opt) + } + + configure (opts: WordOptions): Word { + return new Adjective(this.adjective, opts) + } + + toString (): string { + return this.adjective + } +} + interface PronounDict { subjective: string; objective: string;