From 25ec1c54e7533d03c378b8b3a310f2a7d30f38de Mon Sep 17 00:00:00 2001 From: Corey <45918935+corey-b@users.noreply.github.com> Date: Mon, 23 Aug 2021 10:07:13 -0400 Subject: [PATCH] Auto-assigning challenge roles for discord (corey <-- real) (#1751) * sending bot command to db * verifying challenge completion * added requirements Co-authored-by: Corey --- backend/api/controllers/result.js | 4 ++ backend/dao/bot.js | 4 ++ src/js/challenge-controller.js | 110 +++++++++++++++++++++++++++++- src/js/test/test-logic.js | 3 + static/challenges/_list.json | 55 +++++++++++++-- 5 files changed, 169 insertions(+), 7 deletions(-) diff --git a/backend/api/controllers/result.js b/backend/api/controllers/result.js index 5848932ab..5acaaaf33 100644 --- a/backend/api/controllers/result.js +++ b/backend/api/controllers/result.js @@ -177,6 +177,10 @@ class ResultController { } } + if (result.challenge && user.discordId) { + BotDAO.awardChallenge(user.discordId, result.challenge); + } + let tt = 0; let afk = result.afkDuration; if (afk == undefined) { diff --git a/backend/dao/bot.js b/backend/dao/bot.js index 1182aad98..b1b07726d 100644 --- a/backend/dao/bot.js +++ b/backend/dao/bot.js @@ -19,6 +19,10 @@ class BotDAO { return await addCommand("linkDiscord", [discordId, uid]); } + static async awardChallenge(discordId, challengeName) { + return await addCommand("awardChallenge", [discordId, challengeName]); + } + // static async announceLbUpdate(discordId, pos, lb, wpm, raw, acc, con) { // return await addCommand("sayLbUpdate", [ // discordId, diff --git a/src/js/challenge-controller.js b/src/js/challenge-controller.js index 8deb30ec2..8f0ced1e7 100644 --- a/src/js/challenge-controller.js +++ b/src/js/challenge-controller.js @@ -1,10 +1,10 @@ import * as Misc from "./misc"; import * as Notifications from "./notifications"; -import * as UpdateConfig from "./config"; import * as ManualRestart from "./manual-restart-tracker"; import * as CustomText from "./custom-text"; import * as TestLogic from "./test-logic"; import * as Funbox from "./funbox"; +import Config, * as UpdateConfig from "./config"; export let active = null; @@ -15,6 +15,114 @@ export function clearActive() { } } +export function verify(result) { + if (active) { + let afk = (result.afkDuration / result.testDuration) * 100; + + if (afk > 10) { + Notifications.add(`Challenge failed: AFK time is greater than 10%`, 0); + return null; + } + + if (!active.requirements) { + Notifications.add(`${active.display} challenge passed!`, 1); + return active.name; + } else { + let requirementsMet = true; + let failReasons = []; + for (let requirementType in active.requirements) { + if (requirementsMet == false) return; + let requirementValue = active.requirements[requirementType]; + if (requirementType == "wpm") { + let wpmMode = Object.keys(requirementValue)[0]; + if (wpmMode == "exact") { + if (Math.round(result.wpm) != requirementValue.exact) { + requirementsMet = false; + failReasons.push(`WPM not ${requirementValue.exact}`); + } + } else if (wpmMode == "min") { + if (result.wpm < requirementValue.min) { + requirementsMet = false; + failReasons.push(`WPM below ${requirementValue.min}`); + } + } + } else if (requirementType == "acc") { + let accMode = Object.keys(requirementValue)[0]; + if (accMode == "exact") { + if (Math.round(result.acc) != requirementValue.exact) { + requirementsMet = false; + failReasons.push(`Accuracy not ${requirementValue.exact}`); + } + } else if (accMode == "min") { + if (result.acc < requirementValue.min) { + requirementsMet = false; + failReasons.push(`Accuracy below ${requirementValue.min}`); + } + } + } else if (requirementType == "afk") { + let afkMode = Object.keys(requirementValue)[0]; + if (afkMode == "max") { + if (Math.round(afk) > requirementValue.max) { + requirementsMet = false; + failReasons.push(`AFK percentage above ${requirementValue.max}`); + } + } + } else if (requirementType == "time") { + let timeMode = Object.keys(requirementValue)[0]; + if (timeMode == "min") { + if (Math.round(result.testDuration) < requirementValue.min) { + requirementsMet = false; + failReasons.push(`Test time below ${requirementValue.min}`); + } + } + } else if (requirementType == "funbox") { + let funboxMode = requirementValue[0]; + if (funboxMode != result.funbox) { + requirementsMet = false; + failReasons.push(`${funboxMode} funbox not active`); + } + } else if (requirementType == "raw") { + let rawMode = Object.keys(requirementValue)[0]; + if (rawMode == "exact") { + if (Math.round(result.rawWpm) != requirementValue.exact) { + requirementsMet = false; + failReasons.push(`Raw WPM not ${requirementValue.exact}`); + } + } + } else if (requirementType == "con") { + let conMode = Object.keys(requirementValue)[0]; + if (conMode == "exact") { + if (Math.round(result.consistency) != requirementValue.exact) { + requirementsMet = false; + failReasons.push(`Consistency not ${requirementValue.exact}`); + } + } + } else if (requirementType == "config") { + for (let configKey in requirementValue) { + let configValue = requirementValue[configKey]; + if (Config[configKey] != configValue) { + requirementsMet = false; + failReasons.push(`${configKey} not set to ${configValue}`); + } + } + } + } + if (requirementsMet) { + Notifications.add(`${active.display} challenge passed!`, 1); + return active.name; + } else { + Notifications.add( + `${active.display} challenge failed: ${failReasons.join(", ")}`, + 0 + ); + return null; + } + } + } else { + return null; + } +} + export async function setup(challengeName) { let list = await Misc.getChallengeList(); let challenge = list.filter((c) => c.name === challengeName)[0]; diff --git a/src/js/test/test-logic.js b/src/js/test/test-logic.js index bc2e68521..e45bfa03a 100644 --- a/src/js/test/test-logic.js +++ b/src/js/test/test-logic.js @@ -34,6 +34,7 @@ import * as Poetry from "./poetry.js"; import * as TodayTracker from "./today-tracker"; import * as WeakSpot from "./weak-spot"; import * as Wordset from "./wordset"; +import * as ChallengeContoller from "./challenge-controller"; let glarsesMode = false; @@ -1534,6 +1535,8 @@ export async function finish(difficultyFailed = false) { customText: cdata, }; + completedEvent.challenge = ChallengeContoller.verify(completedEvent); + if (Config.mode !== "custom") { delete completedEvent.CustomText; } diff --git a/static/challenges/_list.json b/static/challenges/_list.json index 1540deca3..ab8b7ab7c 100644 --- a/static/challenges/_list.json +++ b/static/challenges/_list.json @@ -4,39 +4,81 @@ "display": "One Hour Warrior", "autoRole": true, "type": "customTime", - "parameters": [3600] + "parameters": [3600], + "requirements" : { + "time": { + "min": 3600 + } + } } ,{ "name": "doubleDown", "display": "Double Down", "autoRole": true, "type": "customTime", - "parameters": [7200] + "parameters": [7200], + "requirements" : { + "time": { + "min": 7200 + } + } + } + ,{ + "name": "tripleTrouble", + "display": "Triple Trouble", + "autoRole": true, + "type": "customTime", + "parameters": [10800], + "requirements" : { + "time": { + "min": 10800 + } + } } ,{ "name": "quad", "display": "Quaaaaad", "autoRole": true, "type": "customTime", - "parameters": [14400] + "parameters": [14400], + "requirements" : { + "time": { + "min": 14400 + } + } } ,{ "name": "8Ball", "display": "8 Ball", "type": "customTime", - "parameters": [28800] + "parameters": [28800], + "requirements" : { + "time": { + "min": 28800 + } + } } ,{ "name": "theBig12", "display": "The Big 12", "type": "customTime", - "parameters": [43200] + "parameters": [43200], + "requirements" : { + "time": { + "min": 43200 + } + } } ,{ "name": "1Day", "display": "1 Day", "type": "customTime", - "parameters": [86400] + "parameters": [86400], + "requirements" : { + "time": { + "min": 86400 + } + } } ,{ "name": "trueSimp", @@ -536,6 +578,7 @@ ,{ "name": "69", "display": "6969696969", + "autoRole": true, "type": "customTime", "parameters": [69], "message": "You need to achieve 69 wpm, 69 raw, 69% accuracy and 69% consistency.",