Feast 2.0!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

215 lines
6.1 KiB

  1. import { TextLike, LiveText, DynText, Word, ImproperNoun, Verb } from './language'
  2. import { Actionable, Action, DamageFormula, ConstantDamageFormula, Damage, DamageType, Vigor, StatDamageFormula, Stat, Effective, CompositionAction, Condition, CompositeDamageFormula } from './combat'
  3. import { AttackAction } from './combat/actions'
  4. import { Resistances } from './entity'
  5. import { DamageTypeResistanceEffect } from './combat/effects'
  6. import { DamageConsequence, LogConsequence, HealingConsequence } from './combat/consequences'
  7. import { SoloCondition } from './combat/conditions'
  8. import { LogLine, LogEntry } from './interface'
  9. import { Creature } from './creature'
  10. export enum ItemKind {
  11. Key = "Key Item",
  12. Consumable = "Consumable",
  13. Equipment = "Equipment"
  14. }
  15. export const ItemKindIcons: {[key in ItemKind]: string} = {
  16. [ItemKind.Key]: "fas fa-key",
  17. [ItemKind.Consumable]: "fas fa-wine-bottle",
  18. [ItemKind.Equipment]: "fas fa-hammer"
  19. }
  20. export abstract class Item implements Actionable {
  21. actions: Array<Action> = []
  22. effects: Array<Effective> = []
  23. consumed = false
  24. abstract kind: ItemKind
  25. constructor (public name: Word, public desc: TextLike) {
  26. }
  27. }
  28. export enum EquipmentSlot {
  29. Head = "Head",
  30. Chest = "Chest",
  31. Legs = "Legs",
  32. Arms = "Arms",
  33. MainHand = "MainHand",
  34. OffHand = "OffHand",
  35. Feet = "Feet"
  36. }
  37. export abstract class Equipment extends Item {
  38. kind = ItemKind.Equipment
  39. abstract slot: EquipmentSlot
  40. }
  41. export abstract class Weapon extends Equipment {
  42. actions: Array<Action> = []
  43. slot = EquipmentSlot.MainHand
  44. constructor (name: Word, desc: TextLike, damageFormula: DamageFormula, verb: Verb) {
  45. super(name, desc)
  46. const attack = new AttackAction(damageFormula, verb)
  47. attack.desc = new DynText(`Attack with your `, this.name.all)
  48. this.actions.push(attack)
  49. }
  50. }
  51. export class Sword extends Weapon {
  52. constructor () {
  53. super(
  54. new ImproperNoun('sword', 'swords'),
  55. 'An arming sword',
  56. new StatDamageFormula([
  57. { fraction: 0.35, stat: Stat.Power, target: Vigor.Health, type: DamageType.Slash },
  58. { fraction: 0.25, stat: Stat.Power, target: Vigor.Health, type: DamageType.Pierce }
  59. ]),
  60. new Verb('slash', 'slashes')
  61. )
  62. }
  63. }
  64. export class Dagger extends Weapon {
  65. constructor () {
  66. super(
  67. new ImproperNoun('dagger', 'daggers'),
  68. 'A pointy dagger',
  69. new StatDamageFormula([
  70. { fraction: 0.50, stat: Stat.Speed, target: Vigor.Health, type: DamageType.Pierce },
  71. { fraction: 0.05, stat: Stat.Speed, target: Vigor.Health, type: DamageType.Slash }
  72. ]),
  73. new Verb('stab', 'stabs', 'stabbing', 'stabbed')
  74. )
  75. }
  76. }
  77. export class Wand extends Weapon {
  78. constructor () {
  79. super(
  80. new ImproperNoun('wand', 'wands'),
  81. 'A magical wand',
  82. new StatDamageFormula([
  83. { fraction: 0.25, stat: Stat.Charm, target: Vigor.Health, type: DamageType.Crush },
  84. { fraction: 0.25, stat: Stat.Willpower, target: Vigor.Health, type: DamageType.Crush }
  85. ]),
  86. new Verb('zap', 'zaps', 'zapping', 'zapped')
  87. )
  88. }
  89. }
  90. export class Mace extends Weapon {
  91. constructor () {
  92. super(
  93. new ImproperNoun('mace', 'maces'),
  94. 'A heavy mace',
  95. new StatDamageFormula([
  96. { fraction: 0.4, stat: Stat.Power, target: Vigor.Health, type: DamageType.Crush },
  97. { fraction: 0.2, stat: Stat.Power, target: Vigor.Health, type: DamageType.Pierce }
  98. ]),
  99. new Verb('bash', 'bashes', 'bashing', 'bashed')
  100. )
  101. }
  102. }
  103. export abstract class Armor extends Equipment {
  104. constructor (name: Word, desc: TextLike, public slot: EquipmentSlot, resistances: Partial<Resistances>) {
  105. super(name, desc)
  106. Object.entries(resistances).forEach(([damageType, value]) => {
  107. if (value !== undefined) {
  108. this.effects.push(
  109. new DamageTypeResistanceEffect(
  110. [damageType as DamageType],
  111. value
  112. )
  113. )
  114. }
  115. })
  116. }
  117. }
  118. export class Helmet extends Armor {
  119. constructor () {
  120. super(
  121. new ImproperNoun('helmet'),
  122. 'A helmet',
  123. EquipmentSlot.Head,
  124. {
  125. Slash: 0.75,
  126. Pierce: 0.5,
  127. Crush: 0.9
  128. }
  129. )
  130. }
  131. }
  132. export class ItemAction extends Action {
  133. constructor (name: TextLike, desc: TextLike, private item: Item, private action: Action) {
  134. super(name, desc, action.conditions)
  135. }
  136. execute (user: Creature, target: Creature): LogEntry {
  137. this.item.consumed = true
  138. return this.action.execute(user, target)
  139. }
  140. describe (user: Creature, target: Creature): LogEntry {
  141. return this.action.describe(user, target)
  142. }
  143. }
  144. export class Consumable extends Item {
  145. kind = ItemKind.Consumable
  146. constructor (name: Word, desc: TextLike, onUse: Action) {
  147. super(name, desc)
  148. this.actions.push(new ItemAction(
  149. onUse.name,
  150. onUse.desc,
  151. this,
  152. onUse
  153. ))
  154. }
  155. }
  156. export class HealthPotion extends Consumable {
  157. constructor () {
  158. super(
  159. new ImproperNoun("health potion"),
  160. "Restores all of your vigors",
  161. new CompositionAction(
  162. "Drink Potion",
  163. "Heals your vigors",
  164. {
  165. conditions: [
  166. new SoloCondition()
  167. ],
  168. consequences: [
  169. new LogConsequence(
  170. (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('drink'))} a potion.`)
  171. ),
  172. new HealingConsequence(
  173. new CompositeDamageFormula([
  174. new ConstantDamageFormula(
  175. new Damage(
  176. { amount: 100, target: Vigor.Health, type: DamageType.Heal },
  177. { amount: 100, target: Vigor.Stamina, type: DamageType.Heal },
  178. { amount: 100, target: Vigor.Resolve, type: DamageType.Heal }
  179. )
  180. ),
  181. new StatDamageFormula([
  182. { fraction: 2, stat: Stat.Toughness, target: Vigor.Health, type: DamageType.Heal },
  183. { fraction: 2, stat: Stat.Speed, target: Vigor.Stamina, type: DamageType.Heal },
  184. { fraction: 2, stat: Stat.Willpower, target: Vigor.Resolve, type: DamageType.Heal }
  185. ])
  186. ])
  187. )
  188. ]
  189. }
  190. )
  191. )
  192. }
  193. }