+ ACS: AC for achievement count check

+ ACS: AP for achievement point check
+ User minutes used on the system are now tracked
+ MCI: TO for total time spent online system (friendly format)
* Fix up a couple ACS bugs with |value|
* Fix formatting of achievement text
+ Add more achievements
* Fix achievement duration formatting
This commit is contained in:
Bryan Ashby 2019-01-10 20:34:52 -07:00
parent 091a9ae2c7
commit 2788c37492
12 changed files with 149 additions and 27 deletions

View file

@ -406,19 +406,23 @@ class Achievements {
getFormattedTextFor(info, textType, defaultSgr = '|07') {
const themeDefaults = _.get(info.client.currentTheme, 'achievements.defaults', {});
const defSgr = themeDefaults[`${textType}SGR`] || defaultSgr;
const textTypeSgr = themeDefaults[`${textType}SGR`] || defaultSgr;
const wrap = (fieldName, value) => {
return `${themeDefaults[fieldName] || defSgr}${value}${defSgr}`;
const formatObj = this.getFormatObject(info);
const wrap = (input) => {
const re = new RegExp(`{(${Object.keys(formatObj).join('|')})([^}]*)}`, 'g');
return input.replace(re, (m, formatVar, formatOpts) => {
const varSgr = themeDefaults[`${formatVar}SGR`] || textTypeSgr;
let r = `${varSgr}{${formatVar}`;
if(formatOpts) {
r += formatOpts;
}
return `${r}}${textTypeSgr}`;
});
};
let formatObj = this.getFormatObject(info);
formatObj = _.reduce(formatObj, (out, v, k) => {
out[k] = wrap(k, v);
return out;
}, {});
return stringFormat(`${defSgr}${info.details[textType]}`, formatObj);
return stringFormat(`${textTypeSgr}${wrap(info.details[textType])}`, formatObj);
}
createAchievementInterruptItems(info, cb) {

View file

@ -1004,7 +1004,7 @@ function peg$parse(input, options) {
TW : function termWidth() {
return !isNaN(value) && _.get(client, 'term.termWidth', 0) >= value;
},
ID : function isUserId(value) {
ID : function isUserId() {
if(!user) {
return false;
}
@ -1024,6 +1024,20 @@ function peg$parse(input, options) {
const midnight = now.clone().startOf('day')
const minutesPastMidnight = now.diff(midnight, 'minutes');
return !isNaN(value) && minutesPastMidnight >= value;
},
AC : function achievementCount() {
if(!user) {
return false;
}
const count = user.getPropertyAsNumber(UserProps.AchievementTotalCount) || 0;
return !isNan(value) && points >= value;
},
AP : function achievementPoints() {
if(!user) {
return false;
}
const points = user.getPropertyAsNumber(UserProps.AchievementTotalPoints) || 0;
return !isNan(value) && points >= value;
}
}[acsCode](value);
} catch (e) {

View file

@ -23,6 +23,8 @@
// General
// * http://en.wikipedia.org/wiki/ANSI_escape_code
// * http://www.inwap.com/pdp10/ansicode.txt
// * Excellent information with many standards covered (for hterm):
// https://chromium.googlesource.com/apps/libapps/+/master/hterm/doc/ControlSequences.md
//
// Other Implementations
// * https://github.com/chjj/term.js/blob/master/src/term.js

View file

@ -40,6 +40,7 @@ const MenuStack = require('./menu_stack.js');
const ACS = require('./acs.js');
const Events = require('./events.js');
const UserInterruptQueue = require('./user_interrupt_queue.js');
const UserProps = require('./user_property.js');
// deps
const stream = require('stream');
@ -442,13 +443,36 @@ Client.prototype.startIdleMonitor = function() {
//
// Every 1m, check for idle.
// We also update minutes spent online the system here,
// if we have a authenticated user.
//
this.idleCheck = setInterval( () => {
const nowMs = Date.now();
const idleLogoutSeconds = this.user.isAuthenticated() ?
Config().users.idleLogoutSeconds :
Config().users.preAuthIdleLogoutSeconds;
let idleLogoutSeconds;
if(this.user.isAuthenticated()) {
idleLogoutSeconds = Config().users.idleLogoutSeconds;
//
// We don't really want to be firing off an event every 1m for
// every user, but want at least some updates for various things
// such as achievements. Send off every 5m.
//
const minOnline = this.user.incrementProperty(UserProps.MinutesOnlineTotalCount, 1);
if(0 === (minOnline % 5)) {
Events.emit(
Events.getSystemEvents().UserStatIncrement,
{
user : this.user,
statName : UserProps.MinutesOnlineTotalCount,
statIncrementBy : 1,
statValue : minOnline
}
);
}
} else {
idleLogoutSeconds = Config().users.preAuthIdleLogoutSeconds;
}
if(nowMs - this.lastKeyPressMs >= (idleLogoutSeconds * 1000)) {
this.emit('idle timeout');
@ -473,6 +497,14 @@ Client.prototype.end = function () {
currentModule.leave();
}
// persist time online for authenticated users
if(this.user.isAuthenticated()) {
this.user.persistProperty(
UserProps.MinutesOnlineTotalCount,
this.user.getProperty(UserProps.MinutesOnlineTotalCount)
);
}
this.stopIdleMonitor();
try {

View file

@ -160,6 +160,10 @@ const PREDEFINED_MCI_GENERATORS = {
const minutes = client.user.properties[UserProps.DoorRunTotalMinutes] || 0;
return moment.duration(minutes, 'minutes').humanize();
},
TO : function friendlyTotalTimeOnSystem(client) {
const minutes = client.user.properties[UserProps.MinutesOnlineTotalCount] || 0;
return moment.duration(minutes, 'minutes').humanize();
},
//
// Date/Time

View file

@ -443,6 +443,22 @@ module.exports = class User {
);
}
setProperty(propName, propValue) {
this.properties[propName] = propValue;
}
incrementProperty(propName, incrementBy) {
incrementBy = incrementBy || 1;
let newValue = parseInt(this.getProperty(propName));
if(newValue) {
newValue += incrementBy;
} else {
newValue = incrementBy;
}
this.setProperty(propName, newValue);
return newValue;
}
getProperty(propName) {
return this.properties[propName];
}

View file

@ -55,5 +55,7 @@ module.exports = {
AchievementTotalCount : 'achievement_total_count',
AchievementTotalPoints : 'achievement_total_points',
MinutesOnlineTotalCount : 'minutes_online_total_count',
};