diff --git a/src/App.vue b/src/App.vue index 9168128..09c51d3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -10,6 +10,7 @@ import { Component, Vue, Prop } from 'vue-property-decorator' import Combat from './components/Combat.vue' import Header from './components/Header.vue' import * as Creatures from '@/game/creatures' +import * as Items from '@/game/items' import { Creature, POV } from '@/game/entity' import { ProperNoun, TheyPronouns, FemalePronouns, MalePronouns, ImproperNoun } from '@/game/language' @@ -35,6 +36,7 @@ export default class App extends Vue { } }) fighter.title = "Lv. 6 Fighter" + fighter.items.push(Items.Sword) const rogue = new Creatures.Human(new ProperNoun('Lidda'), FemalePronouns, { stats: { Toughness: 25, @@ -45,6 +47,7 @@ export default class App extends Vue { } }) rogue.title = "Lv. 5 Rogue" + rogue.items.push(Items.Dagger) const wizard = new Creatures.Human(new ProperNoun('Mialee'), FemalePronouns, { stats: { Toughness: 30, @@ -55,6 +58,7 @@ export default class App extends Vue { } }) wizard.title = "Lv. 6 Wizard" + wizard.items.push(Items.Wand) const cleric = new Creatures.Human(new ProperNoun('Jozan'), MalePronouns, { stats: { Toughness: 35, @@ -64,7 +68,8 @@ export default class App extends Vue { Charm: 50 } }) - cleric.title = "Lv. 5 Wizard" + cleric.title = "Lv. 5 Cleric" + cleric.items.push(Items.Mace) this.left = fighter this.right = new Creatures.Withers() diff --git a/src/game/combat.ts b/src/game/combat.ts index a969573..a7a4e63 100644 --- a/src/game/combat.ts +++ b/src/game/combat.ts @@ -121,6 +121,11 @@ export class Damage { return new Damage(...results) } + // TODO make this combine damage instances when appropriate + combine (other: Damage): Damage { + return new Damage(...this.damages.concat(other.damages)) + } + toString (): string { return this.damages.map(damage => damage.amount + " " + damage.type).join("/") } @@ -206,6 +211,44 @@ export class UniformRandomDamageFormula implements DamageFormula { } } +export class StatDamageFormula implements DamageFormula { + calc (user: Creature, target: Creature): Damage { + const instances: Array = this.factors.map(factor => ( + { + amount: factor.fraction * user.stats[factor.stat], + target: factor.target, + type: factor.type + } + )) + + return new Damage(...instances) + } + + describe (user: Creature, target: Creature): LogEntry { + return new LogLine( + this.explain(user), + `, for a total of `, + this.calc(user, target).renderShort() + ) + } + + explain (user: Creature): LogEntry { + return new LogLine( + `Deal `, + ...this.factors.map(factor => new LogLine( + `${factor.fraction * 100}% of your `, + new PropElem(factor.stat), + ` as `, + new PropElem(factor.target) + )).joinGeneral(new LogLine(`, `), new LogLine(` and `)) + ) + } + + constructor (private factors: Array<{ stat: Stat; fraction: number; type: DamageType; target: Vigor|Stat }>) { + + } +} + export enum Side { Heroes, Monsters diff --git a/src/game/entity.ts b/src/game/entity.ts index 5c66751..cc4db55 100644 --- a/src/game/entity.ts +++ b/src/game/entity.ts @@ -2,6 +2,7 @@ import { DamageType, Damage, Combatant, Stats, Action, Vigor, VoreStats, VoreSta import { Noun, Pronoun, Adjective, ImproperNoun, TextLike } from './language' import { LogEntry, LogLine } from './interface' import { Vore, VoreContainer, VoreType, Container } from './vore' +import { Item } from './items' export enum POV {First, Third} @@ -57,6 +58,8 @@ export class Creature extends Vore implements Combatant { groupActions: Array = [] otherActions: Array = [] + items: Array = [] + 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) } @@ -156,7 +159,9 @@ export class Creature extends Vore implements Combatant { let choices = this.actions.concat( this.containers.flatMap(container => container.actions)).concat( target.otherActions.concat( - this.otherContainers.flatMap(container => container.actions) + this.otherContainers.flatMap(container => container.actions).concat( + this.items.flatMap(item => item.actions) + ) ) ) diff --git a/src/game/items.ts b/src/game/items.ts new file mode 100644 index 0000000..a3ac3c3 --- /dev/null +++ b/src/game/items.ts @@ -0,0 +1,54 @@ +import { TextLike, LiveText, DynText, Word, ImproperNoun } from './language' +import { Actionable, Action, DamageFormula, ConstantDamageFormula, Damage, DamageType, Vigor, StatDamageFormula, Stat } from './combat' +import { AttackAction } from './combat/actions' + +export interface Item extends Actionable { + name: Word; + desc: TextLike; +} + +export class Weapon implements Actionable { + actions: Array = [] + + constructor (public name: Word, public desc: TextLike, damageFormula: DamageFormula) { + const attack = new AttackAction(damageFormula) + attack.desc = new DynText(`Attack with your `, this.name.all) + this.actions.push(attack) + } +} + +export const Sword = new Weapon( + new ImproperNoun('sword', 'swords'), + 'An arming sword', + new StatDamageFormula([ + { fraction: 0.35, stat: Stat.Power, target: Vigor.Health, type: DamageType.Slash }, + { fraction: 0.25, stat: Stat.Power, target: Vigor.Health, type: DamageType.Pierce } + ]) +) + +export const Dagger = new Weapon( + new ImproperNoun('dagger', 'daggers'), + 'A pointy dagger', + new StatDamageFormula([ + { fraction: 0.50, stat: Stat.Speed, target: Vigor.Health, type: DamageType.Pierce }, + { fraction: 0.05, stat: Stat.Speed, target: Vigor.Health, type: DamageType.Slash } + ]) +) + +export const Wand = new Weapon( + new ImproperNoun('wand', 'wands'), + 'A magical wand', + new StatDamageFormula([ + { fraction: 0.25, stat: Stat.Charm, target: Vigor.Health, type: DamageType.Crush }, + { fraction: 0.25, stat: Stat.Willpower, target: Vigor.Health, type: DamageType.Crush } + ]) +) + +export const Mace = new Weapon( + new ImproperNoun('mace', 'maces'), + 'A heavy mace', + new StatDamageFormula([ + { fraction: 0.4, stat: Stat.Power, target: Vigor.Health, type: DamageType.Crush }, + { fraction: 0.2, stat: Stat.Power, target: Vigor.Health, type: DamageType.Pierce } + ]) +) diff --git a/src/main.ts b/src/main.ts index fca74cf..170e710 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,21 @@ import Vue from 'vue' import App from './App.vue' +declare global { + interface Array { + joinGeneral (item: T, endItem: T|null): Array; + } +} + +/* eslint-disable-next-line */ +Array.prototype.joinGeneral = function (item, endItem = null) { + if (endItem === null) { + return this.slice(0, -1).flatMap(x => [x, item]).concat(this.slice(-1)) + } else { + return this.slice(0, -2).flatMap(x => [x, item]).concat(this.slice(-2, -1).flatMap(x => [x, endItem])).concat(this.slice(-1)) + } +} + Vue.config.productionTip = false new Vue({