'use strict';
const EventEmitter = require('events');
/**
* @property {object} config Default config for this quest, see individual quest types for details
* @property {Player} player
* @property {object} state Current completion state
* @extends EventEmitter
*/
class Quest extends EventEmitter {
constructor(GameState, id, config, player) {
super();
this.id = id;
this.entityReference = config.entityReference;
this.config = Object.assign({
title: 'Missing Quest Title',
description: 'Missing Quest Description',
completionMessage: null,
requires: [],
level: 1,
autoComplete: false,
repeatable: false,
rewards: [],
goals: [],
}, config);
this.player = player;
this.goals = [];
this.state = [];
this.GameState = GameState;
}
/**
* Proxy all events to all the goals
* @param {string} event
* @param {...*} args
*/
emit(event, ...args) {
super.emit(event, ...args);
if (event === 'progress') {
// don't proxy progress event
return;
}
this.goals.forEach(goal => {
goal.emit(event, ...args);
});
}
addGoal(goal) {
this.goals.push(goal);
goal.on('progress', () => this.onProgressUpdated());
}
/**
* @fires Quest#turn-in-ready
* @fires Quest#progress
*/
onProgressUpdated() {
const progress = this.getProgress();
if (progress.percent >= 100) {
if (this.config.autoComplete) {
this.complete();
} else {
/**
* @event Quest#turn-in-ready
*/
this.emit('turn-in-ready');
}
return;
}
/**
* @event Quest#progress
* @param {object} progress
*/
this.emit('progress', progress);
}
/**
* @return {{ percent: number, display: string }}
*/
getProgress() {
let overallPercent = 0;
let overallDisplay = [];
this.goals.forEach(goal => {
const goalProgress = goal.getProgress();
overallPercent += goalProgress.percent;
overallDisplay.push(goalProgress.display);
});
return {
percent: Math.round(overallPercent / this.goals.length),
display: overallDisplay.join('\r\n'),
};
}
/**
* Save the current state of the quest on player save
* @return {object}
*/
serialize() {
return {
state: this.goals.map(goal => goal.serialize()),
progress: this.getProgress(),
config: {
desc: this.config.desc,
level: this.config.level,
title: this.config.title,
},
};
}
hydrate() {
this.state.forEach((goalState, i) => {
this.goals[i].hydrate(goalState.state);
});
}
/**
* @fires Quest#complete
*/
complete() {
/**
* @event Quest#complete
*/
this.emit('complete');
for (const goal of this.goals) {
goal.complete();
}
}
}
module.exports = Quest;