Progress on achivements
* Fetch art if available * Queue local and/or global interrupts * Apply text formatting * Bug exists with interruptions in certain scenarios that needs worked out
This commit is contained in:
parent
bd03d7a79b
commit
10517b1060
|
@ -9,9 +9,16 @@ const UserInterruptQueue = require('./user_interrupt_queue.js');
|
|||
const {
|
||||
getConnectionByUserId
|
||||
} = require('./client_connections.js');
|
||||
const UserProps = require('./user_property.js');
|
||||
const { Errors } = require('./enig_error.js');
|
||||
const { getThemeArt } = require('./theme.js');
|
||||
const { pipeToAnsi } = require('./color_codes.js');
|
||||
const stringFormat = require('./string_format.js');
|
||||
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
const async = require('async');
|
||||
const moment = require('moment');
|
||||
|
||||
class Achievements {
|
||||
constructor(events) {
|
||||
|
@ -61,29 +68,141 @@ class Achievements {
|
|||
const achievement = config.userAchievements.achievements[achievementTag];
|
||||
let matchValue = Object.keys(achievement.match || {}).sort( (a, b) => b - a).find(v => statValue >= v);
|
||||
if(matchValue) {
|
||||
const match = achievement.match[matchValue];
|
||||
const details = achievement.match[matchValue];
|
||||
matchValue = parseInt(matchValue);
|
||||
|
||||
//
|
||||
// Check if we've triggered this event before
|
||||
//
|
||||
async.series(
|
||||
[
|
||||
(callback) => {
|
||||
this.loadAchievementHitCount(userStatEvent.user, achievementTag, null, matchValue, (err, count) => {
|
||||
if(count > 0) {
|
||||
return;
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(count > 0 ? Errors.General('Achievement already acquired') : null);
|
||||
});
|
||||
},
|
||||
(callback) => {
|
||||
const client = getConnectionByUserId(userStatEvent.user.userId);
|
||||
if(!client) {
|
||||
return callback(Errors.UnexpectedState('Failed to get client for user ID'));
|
||||
}
|
||||
|
||||
const conn = getConnectionByUserId(userStatEvent.user.userId);
|
||||
if(!conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const interruptItem = {
|
||||
text : match.text,
|
||||
pause : true,
|
||||
const info = {
|
||||
achievement,
|
||||
details,
|
||||
client,
|
||||
value : matchValue,
|
||||
user : userStatEvent.user,
|
||||
timestamp : moment(),
|
||||
};
|
||||
|
||||
UserInterruptQueue.queue(interruptItem, { omit : conn} );
|
||||
this.createAchievementInterruptItems(info, (err, interruptItems) => {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if(interruptItems.local) {
|
||||
UserInterruptQueue.queue(interruptItems.local, { clients : client } );
|
||||
}
|
||||
|
||||
if(interruptItems.global) {
|
||||
UserInterruptQueue.queue(interruptItems.global, { omit : client } );
|
||||
}
|
||||
});
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createAchievementInterruptItems(info, cb) {
|
||||
const dateTimeFormat =
|
||||
info.details.dateTimeFormat ||
|
||||
info.achievement.dateTimeFormat ||
|
||||
info.client.currentTheme.helpers.getDateTimeFormat();
|
||||
|
||||
const config = Config();
|
||||
|
||||
const formatObj = {
|
||||
userName : info.user.username,
|
||||
userRealName : info.user.properties[UserProps.RealName],
|
||||
userLocation : info.user.properties[UserProps.Location],
|
||||
userAffils : info.user.properties[UserProps.Affiliations],
|
||||
nodeId : info.client.node,
|
||||
title : info.details.title,
|
||||
text : info.global ? info.details.globalText : info.details.text,
|
||||
points : info.details.points,
|
||||
value : info.value,
|
||||
timestamp : moment(info.timestamp).format(dateTimeFormat),
|
||||
boardName : config.general.boardName,
|
||||
};
|
||||
|
||||
const title = stringFormat(info.details.title, formatObj);
|
||||
const text = stringFormat(info.details.text, formatObj);
|
||||
|
||||
let globalText;
|
||||
if(info.details.globalText) {
|
||||
globalText = stringFormat(info.details.globalText, formatObj);
|
||||
}
|
||||
|
||||
const getArt = (name, callback) => {
|
||||
const spec =
|
||||
_.get(info.details, `art.${name}`) ||
|
||||
_.get(info.achievement, `art.${name}`) ||
|
||||
_.get(config, `userAchievements.art.${name}`);
|
||||
if(!spec) {
|
||||
return callback(null);
|
||||
}
|
||||
const getArtOpts = {
|
||||
name : spec,
|
||||
client : this.client,
|
||||
random : false,
|
||||
};
|
||||
getThemeArt(getArtOpts, (err, artInfo) => {
|
||||
// ignore errors
|
||||
return callback(artInfo ? artInfo.data : null);
|
||||
});
|
||||
};
|
||||
|
||||
const interruptItems = {};
|
||||
let itemTypes = [ 'local' ];
|
||||
if(globalText) {
|
||||
itemTypes.push('global');
|
||||
}
|
||||
|
||||
async.each(itemTypes, (itemType, nextItemType) => {
|
||||
async.waterfall(
|
||||
[
|
||||
(callback) => {
|
||||
getArt('header', headerArt => {
|
||||
return callback(null, headerArt);
|
||||
});
|
||||
},
|
||||
(headerArt, callback) => {
|
||||
getArt('footer', footerArt => {
|
||||
return callback(null, headerArt, footerArt);
|
||||
});
|
||||
},
|
||||
(headerArt, footerArt, callback) => {
|
||||
const itemText = 'global' === itemType ? globalText : text;
|
||||
interruptItems[itemType] = {
|
||||
text : `${title}\r\n${itemText}`,
|
||||
pause : true,
|
||||
};
|
||||
if(headerArt || footerArt) {
|
||||
interruptItems[itemType].contents = `${headerArt || ''}\r\n${pipeToAnsi(itemText)}\r\n${footerArt || ''}`;
|
||||
}
|
||||
return callback(null);
|
||||
}
|
||||
],
|
||||
err => {
|
||||
return nextItemType(err);
|
||||
}
|
||||
);
|
||||
},
|
||||
err => {
|
||||
return cb(err, interruptItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1008,8 +1008,12 @@ function getDefaultConfig() {
|
|||
userAchievements : {
|
||||
enabled : true,
|
||||
|
||||
artHeader : 'achievement_header',
|
||||
artFooter : 'achievement_footer',
|
||||
art : {
|
||||
header : 'achievement_header',
|
||||
footer : 'achievement_footer',
|
||||
},
|
||||
|
||||
// :TODO: achievements should be a path/filename -> achievements.hjson & allow override/theming
|
||||
|
||||
achievements : {
|
||||
user_login_count : {
|
||||
|
@ -1019,20 +1023,20 @@ function getDefaultConfig() {
|
|||
match : {
|
||||
10 : {
|
||||
title : 'Return Caller',
|
||||
globalText : '{userName} has logged in {statValue} times!',
|
||||
text : 'You\'ve logged in {statValue} times!',
|
||||
globalText : '{userName} has logged in {value} times!',
|
||||
text : 'You\'ve logged in {value} times!',
|
||||
points : 5,
|
||||
},
|
||||
25 : {
|
||||
title : 'Seems To Like It!',
|
||||
globalText : '{userName} has logged in {statValue} times!',
|
||||
text : 'You\'ve logged in {statValue} times!',
|
||||
globalText : '{userName} has logged in {value} times!',
|
||||
text : 'You\'ve logged in {value} times!',
|
||||
points : 10,
|
||||
},
|
||||
100 : {
|
||||
title : '{boardName} Addict',
|
||||
globalText : '{userName} the BBS {boardName} addict has logged in {statValue} times!',
|
||||
text : 'You\'re a {boardName} addict! You\'ve logged in {statValue} times!',
|
||||
globalText : '{userName} the BBS {boardName} addict has logged in {value} times!',
|
||||
text : 'You\'re a {boardName} addict! You\'ve logged in {value} times!',
|
||||
points : 10,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue