Feast 2.0!
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

125 lines
3.7 KiB

  1. import { DamageType, Damage, Stats, Vigor, VoreStats, VoreStat, Stat, Vigors, DamageInstance } from './combat'
  2. import { Noun, Pronoun, TextLike, POV, PronounAsNoun, FirstPersonPronouns, SecondPersonPronouns } from './language'
  3. import { LogEntry, LogLine } from './interface'
  4. import { Place, Nowhere } from './world'
  5. export abstract class Entity {
  6. get name (): Noun {
  7. if (this.perspective === POV.First) {
  8. return new PronounAsNoun(FirstPersonPronouns)
  9. } else if (this.perspective === POV.Second) {
  10. return new PronounAsNoun(SecondPersonPronouns)
  11. } else {
  12. return this.baseName
  13. }
  14. }
  15. get pronouns (): Pronoun {
  16. if (this.perspective === POV.First) {
  17. return FirstPersonPronouns
  18. } else if (this.perspective === POV.Second) {
  19. return SecondPersonPronouns
  20. } else {
  21. return this.basePronouns
  22. }
  23. }
  24. desc: TextLike = "It's a ting."
  25. perspective: POV = POV.Third
  26. title: TextLike = "Some thing."
  27. location: Place
  28. constructor (public baseName: Noun, public kind: Noun, public basePronouns: Pronoun) {
  29. this.location = Nowhere
  30. }
  31. }
  32. export type Resistances = {[key in DamageType]: number}
  33. export abstract class Mortal extends Entity {
  34. baseResistances: Resistances
  35. stats: Stats;
  36. vigors: {[key in Vigor]: number} = {
  37. [Vigor.Health]: 100,
  38. [Vigor.Stamina]: 100,
  39. [Vigor.Resolve]: 100
  40. }
  41. constructor (name: Noun, kind: Noun, pronouns: Pronoun, public baseStats: Stats) {
  42. super(name, kind, pronouns)
  43. this.stats = Object.keys(Stat).reduce((base: any, key) => { base[key] = baseStats[key as Stat]; return base }, {})
  44. this.baseResistances = Object.keys(DamageType).reduce((resist: any, key) => { resist[key] = 1; return resist }, {})
  45. Object.entries(this.maxVigors).forEach(([key, val]) => {
  46. this.vigors[key as Vigor] = val
  47. })
  48. }
  49. resistanceTo (damageType: DamageType): number {
  50. return this.baseResistances[damageType]
  51. }
  52. get maxVigors (): Readonly<Vigors> {
  53. return {
  54. Health: this.stats.Toughness * 10 + this.stats.Power * 5,
  55. Resolve: this.stats.Willpower * 10 + this.stats.Charm * 5,
  56. Stamina: this.stats.Speed * 10 + this.stats.Power * 2.5 + this.stats.Charm * 2.5
  57. }
  58. }
  59. get disabled (): boolean {
  60. return Object.values(this.vigors).some(val => val <= 0)
  61. }
  62. effectiveDamage (damage: Damage): Damage {
  63. const newDamages: DamageInstance[] = []
  64. damage.damages.forEach(instance => {
  65. const factor = instance.type === DamageType.Heal ? -1 : 1
  66. const baseResistance: number = this.resistanceTo(instance.type)
  67. const resistance = baseResistance * factor
  68. newDamages.push({
  69. amount: instance.amount * resistance,
  70. target: instance.target,
  71. type: instance.type
  72. })
  73. })
  74. return new Damage(...newDamages)
  75. }
  76. takeDamage (damage: Damage): LogEntry {
  77. // first, we record health to decide if the entity just died
  78. const startHealth = this.vigors.Health
  79. damage = this.effectiveDamage(damage)
  80. damage.damages.forEach(instance => {
  81. if (instance.target in Vigor) {
  82. // just deal damage
  83. this.vigors[instance.target as Vigor] -= instance.amount
  84. } else if (instance.target in Stat) {
  85. // drain the stats, then deal damage to match
  86. const startVigors = this.maxVigors
  87. this.stats[instance.target as Stat] -= instance.amount
  88. const endVigors = this.maxVigors
  89. Object.keys(Vigor).map(vigor => {
  90. this.vigors[vigor as Vigor] -= startVigors[vigor as Vigor] - endVigors[vigor as Vigor]
  91. })
  92. }
  93. })
  94. if (this.vigors.Health <= 0 && startHealth > 0) {
  95. return this.destroy()
  96. } else {
  97. return new LogLine()
  98. }
  99. }
  100. toString (): string {
  101. return this.name.toString()
  102. }
  103. abstract destroy (): LogEntry;
  104. }