///
///
///
///
///
/**
* A person is a thing that happens to be "alive" in some significant way, not necessarily human.
* A robot is a person.
* A dog is a person.
*
* Fuck your standards.
*/
class Person extends Thing implements AttributeBearer, SkillBearer {
public AI = new AI({actor: this});
public animated = true;
public soreness = 0;
public lastHealthUpdate = 0;
public stamina = 10;
public lastStaminaUpdate = 0;
public staminaPerTurn = 1;
public static MAX_STAMINA = 10;
public static STRENGTH_SORENESS_MULTIPLIER = 4;
public constructor (options : ThingOptions) {
super(options);
this.addGetAlterations((person : Person) => {
// Let's not do this for NPCs. It can break patches.
if (person.isPlayer()) {
return {
Stats: this.attributeValue,
Skills: this.skillValue
}
}
});
this.addSetAlterations((person : Person, changes) => {
// Let's not do this for NPCs. It can break patches.
if (person.isPlayer()) {
if (changes.Stats != undefined) {
for (let name in changes.Stats) {
let attr = Attribute.getAttribute(name);
if (attr != undefined) {
this.setStat(attr, changes.Stats[name]);
}
}
}
if (changes.Skills != undefined) {
for (let name in changes.Skills) {
let attr = Skill.getSkill(name);
if (attr != undefined) {
this.setSkill(attr, changes.Skills[name]);
}
}
}
}
});
}
public changeHealth (n : number) {
let bodyparts = > this.getParts(Bodypart);
for (let i = 0; i < bodyparts.length; i++) {
bodyparts[i].changeSoreness(n);
}
this.updateHealth();
}
/**
* Returns health as a number from 0 to 10.
*/
public getHealthOnScale () {
return Math.round(
((this.getHealth() * 10) / (this.getStat(Attributes.Strength) * 2))
);
}
/**
* Returns current health.
* Important = force update, otherwise use sufficiently accurate current value. to prevent looping too much.
* @param {boolean} important
* @returns {number}
*/
public getHealth (important? : boolean) {
if (important === true || this.lastHealthUpdate != WorldState.getCurrentTurn()) {
this.updateHealth();
}
return this.soreness / (this.getStat(Attributes.Strength) * Person.STRENGTH_SORENESS_MULTIPLIER)
}
/**
* Lazy updates allow us to count Health/Stamina for NPCs without overloading the Every Turn rulebook.
*/
public updateHealth () {
let health = 0;
let bodyparts = this.getParts(Bodypart);
for (let i = 0; i < bodyparts.length; i++) {
health += bodyparts[i].getWeightedSoreness();
}
this.soreness = health;
this.lastHealthUpdate = WorldState.getCurrentTurn();
}
public changeStamina (n : number) {
this.updateStamina();
this.stamina += n;
if (this.stamina > Person.MAX_STAMINA) {
this.stamina = Person.MAX_STAMINA;
} else if (this.stamina < 0) {
this.stamina = 0;
}
}
/**
* Returns stamina as a number from 0 to 10.
*/
public getStaminaOnScale () {
return Math.round(
((this.stamina * 10) / Person.MAX_STAMINA)
);
}
public updateStamina () {
var nTurns = WorldState.getCurrentTurn() - this.lastStaminaUpdate;
this.stamina += this.staminaPerTurn * nTurns;
if (this.stamina > Person.MAX_STAMINA) {
this.stamina = Person.MAX_STAMINA;
}
}
public isPlayer () {
return ( this) == WorldState.player;
}
protected attributeValue : {[id : string] : number} = {};
protected skillValue : {[id : string] : number} = {};
public getStat (stat : Attribute) {
if (this.attributeValue[stat.id] == undefined) {
this.attributeValue[stat.id] = stat.defaultValue;
}
return this.attributeValue[stat.id];
}
public setStat (stat : Attribute, value : number) {
this.attributeValue[stat.id] = value;
}
public getSkill (stat : Skill) {
if (this.skillValue[stat.id] == undefined) {
this.skillValue[stat.id] = stat.defaultValue;
}
return this.skillValue[stat.id];
}
public setSkill (stat : Skill, value : number) {
this.skillValue[stat.id] = value;
}
public die () {
let corpse = new Corpse({
name : this.name + "'s corpse",
unique : false,
description : new Say("The lifeless body of ", this, ". May ", new SayHeSheIt(this), " rest in peace.")
});
corpse.put(...Thing.CarryRelation.getRight(this));
corpse.put(...Thing.WearRelation.getRight(this));
this.getRoom().place(corpse);
OutOfPlay.removeFromPlay(this);
}
}