Person.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /// <reference path="../Thing.ts" />
  2. /// <reference path="../AI.ts" />
  3. /// <reference path="Person/Attribute.ts" />
  4. /// <reference path="Person/Skill.ts" />
  5. /// <reference path="../Container/Corpse.ts" />
  6. /**
  7. * A person is a thing that happens to be "alive" in some significant way, not necessarily human.
  8. * A robot is a person.
  9. * A dog is a person.
  10. *
  11. * Fuck your standards.
  12. */
  13. class Person extends Thing implements AttributeBearer, SkillBearer {
  14. public AI = new AI({});
  15. public animated = true;
  16. public soreness = 0;
  17. public lastHealthUpdate = 0;
  18. public stamina = 10;
  19. public lastStaminaUpdate = 0;
  20. public staminaPerTurn = 1;
  21. public static MAX_STAMINA = 10;
  22. public static STRENGTH_SORENESS_MULTIPLIER = 4;
  23. public constructor (options : ThingOptions) {
  24. super(options);
  25. this.addGetAlterations((person : Person) => {
  26. // Let's not do this for NPCs. It can break patches.
  27. if (person.isPlayer()) {
  28. return {
  29. Stats: this.attributeValue,
  30. Skills: this.skillValue
  31. }
  32. }
  33. });
  34. this.addSetAlterations((person : Person, changes) => {
  35. // Let's not do this for NPCs. It can break patches.
  36. if (person.isPlayer()) {
  37. if (changes.Stats != undefined) {
  38. for (let name in changes.Stats) {
  39. let attr = Attribute.getAttribute(name);
  40. if (attr != undefined) {
  41. this.setStat(attr, changes.Stats[name]);
  42. }
  43. }
  44. }
  45. if (changes.Skills != undefined) {
  46. for (let name in changes.Skills) {
  47. let attr = Skill.getSkill(name);
  48. if (attr != undefined) {
  49. this.setSkill(attr, changes.Skills[name]);
  50. }
  51. }
  52. }
  53. }
  54. });
  55. }
  56. public changeHealth (n : number) {
  57. let bodyparts = <Array<Bodypart>> this.getParts(Bodypart);
  58. for (let i = 0; i < bodyparts.length; i++) {
  59. bodyparts[i].changeSoreness(n);
  60. }
  61. this.updateHealth();
  62. }
  63. /**
  64. * Returns health as a number from 0 to 10.
  65. */
  66. public getHealthOnScale () {
  67. return Math.round(
  68. ((this.getHealth() * 10) / (this.getStat(Attributes.Strength) * 2))
  69. );
  70. }
  71. /**
  72. * Returns current health.
  73. * Important = force update, otherwise use sufficiently accurate current value. to prevent looping too much.
  74. * @param {boolean} important
  75. * @returns {number}
  76. */
  77. public getHealth (important? : boolean) {
  78. if (important === true || this.lastHealthUpdate != WorldState.getCurrentTurn()) {
  79. this.updateHealth();
  80. }
  81. return this.soreness / (this.getStat(Attributes.Strength) * Person.STRENGTH_SORENESS_MULTIPLIER)
  82. }
  83. /**
  84. * Lazy updates allow us to count Health/Stamina for NPCs without overloading the Every Turn rulebook.
  85. */
  86. public updateHealth () {
  87. let health = 0;
  88. let bodyparts = this.getParts(Bodypart);
  89. for (let i = 0; i < bodyparts.length; i++) {
  90. health += bodyparts[i].getWeightedSoreness();
  91. }
  92. this.soreness = health;
  93. this.lastHealthUpdate = WorldState.getCurrentTurn();
  94. }
  95. public changeStamina (n : number) {
  96. this.updateStamina();
  97. this.stamina += n;
  98. if (this.stamina > Person.MAX_STAMINA) {
  99. this.stamina = Person.MAX_STAMINA;
  100. } else if (this.stamina < 0) {
  101. this.stamina = 0;
  102. }
  103. }
  104. /**
  105. * Returns stamina as a number from 0 to 10.
  106. */
  107. public getStaminaOnScale () {
  108. return Math.round(
  109. ((this.stamina * 10) / Person.MAX_STAMINA)
  110. );
  111. }
  112. public updateStamina () {
  113. var nTurns = WorldState.getCurrentTurn() - this.lastStaminaUpdate;
  114. this.stamina += this.staminaPerTurn * nTurns;
  115. if (this.stamina > Person.MAX_STAMINA) {
  116. this.stamina = Person.MAX_STAMINA;
  117. }
  118. }
  119. public isPlayer () {
  120. return (<any> this) == WorldState.player;
  121. }
  122. protected attributeValue : {[id : string] : number} = {};
  123. protected skillValue : {[id : string] : number} = {};
  124. public getStat (stat : Attribute) {
  125. if (this.attributeValue[stat.id] == undefined) {
  126. this.attributeValue[stat.id] = stat.defaultValue;
  127. }
  128. return this.attributeValue[stat.id];
  129. }
  130. public setStat (stat : Attribute, value : number) {
  131. this.attributeValue[stat.id] = value;
  132. }
  133. public getSkill (stat : Skill) {
  134. if (this.skillValue[stat.id] == undefined) {
  135. this.skillValue[stat.id] = stat.defaultValue;
  136. }
  137. return this.skillValue[stat.id];
  138. }
  139. public setSkill (stat : Skill, value : number) {
  140. this.skillValue[stat.id] = value;
  141. }
  142. public die () {
  143. let corpse = new Corpse({
  144. name : this.name + "'s corpse",
  145. unique : false,
  146. description : new Say("The lifeless body of ", this, ". May ", new SayHeSheIt(this), " rest in peace.")
  147. });
  148. corpse.put(...Thing.CarryRelation.getRight(this));
  149. corpse.put(...Thing.WearRelation.getRight(this));
  150. this.getRoom().place(corpse);
  151. OutOfPlay.removeFromPlay(this);
  152. }
  153. }