Implement retroactive achievements (for userStat types so far)

This commit is contained in:
Bryan Ashby 2019-01-06 10:41:04 -07:00
parent 2b802cb534
commit f653d83c14
4 changed files with 49 additions and 17 deletions

View File

@ -984,7 +984,7 @@
achievements: { achievements: {
defaults: { defaults: {
format: "|08 > |10{title} |08(|11{points} |03points|08)\r\n\r\n {message}" format: "|08 > |10{title} |08(|11{points} |03points|08)\r\n\r\n {message}"
globalFformat: "|08 > |10{title} |08(|11{points} |03points|08)\r\n\r\n {message}" globalformat: "|08 > |10{title} |08(|11{points} |03points|08)\r\n\r\n {message}"
titleSGR: "|10" titleSGR: "|10"
pointsSGR: "|12" pointsSGR: "|12"
textSGR: "|00|03" textSGR: "|00|03"

View File

@ -55,12 +55,11 @@
user_login_count: { user_login_count: {
type: userStat type: userStat
statName: login_count statName: login_count
retroactive: true
match: { match: {
2: { 2: {
title: "Return Caller" title: "Return Caller"
globalText: "{userName} has returned to {boardName}!" globalText: "{userName} has returned to {boardName}!"
text: "You\"ve returned to {boardName}!" text: "You've returned to {boardName}!"
points: 5 points: 5
} }
10: { 10: {
@ -93,7 +92,6 @@
user_post_count: { user_post_count: {
type: userStat type: userStat
statName: post_count statName: post_count
retroactive: true
match: { match: {
5: { 5: {
title: "Poster" title: "Poster"
@ -125,7 +123,6 @@
user_upload_count: { user_upload_count: {
type: userStat type: userStat
statName: ul_total_count statName: ul_total_count
retroactive: true
match: { match: {
1: { 1: {
title: "Uploader" title: "Uploader"
@ -164,7 +161,6 @@
user_download_count: { user_download_count: {
type: userStat type: userStat
statName: dl_total_count statName: dl_total_count
retroactive: true
match: { match: {
1: { 1: {
title: "Downloader" title: "Downloader"
@ -202,7 +198,6 @@
user_door_runs: { user_door_runs: {
type: userStat type: userStat
statName: door_run_total_count statName: door_run_total_count
retroactive: true
match: { match: {
1: { 1: {
title: "Nostalgia Toe Dip", title: "Nostalgia Toe Dip",
@ -240,7 +235,6 @@
user_door_total_minutes: { user_door_total_minutes: {
type: userStat type: userStat
statName: door_run_total_minutes statName: door_run_total_minutes
retroactive: true
match: { match: {
1: { 1: {
title: "Nevermind!" title: "Nevermind!"

View File

@ -37,6 +37,9 @@ const paths = require('path');
class Achievement { class Achievement {
constructor(data) { constructor(data) {
this.data = data; this.data = data;
// achievements are retroactive by default
this.data.retroactive = _.get(this.data, 'retroactive', true);
} }
static factory(data) { static factory(data) {
@ -87,6 +90,9 @@ class Achievement {
class UserStatAchievement extends Achievement { class UserStatAchievement extends Achievement {
constructor(data) { constructor(data) {
super(data); super(data);
// sort match keys for quick match lookup
this.matchKeys = Object.keys(this.data.match || {}).map(k => parseInt(k)).sort( (a, b) => b - a);
} }
isValid() { isValid() {
@ -97,7 +103,7 @@ class UserStatAchievement extends Achievement {
} }
getMatchDetails(matchValue) { getMatchDetails(matchValue) {
let matchField = Object.keys(this.data.match || {}).sort( (a, b) => b - a).find(v => matchValue >= v); let matchField = this.matchKeys.find(v => matchValue >= v);
if(matchField) { if(matchField) {
const match = this.data.match[matchField]; const match = this.data.match[matchField];
if(this.isValidMatchDetails(match)) { if(this.isValidMatchDetails(match)) {
@ -218,6 +224,22 @@ class Achievements {
}); });
} }
recordAndDisplayAchievement(info, cb) {
async.series(
[
(callback) => {
return this.record(info, callback);
},
(callback) => {
return this.display(info, callback);
}
],
err => {
return cb(err);
}
);
}
monitorUserStatUpdateEvents() { monitorUserStatUpdateEvents() {
if(this.userStatEventListener) { if(this.userStatEventListener) {
return; // already listening return; // already listening
@ -287,15 +309,31 @@ class Achievements {
timestamp : moment(), timestamp : moment(),
}; };
return callback(null, info); const achievementsInfo = [ info ];
}, if(true === achievement.data.retroactive) {
(info, callback) => { // For userStat, any lesser match keys(values) are also met. Example:
this.record(info, err => { // matchKeys: [ 500, 200, 100, 20, 10, 2 ]
return callback(err, info); // ^---- we met here
// ^------------^ retroactive range
//
const index = achievement.matchKeys.findIndex(v => v < matchField);
if(index > -1) {
achievementsInfo.push(...achievement.matchKeys.slice(index).map(k => {
const [ d, f, v ] = achievement.getMatchDetails(k);
return Object.assign({}, info, { details : d, matchField : f, achievedValue : f, matchValue : v } );
}));
}
}
// reverse achievementsInfo so we display smallest > largest
achievementsInfo.reverse();
async.each(achievementsInfo, (achInfo, nextAchInfo) => {
return this.recordAndDisplayAchievement(achInfo, nextAchInfo);
},
err => {
return callback(err);
}); });
},
(info, callback) => {
return this.display(info, callback);
} }
], ],
err => { err => {