tutorials/nodeJS/warriorjs/tim-intermediate/Player.js

166 lines
3.3 KiB
JavaScript

const reverseMap = {
forward: 'backward',
backward: 'forward',
left: 'right',
right: 'left'
};
/**
* Class determining player actions for warriorjs 'game'
*/
class Player {
constructor() {
this.warrior = null;
this.direction = 'forward';
this.status = {
_health: 20,
health: 20,
isHealing: false,
damage: false
};
this.adjacent = {
forward: null,
backward: null,
left: null,
right: null
};
}
/**
* Collect information about the world for the Turn
*/
sense() {
this.status.health = this.warrior.health(); // Health of current turn
this.status.damage = (this.status._health > this.status.health);
this.direction = this.warrior.directionOfStairs();
this.adjacent = {
forward: this.warrior.feel('forward'),
backward: this.warrior.feel('backward'),
left: this.warrior.feel('left'),
right: this.warrior.feel('right')
};
}
/**
* Logic for resting to gain health
*/
heal() {
if (this.status.isHealing === false) {
this.status.isHealing = true;
}
this.warrior.rest();
// Stop healing when at penultimate heath level
// or if taking damage
if (this.status.health >= 18 || this.status.damage) {
this.status.isHealing = false;
}
}
isNothingAdjacent() {
let allClear = true;
for (const dir in this.adjacent) {
if ( ! (this.adjacent[dir].isEmpty() || this.adjacent[dir].isWall())) {
return false;
}
}
return allClear;
}
/**
* Does an adjacent enemy exist?
*/
isEnemyInRange() {
for (const dir in this.adjacent) {
if (this.adjacent[dir].isEnemy()) {
return true;
}
}
return false;
}
/**
* Determine if there are multiple adjacent enemies
*/
areMultipleEnemiesAdjacent() {
let numEnemies = 0;
for(const dir in this.adjacent) {
if (this.adjacent[dir].isEnemy() {
numEnemies++;
}
}
return (numEnemies > 1);
}
/**
* Return the direction of the first ajacent enemy found
*
* @return {string | boolean}
*/
findAdjacentEnemy() {
let enemy = false;
for (const dir in this.adjacent) {
if (this.adjacent[dir].isEnemy()) {
return dir;
}
}
return false;
}
/**
* Determine what to do based on what you've found with the senses
*
* @param direction - The direction to go for the next turn
*/
next(direction) {
switch(true) {
// There are multiple adjacent enemies
case this.areMultipleEnemiesAdjacent():
this.warrior.bind(this.findAdjacentEnemy());
break;
// There's an adjacent enemy
case this.isEnemyInRange():
this.warrior.attack(this.findAdjacentEnemy());
break;
// Nothing directly adjacent
case this.isNothingAdjacent():
// Check health (From 0 to 20)
if ( ! this.status.damage && (this.status.health <= 16 || this.status.isHealing === true)) {
this.heal();
} else if (this.status.damage && this.status.health <= 12) {
// Low health and taking damage
// Retreat to be able to heal
this.warrior.walk(reverseMap[direction]);
} else {
this.warrior.walk(direction);
}
break;
}
}
/**
* Callback for each Turn
*
* @param warrior - The player object
*/
playTurn(warrior) {
// Save the warrior object for other methods
this.warrior = warrior;
// Examine the world
this.sense();
// Figure out what to do with the next space
this.next(this.direction);
// Save current health
this.status._health = this.status.health;
}
}