| @@ -69,6 +69,7 @@ export default class App extends Vue { | |||||
| player.side = Side.Heroes | player.side = Side.Heroes | ||||
| player.equipment.set(Items.EquipmentSlot.MainHand, new Items.Sword()) | player.equipment.set(Items.EquipmentSlot.MainHand, new Items.Sword()) | ||||
| player.equipment.set(Items.EquipmentSlot.Head, new Items.Helmet()) | 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.Mace()) | ||||
| player.items.push(new Items.Dagger()) | player.items.push(new Items.Dagger()) | ||||
| this.$data.world = new World(player) | this.$data.world = new World(player) | ||||
| @@ -166,7 +166,6 @@ export default class Combat extends Vue { | |||||
| pickNext () { | pickNext () { | ||||
| // Did one side win? | // Did one side win? | ||||
| console.log(this.encounter.winner, this.encounter.totalWinner) | |||||
| if (this.encounter.totalWinner !== null && !this.$data.totalWon) { | if (this.encounter.totalWinner !== null && !this.$data.totalWon) { | ||||
| this.$data.totalWon = true | this.$data.totalWon = true | ||||
| @@ -158,7 +158,6 @@ export default class Statblock extends Vue { | |||||
| this.statusChanged([]) | this.statusChanged([]) | ||||
| const picker = this.$el.querySelector(".ai-picker") as HTMLSelectElement | 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) | picker.selectedIndex = this.$data.ais.findIndex((ai: AI) => ai.name === this.subject.ai.name) | ||||
| } | } | ||||
| } | } | ||||
| @@ -347,7 +347,7 @@ 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, private conditions: Array<Condition> = []) { | |||||
| constructor (public name: TextLike, public desc: TextLike, public conditions: Array<Condition> = []) { | |||||
| } | } | ||||
| @@ -590,7 +590,6 @@ export class Encounter { | |||||
| if (effectResults.some(result => result.prevented)) { | if (effectResults.some(result => result.prevented)) { | ||||
| const parts = effectResults.map(result => result.log).concat([this.nextMove()]) | const parts = effectResults.map(result => result.log).concat([this.nextMove()]) | ||||
| console.log(parts) | |||||
| return new LogLines( | return new LogLines( | ||||
| ...parts | ...parts | ||||
| ) | ) | ||||
| @@ -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 | * Applies a status effect | ||||
| */ | */ | ||||
| @@ -2,7 +2,7 @@ import { Damage, Combatant, Stats, Action, Vigor, Side, GroupAction, VisibleStat | |||||
| import { Noun, Pronoun } from './language' | import { Noun, Pronoun } from './language' | ||||
| import { LogEntry, LogLines } from './interface' | import { LogEntry, LogLines } from './interface' | ||||
| import { Vore, VoreContainer, VoreType } from './vore' | 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 { PassAction } from './combat/actions' | ||||
| import { AI, NoAI } from './ai' | import { AI, NoAI } from './ai' | ||||
| @@ -102,7 +102,8 @@ export class Creature extends Vore implements Combatant { | |||||
| this.containers.flatMap(container => container.actions), | this.containers.flatMap(container => container.actions), | ||||
| target.otherActions, | target.otherActions, | ||||
| this.otherContainers.flatMap(container => container.actions), | 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) { | if (this.containedIn !== null) { | ||||
| @@ -1,8 +1,12 @@ | |||||
| import { TextLike, LiveText, DynText, Word, ImproperNoun, Verb } from './language' | 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 { AttackAction } from './combat/actions' | ||||
| import { Resistances } from './entity' | import { Resistances } from './entity' | ||||
| import { DamageTypeResistanceEffect } from './combat/effects' | 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 { | export enum ItemKind { | ||||
| Key = "Key Item", | Key = "Key Item", | ||||
| @@ -19,6 +23,7 @@ export const ItemKindIcons: {[key in ItemKind]: string} = { | |||||
| export abstract class Item implements Actionable { | export abstract class Item implements Actionable { | ||||
| actions: Array<Action> = [] | actions: Array<Action> = [] | ||||
| effects: Array<Effective> = [] | effects: Array<Effective> = [] | ||||
| consumed = false | |||||
| abstract kind: ItemKind | abstract kind: ItemKind | ||||
| constructor (public name: Word, public desc: TextLike) { | 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 } | |||||
| ) | |||||
| ) | |||||
| ) | |||||
| ] | |||||
| } | |||||
| ) | |||||
| ) | |||||
| } | |||||
| } | |||||