Feast 2.0!
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 

138 строки
4.0 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. destroyed = false;
  42. constructor (name: Noun, kind: Noun, pronouns: Pronoun, public baseStats: Stats) {
  43. super(name, kind, pronouns)
  44. this.stats = Object.keys(Stat).reduce((base: any, key) => { base[key] = baseStats[key as Stat]; return base }, {})
  45. this.baseResistances = Object.keys(DamageType).reduce((resist: any, key) => { resist[key] = 1; return resist }, {})
  46. Object.entries(this.maxVigors).forEach(([key, val]) => {
  47. this.vigors[key as Vigor] = val
  48. })
  49. }
  50. resistanceTo (damageType: DamageType): number {
  51. return this.baseResistances[damageType]
  52. }
  53. get maxVigors (): Readonly<Vigors> {
  54. return {
  55. Health: this.stats.Toughness * 10 + this.stats.Power * 5,
  56. Resolve: this.stats.Willpower * 10 + this.stats.Charm * 5,
  57. Stamina: this.stats.Speed * 10 + this.stats.Power * 2.5 + this.stats.Charm * 2.5
  58. }
  59. }
  60. get disabled (): boolean {
  61. return Object.values(this.vigors).some(val => val <= 0)
  62. }
  63. effectiveDamage (damage: Damage): Damage {
  64. const newDamages: DamageInstance[] = []
  65. damage.damages.forEach(instance => {
  66. const factor = instance.type === DamageType.Heal ? -1 : 1
  67. const baseResistance: number = this.resistanceTo(instance.type)
  68. const resistance = baseResistance * factor
  69. newDamages.push({
  70. amount: instance.amount * resistance,
  71. target: instance.target,
  72. type: instance.type
  73. })
  74. })
  75. return new Damage(...newDamages)
  76. }
  77. takeDamage (damage: Damage): LogEntry {
  78. // first, we record health to decide if the entity just died
  79. const startHealth = this.vigors.Health
  80. damage = this.effectiveDamage(damage)
  81. damage.damages.forEach(instance => {
  82. if (instance.target in Vigor) {
  83. // just deal damage
  84. this.vigors[instance.target as Vigor] -= instance.amount
  85. } else if (instance.target in Stat) {
  86. // drain the stats, then deal damage to match
  87. const startVigors = this.maxVigors
  88. this.stats[instance.target as Stat] -= instance.amount
  89. const endVigors = this.maxVigors
  90. Object.keys(Vigor).map(vigor => {
  91. this.vigors[vigor as Vigor] -= startVigors[vigor as Vigor] - endVigors[vigor as Vigor]
  92. })
  93. }
  94. })
  95. Object.keys(Vigor).forEach(vigorStr => {
  96. const vigor = vigorStr as Vigor
  97. if (this.vigors[vigor] > this.maxVigors[vigor]) {
  98. this.vigors[vigor] = this.maxVigors[vigor]
  99. }
  100. })
  101. if (this.vigors.Health <= -this.maxVigors.Health) {
  102. this.destroyed = true
  103. }
  104. if (this.vigors.Health <= 0 && startHealth > 0) {
  105. return this.destroy()
  106. } else {
  107. return new LogLine()
  108. }
  109. }
  110. toString (): string {
  111. return this.name.toString()
  112. }
  113. abstract destroy (): LogEntry;
  114. }