From cad538dd51893bcb2f219e4a6204f1bf4caa7c43 Mon Sep 17 00:00:00 2001 From: Alys Date: Tue, 17 May 2016 06:52:56 +1000 Subject: [PATCH] [API v3] add CRON_SAFE_MODE (#7286) * add CRON_SAFE_MODE to example config file, fix some bugs, add an unrelated low-priority TODO * create CRON_SAFE_MODE to disable parts of cron for use after extended outage - fixes https://github.com/HabitRPG/habitrpg/issues/7161 * fix a bug with CRON_SAFE_MODE, remove duplicated code, remove completed TODO comment * fix check for CRON_SAFE_MODE --- config.json.example | 1 + website/server/libs/api-v3/cron.js | 65 ++++++++++++++++-------------- website/server/models/group.js | 6 ++- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/config.json.example b/config.json.example index ca012501bb..35609d1c93 100644 --- a/config.json.example +++ b/config.json.example @@ -9,6 +9,7 @@ "NODE_DB_URI":"mongodb://localhost/habitrpg", "TEST_DB_URI":"mongodb://localhost/habitrpg_test", "NODE_ENV":"development", + "CRON_SAFE_MODE":"false", "SESSION_SECRET":"YOUR SECRET HERE", "ADMIN_EMAIL": "you@example.com", "SMTP_USER":"user@example.com", diff --git a/website/server/libs/api-v3/cron.js b/website/server/libs/api-v3/cron.js index c86dfad2ca..da076b54ce 100644 --- a/website/server/libs/api-v3/cron.js +++ b/website/server/libs/api-v3/cron.js @@ -2,7 +2,9 @@ import moment from 'moment'; import common from '../../../../common/'; import { preenUserHistory } from '../../libs/api-v3/preening'; import _ from 'lodash'; +import nconf from 'nconf'; +const CRON_SAFE_MODE = nconf.get('CRON_SAFE_MODE') === 'true'; const shouldDo = common.shouldDo; const scoreTask = common.ops.scoreTask; // const maxPMs = 200; @@ -68,6 +70,7 @@ function performSleepTasks (user, tasksByType, now) { let thatDay = moment(now).subtract({days: 1}); if (shouldDo(thatDay.toDate(), daily, user.preferences) || completed) { + // TODO also untick checklists if the Daily was due on previous missed days, if two or more days were missed at once -- https://github.com/HabitRPG/habitrpg/pull/7218#issuecomment-219256016 daily.checklist.forEach(box => box.completed = false); } @@ -90,7 +93,7 @@ export function cron (options = {}) { if (user.isSubscribed()) { grantEndOfTheMonthPerks(user, now); - removeTerminatedSubscription(user); + if (!CRON_SAFE_MODE) removeTerminatedSubscription(user); } // User is resting at the inn. @@ -150,31 +153,36 @@ export function cron (options = {}) { } if (scheduleMisses > EvadeTask) { - perfect = false; - - if (task.checklist && task.checklist.length > 0) { // Partially completed checklists dock fewer mana points - let fractionChecked = _.reduce(task.checklist, (m, i) => m + (i.completed ? 1 : 0), 0) / task.checklist.length; - dailyDueUnchecked += 1 - fractionChecked; - dailyChecked += fractionChecked; + // The user did not complete this due Daily (but no penalty if cron is running in safe mode). + if (CRON_SAFE_MODE) { + dailyChecked += 1; // allows full allotment of mp to be gained } else { - dailyDueUnchecked += 1; + perfect = false; + + if (task.checklist && task.checklist.length > 0) { // Partially completed checklists dock fewer mana points + let fractionChecked = _.reduce(task.checklist, (m, i) => m + (i.completed ? 1 : 0), 0) / task.checklist.length; + dailyDueUnchecked += 1 - fractionChecked; + dailyChecked += fractionChecked; + } else { + dailyDueUnchecked += 1; + } + + let delta = scoreTask({ + user, + task, + direction: 'down', + times: multiDaysCountAsOneDay ? 1 : scheduleMisses - EvadeTask, + cron: true, + }); + + // Apply damage from a boss, less damage for Trivial priority (difficulty) + user.party.quest.progress.down += delta * (task.priority < 1 ? task.priority : 1); + // NB: Medium and Hard priorities do not increase damage from boss. This was by accident + // initially, and when we realised, we could not fix it because users are used to + // their Medium and Hard Dailies doing an Easy amount of damage from boss. + // Easy is task.priority = 1. Anything < 1 will be Trivial (0.1) or any future + // setting between Trivial and Easy. } - - let delta = scoreTask({ - user, - task, - direction: 'down', - times: multiDaysCountAsOneDay ? 1 : scheduleMisses - EvadeTask, - cron: true, - }); - - // Apply damage from a boss, less damage for Trivial priority (difficulty) - user.party.quest.progress.down += delta * (task.priority < 1 ? task.priority : 1); - // NB: Medium and Hard priorities do not increase damage from boss. This was by accident - // initially, and when we realised, we could not fix it because users are used to - // their Medium and Hard Dailies doing an Easy amount of damage from boss. - // Easy is task.priority = 1. Anything < 1 will be Trivial (0.1) or any future - // setting between Trivial and Easy. } } @@ -185,7 +193,7 @@ export function cron (options = {}) { task.completed = false; if (completed || scheduleMisses > 0) { - task.checklist.forEach(i => i.completed = false); // TODO this should not happen for grey tasks unless they are completed + task.checklist.forEach(i => i.completed = false); } }); @@ -231,14 +239,9 @@ export function cron (options = {}) { // Add 10 MP, or 10% of max MP if that'd be more. Perform this after Perfect Day for maximum benefit // Adjust for fraction of dailies completed - user.stats.mp += _.max([10, 0.1 * user._statsComputed.maxMP]) * dailyChecked / (dailyDueUnchecked + dailyChecked); - if (user.stats.mp > user._statsComputed.maxMP) user.stats.mp = user._statsComputed.maxMP; - if (dailyDueUnchecked === 0 && dailyChecked === 0) dailyChecked = 1; user.stats.mp += _.max([10, 0.1 * user._statsComputed.maxMP]) * dailyChecked / (dailyDueUnchecked + dailyChecked); - if (user.stats.mp > user._statsComputed.maxMP) { - user.stats.mp = user._statsComputed.maxMP; - } + if (user.stats.mp > user._statsComputed.maxMP) user.stats.mp = user._statsComputed.maxMP; // After all is said and done, progress up user's effect on quest, return those values & reset the user's let progress = user.party.quest.progress; diff --git a/website/server/models/group.js b/website/server/models/group.js index 347079c96a..d22e63cf70 100644 --- a/website/server/models/group.js +++ b/website/server/models/group.js @@ -515,8 +515,10 @@ schema.statics.bossQuest = async function bossQuest (user, progress) { let down = progress.down * quest.boss.str; // multiply by boss strength group.quest.progress.hp -= progress.up; - // TODO Create a party preferred language option so emits like this can be localized - group.sendChat(`\`${user.profile.name} attacks ${quest.boss.name('en')} for ${progress.up.toFixed(1)} damage.\` \`${quest.boss.name('en')} attacks party for ${Math.abs(down).toFixed(1)} damage.\``); + // TODO Create a party preferred language option so emits like this can be localized. Suggestion: Always display the English version too. Or, if English is not displayed to the players, at least include it in a new field in the chat object that's visible in the database - essential for admins when troubleshooting quests! + let playerAttack = `${user.profile.name} attacks ${quest.boss.name('en')} for ${progress.up.toFixed(1)} damage.`; + let bossAttack = nconf.get('CRON_SAFE_MODE') === 'true' ? `${quest.boss.name('en')} did not attack the party because it was asleep while maintenance was happening.` : `${quest.boss.name('en')} attacks party for ${Math.abs(down).toFixed(1)} damage.`; + group.sendChat(`\`${playerAttack}\` \`${bossAttack}\``); // If boss has Rage, increment Rage as well if (quest.boss.rage) {