From d3b078317df9f9c7ce6fd1a41fbd5c2c9643e827 Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Tue, 4 Apr 2023 17:42:02 +0000 Subject: [PATCH 01/10] Utils: Improve and commands --- src/commands/util.ts | 25 +++++++++++++++---------- src/tools.ts | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/commands/util.ts b/src/commands/util.ts index ae6bd2366..c5e9d70b7 100644 --- a/src/commands/util.ts +++ b/src/commands/util.ts @@ -3,6 +3,7 @@ import type { BaseCommandDefinitions } from "../types/command-parser"; import type { CharacterType, ModelGeneration, LocationType, RegionName } from "../types/dex"; import type { IPokemon } from "../types/pokemon-showdown"; +const shinyOption = "shiny"; const RANDOM_GENERATOR_LIMIT = 6; export const commands: BaseCommandDefinitions = { @@ -66,14 +67,9 @@ export const commands: BaseCommandDefinitions = { return this.say("Your timer has been turned off."); } - let time: number; - if (id.length === 1) { - time = parseInt(id) * 60; - } else { - time = parseInt(id); - } - if (isNaN(time) || time > 1800 || time < 5) return this.say("Please enter an amount of time between 5 seconds and 30 minutes."); - time *= 1000; + const time = Tools.fromTimeString(target); + if (isNaN(time) || time > 30 * 60 * 1000 || time < 5) + return this.say("Please enter an amount of time between 5 seconds and 30 minutes."); if (!room.timers) room.timers = {}; if (timerId in room.timers) clearTimeout(room.timers[timerId]); @@ -199,14 +195,23 @@ export const commands: BaseCommandDefinitions = { const gifsOrIcons: string[] = []; const pokemonList: IPokemon[] = []; - for (const name of targets) { + for (let name of targets) { + name = name.trim(); + let shiny: boolean = false; + const names = name.split(" "); + if (names[0] === shinyOption) { + shiny = true; + name = names.slice(1).join(""); + } + if (showIcon && shiny) return this.say("You cannot specify the option shiny with icons."); const pokemon = Dex.getPokemon(name); if (!pokemon) return this.sayError(['invalidPokemon', name]); if (!showIcon && !Dex.hasModelData(pokemon, generation)) { return this.say(pokemon.name + " does not have a" + (isBW ? " BW" : "") + " gif."); } pokemonList.push(pokemon); - gifsOrIcons.push(showIcon ? Dex.getPSPokemonIcon(pokemon) + pokemon.name : Dex.getPokemonModel(pokemon, generation)); + gifsOrIcons.push(showIcon ? Dex.getPSPokemonIcon(pokemon) + pokemon.name : + Dex.getPokemonModel(pokemon, generation, "front", shiny)); } if (!gifsOrIcons.length) return this.say("You must specify at least 1 Pokemon."); diff --git a/src/tools.ts b/src/tools.ts index 472610def..964ddc0f5 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -839,6 +839,24 @@ export class Tools { return parts.slice(0, 3).join("-") + " " + parts.slice(3, human ? 5 : 6).join(":") + (human ? "" + parts[6] : ""); } + fromTimeString(input: string): number { + // detecting "a minute" or something + input = input.toLowerCase().replace(/(?:^| )an? /ig, "1").replace(/[^a-z0-9.:]/g, ""); + let time: number = 0; + const sec = /(\d+(?:\.\d+)?)(?:s(?:ec(?:onds?)?)?)/.exec(input); + if (sec && sec[0] && sec[1] && !Number.isNaN(Number(sec[1]))) { + time += Number(sec[1]) * 1000; + input = input.replace(sec[0], ""); + } + const min = /(\d+(?:\.\d+)?)m(?:in(?:ute?)?s?)?/.exec(input); + if (min && min[0] && min[1] && !Number.isNaN(Number(min[1]))) { + time += Number(min[1]) * 60 * 1000; + } + + if (time < 0) return 0; + return time; + } + /**Converts `input` in milliseconds to a duration string */ toDurationString(input: number, options?: {precision?: number; hhmmss?: boolean, milliseconds?: boolean}): string { const date = new Date(input); From fb32520ed4493712a04098f88138d9f8559190c0 Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Tue, 4 Apr 2023 18:32:40 +0000 Subject: [PATCH 02/10] Add module tests --- src/test/modules/tools.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/test/modules/tools.ts b/src/test/modules/tools.ts index 3f84f9025..86609b8c8 100644 --- a/src/test/modules/tools.ts +++ b/src/test/modules/tools.ts @@ -144,6 +144,29 @@ describe("Tools", () => { assert(!Tools.isFloat('-')); assert(!Tools.isFloat('@')); }); + it('should return proper values from fromTimeString()', () => { + assertStrictEqual(Tools.fromTimeString('1 sec'), 1 * second); + assertStrictEqual(Tools.fromTimeString('2.5 secs'), 2.5 * second); + assertStrictEqual(Tools.fromTimeString('10 second'), 10 * second); + assertStrictEqual(Tools.fromTimeString('1+e7 seconds'), 7 * second); + assertStrictEqual(Tools.fromTimeString('2.5sec'), 2.5 * second); + assertStrictEqual(Tools.fromTimeString('10seconds'), 10 * second); + assertStrictEqual(Tools.fromTimeString('1 min'), 1 * minute); + assertStrictEqual(Tools.fromTimeString('2.5 mins'), 2.5 * minute); + assertStrictEqual(Tools.fromTimeString('10 minute'), 10 * minute); + assertStrictEqual(Tools.fromTimeString('1+e7 minutes'), 7 * minute); + assertStrictEqual(Tools.fromTimeString('2.5min'), 2.5 * minute); + assertStrictEqual(Tools.fromTimeString('10minutes'), 10 * minute); + assertStrictEqual(Tools.fromTimeString('a sec'), 1 * second); + assertStrictEqual(Tools.fromTimeString('a min'), 1 * minute); + assertStrictEqual(Tools.fromTimeString('1min, 1sec'), 1 * minute + 1 * second); + assertStrictEqual(Tools.fromTimeString('5seconds 5min'), 5 * minute + 5 * second); + assertStrictEqual(Tools.fromTimeString('5min5min'), 5 * minute); + assertStrictEqual(Tools.fromTimeString('10minute1sec'), 10 * minute + 1 * second); + assertStrictEqual(Tools.fromTimeString('1hour10sec'), 10 * second); + assertStrictEqual(Tools.fromTimeString('an hour'), 0); + assertStrictEqual(Tools.fromTimeString(''), 0); + }) it('should return proper values from toDurationString()', () => { assertStrictEqual(Tools.toDurationString(second), '1 second'); assertStrictEqual(Tools.toDurationString(2 * second), '2 seconds'); From 521094c849adcd7af0ebaa5d10a06fc0bfd98a53 Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Wed, 5 Apr 2023 03:41:38 +0900 Subject: [PATCH 03/10] `.timer`: Fix typo --- src/commands/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/util.ts b/src/commands/util.ts index c5e9d70b7..9ee5c7a73 100644 --- a/src/commands/util.ts +++ b/src/commands/util.ts @@ -68,7 +68,7 @@ export const commands: BaseCommandDefinitions = { } const time = Tools.fromTimeString(target); - if (isNaN(time) || time > 30 * 60 * 1000 || time < 5) + if (isNaN(time) || time > 30 * 60 * 1000 || time < 5000) return this.say("Please enter an amount of time between 5 seconds and 30 minutes."); if (!room.timers) room.timers = {}; From 581bf63db45d301b7ac6202f35e9af7d8805f80a Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:14:07 +0000 Subject: [PATCH 04/10] Don't use regex --- src/test/modules/tools.ts | 20 +++++++------------- src/tools.ts | 23 ++++++++++++----------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/test/modules/tools.ts b/src/test/modules/tools.ts index 86609b8c8..cdbe8adb8 100644 --- a/src/test/modules/tools.ts +++ b/src/test/modules/tools.ts @@ -146,27 +146,21 @@ describe("Tools", () => { }); it('should return proper values from fromTimeString()', () => { assertStrictEqual(Tools.fromTimeString('1 sec'), 1 * second); - assertStrictEqual(Tools.fromTimeString('2.5 secs'), 2.5 * second); - assertStrictEqual(Tools.fromTimeString('10 second'), 10 * second); - assertStrictEqual(Tools.fromTimeString('1+e7 seconds'), 7 * second); + assertStrictEqual(Tools.fromTimeString('1+e7 seconds'), 1 * second); assertStrictEqual(Tools.fromTimeString('2.5sec'), 2.5 * second); assertStrictEqual(Tools.fromTimeString('10seconds'), 10 * second); assertStrictEqual(Tools.fromTimeString('1 min'), 1 * minute); - assertStrictEqual(Tools.fromTimeString('2.5 mins'), 2.5 * minute); - assertStrictEqual(Tools.fromTimeString('10 minute'), 10 * minute); - assertStrictEqual(Tools.fromTimeString('1+e7 minutes'), 7 * minute); - assertStrictEqual(Tools.fromTimeString('2.5min'), 2.5 * minute); - assertStrictEqual(Tools.fromTimeString('10minutes'), 10 * minute); assertStrictEqual(Tools.fromTimeString('a sec'), 1 * second); assertStrictEqual(Tools.fromTimeString('a min'), 1 * minute); assertStrictEqual(Tools.fromTimeString('1min, 1sec'), 1 * minute + 1 * second); - assertStrictEqual(Tools.fromTimeString('5seconds 5min'), 5 * minute + 5 * second); - assertStrictEqual(Tools.fromTimeString('5min5min'), 5 * minute); - assertStrictEqual(Tools.fromTimeString('10minute1sec'), 10 * minute + 1 * second); - assertStrictEqual(Tools.fromTimeString('1hour10sec'), 10 * second); + assertStrictEqual(Tools.fromTimeString('5seconds, 5min'), 5 * minute + 5 * second); + assertStrictEqual(Tools.fromTimeString('5minand5min,5min'), 15 * minute); + assertStrictEqual(Tools.fromTimeString('10minute,1sec'), 10 * minute + 1 * second); + assertStrictEqual(Tools.fromTimeString('1hour,10sec'), 10 * second); assertStrictEqual(Tools.fromTimeString('an hour'), 0); assertStrictEqual(Tools.fromTimeString(''), 0); - }) + }); + it('should return proper values from toDurationString()', () => { assertStrictEqual(Tools.toDurationString(second), '1 second'); assertStrictEqual(Tools.toDurationString(2 * second), '2 seconds'); diff --git a/src/tools.ts b/src/tools.ts index 964ddc0f5..054adb33a 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -840,19 +840,20 @@ export class Tools { } fromTimeString(input: string): number { - // detecting "a minute" or something - input = input.toLowerCase().replace(/(?:^| )an? /ig, "1").replace(/[^a-z0-9.:]/g, ""); + const targets: string[] = input.split(/,|and/gi).map((str) => this.toId(str)); let time: number = 0; - const sec = /(\d+(?:\.\d+)?)(?:s(?:ec(?:onds?)?)?)/.exec(input); - if (sec && sec[0] && sec[1] && !Number.isNaN(Number(sec[1]))) { - time += Number(sec[1]) * 1000; - input = input.replace(sec[0], ""); + for (const t of targets) { + if (t.includes("sec")) { + const possibleAmount = t.split("sec")[0]!; + const amount = possibleAmount === "a" ? 1 : parseInt(possibleAmount, 10); + if (!Number.isNaN(amount)) time += amount * 1000; + } + if (t.includes("min")) { + const possibleAmount = t.split("min")[0]!; + const amount = possibleAmount === "a" ? 1 : parseInt(possibleAmount, 10); + if (!Number.isNaN(amount)) time += amount * 60 * 1000; + } } - const min = /(\d+(?:\.\d+)?)m(?:in(?:ute?)?s?)?/.exec(input); - if (min && min[0] && min[1] && !Number.isNaN(Number(min[1]))) { - time += Number(min[1]) * 60 * 1000; - } - if (time < 0) return 0; return time; } From e1e156892c3b247ffb1e94b1548dfdc294c6be7d Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:51:57 +0000 Subject: [PATCH 05/10] Fix --- src/test/modules/tools.ts | 4 ++-- src/tools.ts | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/test/modules/tools.ts b/src/test/modules/tools.ts index cdbe8adb8..07b932413 100644 --- a/src/test/modules/tools.ts +++ b/src/test/modules/tools.ts @@ -146,7 +146,7 @@ describe("Tools", () => { }); it('should return proper values from fromTimeString()', () => { assertStrictEqual(Tools.fromTimeString('1 sec'), 1 * second); - assertStrictEqual(Tools.fromTimeString('1+e7 seconds'), 1 * second); + assertStrictEqual(Tools.fromTimeString('1+e7 seconds'), 0); assertStrictEqual(Tools.fromTimeString('2.5sec'), 2.5 * second); assertStrictEqual(Tools.fromTimeString('10seconds'), 10 * second); assertStrictEqual(Tools.fromTimeString('1 min'), 1 * minute); @@ -154,7 +154,7 @@ describe("Tools", () => { assertStrictEqual(Tools.fromTimeString('a min'), 1 * minute); assertStrictEqual(Tools.fromTimeString('1min, 1sec'), 1 * minute + 1 * second); assertStrictEqual(Tools.fromTimeString('5seconds, 5min'), 5 * minute + 5 * second); - assertStrictEqual(Tools.fromTimeString('5minand5min,5min'), 15 * minute); + assertStrictEqual(Tools.fromTimeString('5minand5min,5min'), 10 * minute); assertStrictEqual(Tools.fromTimeString('10minute,1sec'), 10 * minute + 1 * second); assertStrictEqual(Tools.fromTimeString('1hour,10sec'), 10 * second); assertStrictEqual(Tools.fromTimeString('an hour'), 0); diff --git a/src/tools.ts b/src/tools.ts index 054adb33a..f9f6a429d 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -840,18 +840,22 @@ export class Tools { } fromTimeString(input: string): number { - const targets: string[] = input.split(/,|and/gi).map((str) => this.toId(str)); + const targets: string[] = input.split(input.includes("and") ? "and" : ",").map((str) => str.toLowerCase().replaceAll(/[^a-z0-9.]/g, "")); let time: number = 0; for (const t of targets) { if (t.includes("sec")) { const possibleAmount = t.split("sec")[0]!; - const amount = possibleAmount === "a" ? 1 : parseInt(possibleAmount, 10); - if (!Number.isNaN(amount)) time += amount * 1000; + if (!possibleAmount.includes("e")) { + const amount = possibleAmount === "a" ? 1 : parseFloat(possibleAmount, 10); + if (!Number.isNaN(amount)) time += amount * 1000; + } } if (t.includes("min")) { const possibleAmount = t.split("min")[0]!; - const amount = possibleAmount === "a" ? 1 : parseInt(possibleAmount, 10); - if (!Number.isNaN(amount)) time += amount * 60 * 1000; + if (!possibleAmount.includes("e")) { + const amount = possibleAmount === "a" ? 1 : parseFloat(possibleAmount, 10); + if (!Number.isNaN(amount)) time += amount * 60 * 1000; + } } } if (time < 0) return 0; From 47a2475d6422f1d19863a8ee77b1c0fe67bfd53d Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:54:37 +0000 Subject: [PATCH 06/10] Lint --- src/tools.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools.ts b/src/tools.ts index f9f6a429d..b2b52e0d8 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -840,7 +840,8 @@ export class Tools { } fromTimeString(input: string): number { - const targets: string[] = input.split(input.includes("and") ? "and" : ",").map((str) => str.toLowerCase().replaceAll(/[^a-z0-9.]/g, "")); + const targets: string[] = input.split(input.includes("and") ? "and" : ",") + .map((str) => str.toLowerCase().replaceAll(/[^a-z0-9.]/g, "")); let time: number = 0; for (const t of targets) { if (t.includes("sec")) { From 749391fe59eecc7ecbc73b083cc1350be8993692 Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:57:57 +0000 Subject: [PATCH 07/10] tsc --- src/tools.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools.ts b/src/tools.ts index b2b52e0d8..f7d371b15 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -847,14 +847,14 @@ export class Tools { if (t.includes("sec")) { const possibleAmount = t.split("sec")[0]!; if (!possibleAmount.includes("e")) { - const amount = possibleAmount === "a" ? 1 : parseFloat(possibleAmount, 10); + const amount = possibleAmount === "a" ? 1 : parseFloat(possibleAmount); if (!Number.isNaN(amount)) time += amount * 1000; } } if (t.includes("min")) { const possibleAmount = t.split("min")[0]!; if (!possibleAmount.includes("e")) { - const amount = possibleAmount === "a" ? 1 : parseFloat(possibleAmount, 10); + const amount = possibleAmount === "a" ? 1 : parseFloat(possibleAmount); if (!Number.isNaN(amount)) time += amount * 60 * 1000; } } From a14334f817d1fbdee13bb5ecff2eacae04ad1219 Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Sat, 8 Apr 2023 18:37:34 +0000 Subject: [PATCH 08/10] Improve host timers --- src/commands/user-hosted-game.ts | 20 ++++++-------------- src/room-game-user-hosted.ts | 4 ++-- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/commands/user-hosted-game.ts b/src/commands/user-hosted-game.ts index b269d3c63..e24302539 100644 --- a/src/commands/user-hosted-game.ts +++ b/src/commands/user-hosted-game.ts @@ -712,16 +712,8 @@ export const commands: BaseCommandDefinitions = { time *= 60 * 1000; } } else { - time = parseFloat(targets[0] ? targets[0].trim() : ""); - if (secondsArguments.includes(Tools.toId(targets[1]))) { - if (isNaN(time) || time > 60 || time < 3) return this.say("Please enter an amount of seconds between 3 and 60."); - time *= 1000; - } else { - if (isNaN(time) || time < 1) { - return this.say("Please enter a valid amount of minutes (add `` seconds`` to use seconds)."); - } - time *= 60 * 1000; - } + time = Tools.fromTimeString(target); + if (Number.isNaN(time) || time < 3000) this.say("Please enter an amount of seconds more than 3 seconds."); } if (now + time > gameRoom.userHostedGame.endTime) { @@ -759,10 +751,10 @@ export const commands: BaseCommandDefinitions = { return this.say("The game start timer has been turned off."); } - const minutes = parseInt(target.trim()); - if (isNaN(minutes) || minutes < 1 || minutes > 4) return this.say("You must specify a number of minutes between 1 and 4."); - room.userHostedGame.setStartTimer(minutes); - this.say("The game will start in " + minutes + " minutes."); + const time = Tools.fromTimeString(target) + if (isNaN(time) || time < 60 * 1000 || time > 60 * 4000) return this.say("You must specify time between 1 minute and 4 minutes."); + room.userHostedGame.setStartTimer(time); + this.say("The game will start in " + Tools.toDurationString(time) + "."); }, chatOnly: true, aliases: ['sgtimer'], diff --git a/src/room-game-user-hosted.ts b/src/room-game-user-hosted.ts index 35f87f00c..be62040cb 100644 --- a/src/room-game-user-hosted.ts +++ b/src/room-game-user-hosted.ts @@ -212,9 +212,9 @@ export class UserHostedGame extends Game { this.parseCommand(this.subHostName || this.hostName, command, target); } - setStartTimer(minutes: number): void { + setStartTimer(time: number): void { if (this.startTimer) clearTimeout(this.startTimer); - this.startTimer = setTimeout(() => this.useHostCommand('startgame'), minutes * 60 * 1000); + this.startTimer = setTimeout(() => this.useHostCommand('startgame'), time); } // Players From b8e0ff520a60f855292913380194af9cf7b816b1 Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Sun, 9 Apr 2023 03:41:04 +0900 Subject: [PATCH 09/10] Fix error --- src/commands/user-hosted-game.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/user-hosted-game.ts b/src/commands/user-hosted-game.ts index e24302539..c6f81d99b 100644 --- a/src/commands/user-hosted-game.ts +++ b/src/commands/user-hosted-game.ts @@ -751,8 +751,9 @@ export const commands: BaseCommandDefinitions = { return this.say("The game start timer has been turned off."); } - const time = Tools.fromTimeString(target) - if (isNaN(time) || time < 60 * 1000 || time > 60 * 4000) return this.say("You must specify time between 1 minute and 4 minutes."); + const time = Tools.fromTimeString(target); + if (isNaN(time) || time < 60 * 1000 || time > 60 * 4000) + return this.say("You must specify time between 1 minute and 4 minutes."); room.userHostedGame.setStartTimer(time); this.say("The game will start in " + Tools.toDurationString(time) + "."); }, From 2e1f6426cf619c1f4cac1d4d0910b04831d52ada Mon Sep 17 00:00:00 2001 From: Dirain1700 <86363603+Dirain1700@users.noreply.github.com> Date: Sat, 27 May 2023 16:05:31 +0000 Subject: [PATCH 10/10] Improve timers more --- src/commands/user-hosted-game.ts | 7 +++++-- src/commands/util.ts | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/commands/user-hosted-game.ts b/src/commands/user-hosted-game.ts index c6f81d99b..a5f66bc0e 100644 --- a/src/commands/user-hosted-game.ts +++ b/src/commands/user-hosted-game.ts @@ -713,6 +713,7 @@ export const commands: BaseCommandDefinitions = { } } else { time = Tools.fromTimeString(target); + if (!time) time = Tools.fromTimeString(target + (target.trim().length === 1 ? "min" : "sec")); if (Number.isNaN(time) || time < 3000) this.say("Please enter an amount of seconds more than 3 seconds."); } @@ -751,9 +752,11 @@ export const commands: BaseCommandDefinitions = { return this.say("The game start timer has been turned off."); } - const time = Tools.fromTimeString(target); - if (isNaN(time) || time < 60 * 1000 || time > 60 * 4000) + let time = Tools.fromTimeString(target); + if (!time) time = Tools.fromTimeString(id + (id.length === 1 ? "min" : "sec")); + if (isNaN(time) || time < 60 * 1000 || time > 60 * 4000) { return this.say("You must specify time between 1 minute and 4 minutes."); + } room.userHostedGame.setStartTimer(time); this.say("The game will start in " + Tools.toDurationString(time) + "."); }, diff --git a/src/commands/util.ts b/src/commands/util.ts index 9ee5c7a73..81c3f73e2 100644 --- a/src/commands/util.ts +++ b/src/commands/util.ts @@ -67,7 +67,8 @@ export const commands: BaseCommandDefinitions = { return this.say("Your timer has been turned off."); } - const time = Tools.fromTimeString(target); + let time = Tools.fromTimeString(target); + if (!time) time = Tools.fromTimeString(target + (target.trim().length === 1 ? "min" : "sec")); if (isNaN(time) || time > 30 * 60 * 1000 || time < 5000) return this.say("Please enter an amount of time between 5 seconds and 30 minutes.");