import { TextLike, LiveText, DynText, Word, ImproperNoun, Verb, Noun } from './language' import { Actionable, Action, DamageFormula, ConstantDamageFormula, Damage, DamageType, Vigor, StatDamageFormula, Stat, Effective, CompositionAction, Condition, CompositeDamageFormula, Consequence, StatusEffect } from './combat' import { AttackAction } from './combat/actions' import { Resistances } from './entity' import { DamageTypeResistanceEffect, DigestionPowerEffect, SizeEffect, StatEffect } from './combat/effects' import { DamageConsequence, LogConsequence, HealingConsequence, StatusConsequence, ArbitraryConsequence } from './combat/consequences' import { SoloCondition } from './combat/conditions' import { LogLine, LogEntry } from './interface' import { Creature } from './creature' export enum Currency { Gold = "Gold" } export const CurrencyData: {[key in Currency]: { name: Noun }} = { [Currency.Gold]: { name: new ImproperNoun("gold piece", "gold pieces") } } export enum ItemKind { Key = "Key Item", Consumable = "Consumable", Equipment = "Equipment" } export const ItemKindIcons: {[key in ItemKind]: string} = { [ItemKind.Key]: "fas fa-key", [ItemKind.Consumable]: "fas fa-wine-bottle", [ItemKind.Equipment]: "fas fa-hammer" } export abstract class Item implements Actionable { actions: Array = [] effects: Array = [] consumed = false abstract kind: ItemKind constructor (public name: Word, public desc: TextLike) { } } export class KeyItem extends Item { kind = ItemKind.Key constructor (name: Word, desc: TextLike) { super(name, desc) } } export enum EquipmentSlot { Head = "Head", Chest = "Chest", Legs = "Legs", Arms = "Arms", MainHand = "MainHand", OffHand = "OffHand", Feet = "Feet" } export abstract class Equipment extends Item { kind = ItemKind.Equipment abstract slot: EquipmentSlot } export abstract class Weapon extends Equipment { actions: Array = [] slot = EquipmentSlot.MainHand constructor (name: Word, desc: TextLike, damageFormula: DamageFormula, verb: Verb) { super(name, desc) const attack = new AttackAction(damageFormula, verb) attack.desc = new DynText(`Attack with your `, this.name.all) this.actions.push(attack) } } export class Sword extends Weapon { constructor () { super( 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 } ]), new Verb('slash', 'slashes') ) } } export class Dagger extends Weapon { constructor () { super( new ImproperNoun('dagger', 'daggers'), 'A pointy dagger', new StatDamageFormula([ { fraction: 0.50, stat: Stat.Agility, target: Vigor.Health, type: DamageType.Pierce }, { fraction: 0.05, stat: Stat.Agility, target: Vigor.Health, type: DamageType.Slash } ]), new Verb('stab', 'stabs', 'stabbing', 'stabbed') ) } } export class Wand extends Weapon { constructor () { super( 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 } ]), new Verb('zap', 'zaps', 'zapping', 'zapped') ) } } export class Mace extends Weapon { constructor () { super( 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 } ]), new Verb('bash', 'bashes', 'bashing', 'bashed') ) } } export abstract class Armor extends Equipment { constructor (name: Word, desc: TextLike, public slot: EquipmentSlot, resistances: Partial) { super(name, desc) Object.entries(resistances).forEach(([damageType, value]) => { if (value !== undefined) { this.effects.push( new DamageTypeResistanceEffect( [damageType as DamageType], value ) ) } }) } } export class Helmet extends Armor { constructor () { super( new ImproperNoun('helmet'), 'A helmet', EquipmentSlot.Head, { Slash: 0.75, Pierce: 0.5, Crush: 0.9 } ) } } 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 abstract class Potion extends Consumable { constructor (name: ImproperNoun, desc: string, consequences: Array) { super( new ImproperNoun("health potion"), desc, new CompositionAction( "Drink " + name, desc, { conditions: [ new SoloCondition() ], consequences: ([ new LogConsequence( (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('drink'))} a ${name}.`) ) ] as Consequence[]).concat(consequences) } ) ) } } export class HealthPotion extends Potion { constructor () { super( new ImproperNoun("Health Potion"), "Heals your vigors", [ new HealingConsequence( new CompositeDamageFormula([ 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 } ) ), new StatDamageFormula([ { fraction: 2, stat: Stat.Toughness, target: Vigor.Health, type: DamageType.Heal }, { fraction: 2, stat: Stat.Agility, target: Vigor.Stamina, type: DamageType.Heal }, { fraction: 2, stat: Stat.Willpower, target: Vigor.Resolve, type: DamageType.Heal } ]) ]) ) ] ) } } export class StrengthPotion extends Potion { constructor () { super( new ImproperNoun("Strength Potion"), "Power up!", [ new StatusConsequence( (user, target) => new StatEffect(Stat.Power, 0, 1.5) ) ] ) } } export class AcidPotion extends Potion { constructor () { super( new ImproperNoun("Acid Potion"), "Boosts your digestive power", [ new StatusConsequence( (user, target) => new DigestionPowerEffect(2) ) ] ) } } export class ShrinkPotion extends Potion { constructor () { super( new ImproperNoun("Shrink Potion"), "Drink me!", [ new StatusConsequence( (user, target) => new SizeEffect(0.5) ) ] ) } }