Person.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. enum PersonStance {
  14. STANDING, ALLFOURS, KNOCKEDOUT
  15. }
  16. let PersonStanceNames = {};
  17. PersonStanceNames[PersonStance.STANDING] = "standing";
  18. PersonStanceNames[PersonStance.ALLFOURS] = "kneeling";
  19. PersonStanceNames[PersonStance.KNOCKEDOUT] = "passed out";
  20. class Person extends Thing implements AttributeBearer, SkillBearer {
  21. public AI = new AI({actor: this});
  22. public animated = true;
  23. public soreness = 0;
  24. public lastHealthUpdate = 0;
  25. public stamina = 10;
  26. public lastStaminaUpdate = 0;
  27. public staminaPerTurn = 1;
  28. public static MAX_STAMINA = 10;
  29. public static STRENGTH_SORENESS_MULTIPLIER = 4;
  30. public stance : PersonStance = PersonStance.STANDING;
  31. public reputation : number = 0;
  32. public constructor (options : ThingOptions) {
  33. super(options);
  34. this.addGetAlterations((person : Person) => {
  35. // Let's not do this for NPCs. It can break patches.
  36. if (person.isPlayer()) {
  37. return {
  38. Stats: this.attributeValue,
  39. Skills: this.skillValue
  40. }
  41. } else {
  42. return {
  43. reputation : this.reputation
  44. }
  45. }
  46. });
  47. // We *should* have the bodypart thing here, but there are issues with Humanoids and that...
  48. // this.addGetAlterations((person : Person) => {
  49. //
  50. // });
  51. this.addSetAlterations((person : Person, changes) => {
  52. // Let's not do this for NPCs. It can break patches.
  53. if (person.isPlayer()) {
  54. if (changes.Stats != undefined) {
  55. for (let name in changes.Stats) {
  56. let attr = Attribute.getAttribute(name);
  57. if (attr != undefined) {
  58. this.setStat(attr, changes.Stats[name]);
  59. }
  60. }
  61. }
  62. if (changes.Skills != undefined) {
  63. for (let name in changes.Skills) {
  64. let attr = Skill.getSkill(name);
  65. if (attr != undefined) {
  66. this.setSkill(attr, changes.Skills[name]);
  67. }
  68. }
  69. }
  70. } else {
  71. if (changes.reputation != undefined) {
  72. this.reputation = changes.reputation;
  73. }
  74. }
  75. });
  76. }
  77. public changeHealth (n : number) {
  78. let bodyparts = <Array<Bodypart>> this.getParts(Bodypart);
  79. for (let i = 0; i < bodyparts.length; i++) {
  80. bodyparts[i].changeSoreness(n);
  81. }
  82. this.updateHealth();
  83. }
  84. /**
  85. * Returns health as a number from 0 to 10.
  86. */
  87. public getHealthOnScale () {
  88. return Math.ceil(10 - (this.getHealth() * 10));
  89. }
  90. /**
  91. * Returns current health.
  92. * Important = force update, otherwise use sufficiently accurate current value. to prevent looping too much.
  93. * @param {boolean} important
  94. * @returns {number}
  95. */
  96. public getHealth (important? : boolean) {
  97. if (important === true || this.lastHealthUpdate != WorldState.getCurrentTurn()) {
  98. this.updateHealth();
  99. }
  100. return this.soreness / this.getMaxHealth()
  101. }
  102. public getMaxHealth () {
  103. return (this.getStat(Attributes.Strength) * Person.STRENGTH_SORENESS_MULTIPLIER);
  104. }
  105. /**
  106. * Lazy updates allow us to count Health/Stamina for NPCs without overloading the Every Turn rulebook.
  107. */
  108. public updateHealth () {
  109. let health = 0;
  110. let bodyparts = this.getParts(Bodypart);
  111. for (let i = 0; i < bodyparts.length; i++) {
  112. health += bodyparts[i].getWeightedSoreness();
  113. }
  114. this.soreness = health;
  115. this.lastHealthUpdate = WorldState.getCurrentTurn();
  116. }
  117. public changeStamina (n : number) {
  118. this.updateStamina();
  119. this.stamina += n;
  120. if (this.stamina > Person.MAX_STAMINA) {
  121. this.stamina = Person.MAX_STAMINA;
  122. } else if (this.stamina < 0) {
  123. this.stamina = 0;
  124. }
  125. }
  126. /**
  127. * Returns stamina as a number from 0 to 10.
  128. */
  129. public getStaminaOnScale () {
  130. return Math.round(
  131. ((this.stamina * 10) / Person.MAX_STAMINA)
  132. );
  133. }
  134. public updateStamina () {
  135. var nTurns = WorldState.getCurrentTurn() - this.lastStaminaUpdate;
  136. this.stamina += this.staminaPerTurn * nTurns;
  137. if (this.stamina > Person.MAX_STAMINA) {
  138. this.stamina = Person.MAX_STAMINA;
  139. }
  140. }
  141. public isPlayer () {
  142. return (<any> this) == WorldState.player;
  143. }
  144. protected attributeValue : {[id : string] : number} = {};
  145. protected skillValue : {[id : string] : number} = {};
  146. public getStat (stat : Attribute) {
  147. if (this.attributeValue[stat.id] == undefined) {
  148. this.attributeValue[stat.id] = stat.defaultValue;
  149. }
  150. return this.attributeValue[stat.id];
  151. }
  152. public setStat (stat : Attribute, value : number) {
  153. this.attributeValue[stat.id] = value;
  154. }
  155. public getSkill (stat : Skill) {
  156. if (this.skillValue[stat.id] == undefined) {
  157. this.skillValue[stat.id] = stat.defaultValue;
  158. }
  159. return this.skillValue[stat.id];
  160. }
  161. public setSkill (stat : Skill, value : number) {
  162. this.skillValue[stat.id] = value;
  163. }
  164. public die () {
  165. let corpse = new Corpse({
  166. name : this.name + "'s corpse",
  167. unique : false,
  168. description : new Say("The lifeless body of ", this, ". May ", new SayHeSheIt(this), " rest in peace.")
  169. });
  170. corpse.put(...Thing.CarryRelation.getRight(this));
  171. corpse.put(...Thing.WearRelation.getRight(this));
  172. this.getRoom().place(corpse);
  173. OutOfPlay.removeFromPlay(this);
  174. }
  175. public getPoked (action : Action) {
  176. return this.AI.getPoked(action);
  177. }
  178. }