From 2cd335cf960df9aa024ad495d238f8c35e8c2715 Mon Sep 17 00:00:00 2001 From: Fen Dweller Date: Fri, 7 Aug 2020 17:03:19 -0400 Subject: [PATCH] Add health potions --- src/App.vue | 1 + src/components/Combat.vue | 1 - src/components/Statblock.vue | 1 - src/game/combat.ts | 3 +- src/game/combat/consequences.ts | 17 +++++++++ src/game/creature.ts | 5 ++- src/game/items.ts | 68 ++++++++++++++++++++++++++++++++- 7 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/App.vue b/src/App.vue index c6c3c4a..ae028e2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -69,6 +69,7 @@ export default class App extends Vue { player.side = Side.Heroes player.equipment.set(Items.EquipmentSlot.MainHand, new Items.Sword()) player.equipment.set(Items.EquipmentSlot.Head, new Items.Helmet()) + player.items.push(new Items.HealthPotion()) player.items.push(new Items.Mace()) player.items.push(new Items.Dagger()) this.$data.world = new World(player) diff --git a/src/components/Combat.vue b/src/components/Combat.vue index 2a4f57d..1deadd0 100644 --- a/src/components/Combat.vue +++ b/src/components/Combat.vue @@ -166,7 +166,6 @@ export default class Combat extends Vue { pickNext () { // Did one side win? - console.log(this.encounter.winner, this.encounter.totalWinner) if (this.encounter.totalWinner !== null && !this.$data.totalWon) { this.$data.totalWon = true diff --git a/src/components/Statblock.vue b/src/components/Statblock.vue index 891ca45..9b0eaf4 100644 --- a/src/components/Statblock.vue +++ b/src/components/Statblock.vue @@ -158,7 +158,6 @@ export default class Statblock extends Vue { this.statusChanged([]) const picker = this.$el.querySelector(".ai-picker") as HTMLSelectElement - console.log(this.$data.ais.indexOf(this.subject.ai)) picker.selectedIndex = this.$data.ais.findIndex((ai: AI) => ai.name === this.subject.ai.name) } } diff --git a/src/game/combat.ts b/src/game/combat.ts index 77dafde..91e123a 100644 --- a/src/game/combat.ts +++ b/src/game/combat.ts @@ -347,7 +347,7 @@ export interface Combatant { * An Action is anything that can be done by a [[Creature]] to a [[Creature]]. */ export abstract class Action { - constructor (public name: TextLike, public desc: TextLike, private conditions: Array = []) { + constructor (public name: TextLike, public desc: TextLike, public conditions: Array = []) { } @@ -590,7 +590,6 @@ export class Encounter { if (effectResults.some(result => result.prevented)) { const parts = effectResults.map(result => result.log).concat([this.nextMove()]) - console.log(parts) return new LogLines( ...parts ) diff --git a/src/game/combat/consequences.ts b/src/game/combat/consequences.ts index 168e333..145c632 100644 --- a/src/game/combat/consequences.ts +++ b/src/game/combat/consequences.ts @@ -42,6 +42,23 @@ export class DamageConsequence extends Consequence { } } +/** + * Same as [[DamageConsequence]], but it has healing text + */ +export class HealingConsequence extends Consequence { + constructor (private damageFormula: DamageFormula, conditions: Condition[] = []) { + super(conditions) + } + + apply (user: Creature, target: Creature): LogEntry { + const damage = this.damageFormula.calc(user, target) + return new LogLines( + new LogLine(`${target.name.capital} ${target.name.conjugate(new Verb('heal'))} `, damage.renderShort(), `!`), + target.takeDamage(damage) + ) + } +} + /** * Applies a status effect */ diff --git a/src/game/creature.ts b/src/game/creature.ts index fbccea3..20f1250 100644 --- a/src/game/creature.ts +++ b/src/game/creature.ts @@ -2,7 +2,7 @@ import { Damage, Combatant, Stats, Action, Vigor, Side, GroupAction, VisibleStat import { Noun, Pronoun } from './language' import { LogEntry, LogLines } from './interface' import { Vore, VoreContainer, VoreType } from './vore' -import { Item, EquipmentSlot, Equipment } from './items' +import { Item, EquipmentSlot, Equipment, ItemKind } from './items' import { PassAction } from './combat/actions' import { AI, NoAI } from './ai' @@ -102,7 +102,8 @@ export class Creature extends Vore implements Combatant { this.containers.flatMap(container => container.actions), target.otherActions, this.otherContainers.flatMap(container => container.actions), - Array.from(this.equipment.values()).flatMap(item => item.actions) + Array.from(this.equipment.values()).flatMap(item => item.actions), + this.items.filter(item => item.kind === ItemKind.Consumable && !item.consumed).flatMap(item => item.actions) ) if (this.containedIn !== null) { diff --git a/src/game/items.ts b/src/game/items.ts index ee35850..9ba3dfe 100644 --- a/src/game/items.ts +++ b/src/game/items.ts @@ -1,8 +1,12 @@ import { TextLike, LiveText, DynText, Word, ImproperNoun, Verb } from './language' -import { Actionable, Action, DamageFormula, ConstantDamageFormula, Damage, DamageType, Vigor, StatDamageFormula, Stat, Effective } from './combat' +import { Actionable, Action, DamageFormula, ConstantDamageFormula, Damage, DamageType, Vigor, StatDamageFormula, Stat, Effective, CompositionAction, Condition } from './combat' import { AttackAction } from './combat/actions' import { Resistances } from './entity' import { DamageTypeResistanceEffect } from './combat/effects' +import { DamageConsequence, LogConsequence, HealingConsequence } from './combat/consequences' +import { SoloCondition } from './combat/conditions' +import { LogLine, LogEntry } from './interface' +import { Creature } from './creature' export enum ItemKind { Key = "Key Item", @@ -19,6 +23,7 @@ export const ItemKindIcons: {[key in ItemKind]: string} = { export abstract class Item implements Actionable { actions: Array = [] effects: Array = [] + consumed = false abstract kind: ItemKind constructor (public name: Word, public desc: TextLike) { @@ -139,3 +144,64 @@ export class Helmet extends Armor { ) } } + +export class ItemAction extends Action { + constructor (name: TextLike, desc: TextLike, private item: Item, private action: Action) { + super(name, desc, action.conditions) + } + + execute (user: Creature, target: Creature): LogEntry { + this.item.consumed = true + return this.action.execute(user, target) + } + + describe (user: Creature, target: Creature): LogEntry { + return this.action.describe(user, target) + } +} + +export class Consumable extends Item { + kind = ItemKind.Consumable + + constructor (name: Word, desc: TextLike, onUse: Action) { + super(name, desc) + this.actions.push(new ItemAction( + onUse.name, + onUse.desc, + this, + onUse + )) + } +} + +export class HealthPotion extends Consumable { + constructor () { + super( + new ImproperNoun("health potion"), + "Restores all of your vigors", + new CompositionAction( + "Drink Potion", + "Heals your vigors", + { + conditions: [ + new SoloCondition() + ], + consequences: [ + new LogConsequence( + (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('drink'))} a potion.`) + ), + new HealingConsequence( + new ConstantDamageFormula( + new Damage( + { amount: 100, target: Vigor.Health, type: DamageType.Heal }, + { amount: 100, target: Vigor.Stamina, type: DamageType.Heal }, + { amount: 100, target: Vigor.Resolve, type: DamageType.Heal } + ) + ) + ) + ] + } + ) + ) + } +}