WIP on user achievements
* Hook up events for testing * Start to plug in experimental interrupt
This commit is contained in:
parent
c5a72c7356
commit
a34dab6a73
|
@ -0,0 +1,103 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
// ENiGMA½
|
||||
const Events = require('./events.js');
|
||||
const Config = require('./config.js').get;
|
||||
const UserDb = require('./database.js').dbs.user;
|
||||
const UserInterruptQueue = require('./user_interrupt_queue.js');
|
||||
const {
|
||||
getConnectionByUserId
|
||||
} = require('./client_connections.js');
|
||||
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
|
||||
class Achievements {
|
||||
constructor(events) {
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
init(cb) {
|
||||
this.monitorUserStatUpdateEvents();
|
||||
return cb(null);
|
||||
}
|
||||
|
||||
loadAchievementHitCount(user, achievementTag, field, value, cb) {
|
||||
UserDb.get(
|
||||
`SELECT COUNT() AS count
|
||||
FROM user_achievement
|
||||
WHERE user_id = ? AND achievement_tag = ? AND match_field = ? AND match_value >= ?;`,
|
||||
[ user.userId, achievementTag, field, value ],
|
||||
(err, row) => {
|
||||
return cb(err, row && row.count || 0);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
monitorUserStatUpdateEvents() {
|
||||
this.events.on(Events.getSystemEvents().UserStatUpdate, userStatEvent => {
|
||||
const statValue = parseInt(userStatEvent.statValue, 10);
|
||||
if(isNaN(statValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = Config();
|
||||
const achievementTag = _.findKey(
|
||||
_.get(config, 'userAchievements.achievements', {}),
|
||||
achievement => {
|
||||
if(false === achievement.enabled) {
|
||||
return false;
|
||||
}
|
||||
return 'userStat' === achievement.type &&
|
||||
achievement.statName === userStatEvent.statName;
|
||||
}
|
||||
);
|
||||
|
||||
if(!achievementTag) {
|
||||
return;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
//
|
||||
// Check if we've triggered this event before
|
||||
//
|
||||
this.loadAchievementHitCount(userStatEvent.user, achievementTag, null, matchValue, (err, count) => {
|
||||
if(count > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const conn = getConnectionByUserId(userStatEvent.user.userId);
|
||||
if(!conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const interruptItem = {
|
||||
text : match.text,
|
||||
pause : true,
|
||||
};
|
||||
|
||||
UserInterruptQueue.queue(interruptItem, { omit : conn} );
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let achievements;
|
||||
|
||||
exports.moduleInitialize = (initInfo, cb) => {
|
||||
|
||||
if(false === _.get(Config(), 'userAchievements.enabled')) {
|
||||
// :TODO: Log disabled
|
||||
return cb(null);
|
||||
}
|
||||
|
||||
achievements = new Achievements(initInfo.events);
|
||||
return achievements.init(cb);
|
||||
};
|
||||
|
|
@ -1003,6 +1003,41 @@ function getDefaultConfig() {
|
|||
systemEvents : {
|
||||
loginHistoryMax: -1, // set to -1 for forever
|
||||
}
|
||||
},
|
||||
|
||||
userAchievements : {
|
||||
enabled : true,
|
||||
|
||||
artHeader : 'achievement_header',
|
||||
artFooter : 'achievement_footer',
|
||||
|
||||
achievements : {
|
||||
user_login_count : {
|
||||
type : 'userStat',
|
||||
statName : 'login_count',
|
||||
retroactive : true,
|
||||
match : {
|
||||
10 : {
|
||||
title : 'Return Caller',
|
||||
globalText : '{userName} has logged in {statValue} times!',
|
||||
text : 'You\'ve logged in {statValue} times!',
|
||||
points : 5,
|
||||
},
|
||||
25 : {
|
||||
title : 'Seems To Like It!',
|
||||
globalText : '{userName} has logged in {statValue} times!',
|
||||
text : 'You\'ve logged in {statValue} 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!',
|
||||
points : 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -189,6 +189,18 @@ const DB_INIT_TABLE = {
|
|||
);`
|
||||
);
|
||||
|
||||
dbs.user.run(
|
||||
`CREATE TABLE IF NOT EXISTS user_achievement (
|
||||
user_id INTEGER NOT NULL,
|
||||
achievement_tag VARCHAR NOT NULL,
|
||||
timestamp DATETIME NOT NULL,
|
||||
match_field VARCHAR NOT NULL,
|
||||
match_value VARCHAR NOT NULL,
|
||||
UNIQUE(user_id, achievement_tag, match_field, match_value),
|
||||
FOREIGN KEY(user_id) REFERENCES user(id) ON DELETE CASCADE
|
||||
);`
|
||||
);
|
||||
|
||||
return cb(null);
|
||||
},
|
||||
|
||||
|
|
|
@ -120,11 +120,14 @@ class StatLog {
|
|||
|
||||
//
|
||||
// User specific stats
|
||||
// These are simply convience methods to the user's properties
|
||||
// These are simply convenience methods to the user's properties
|
||||
//
|
||||
setUserStat(user, statName, statValue, cb) {
|
||||
// note: cb is optional in PersistUserProperty
|
||||
return user.persistProperty(statName, statValue, cb);
|
||||
user.persistProperty(statName, statValue, cb);
|
||||
|
||||
const Events = require('./events.js'); // we need to late load currently
|
||||
return Events.emit(Events.getSystemEvents().UserStatUpdate, { user, statName, statValue } );
|
||||
}
|
||||
|
||||
getUserStat(user, statName) {
|
||||
|
|
|
@ -21,4 +21,5 @@ module.exports = {
|
|||
UserSendMail : 'codes.l33t.enigma.system.user_send_mail',
|
||||
UserRunDoor : 'codes.l33t.enigma.system.user_run_door',
|
||||
UserSendNodeMsg : 'codes.l33t.enigma.system.user_send_node_msg',
|
||||
UserStatUpdate : 'codes.l33t.enigma.system.user_stat_set', // { ..., statName, statValue }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue