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.
 
 
 
 
 

286 lines
7.5 KiB

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