mirror of
				https://github.com/keanuplayz/TravBot-v3.git
				synced 2024-08-15 02:33:12 +00:00 
			
		
		
		
	Implemented various ideas from backlog
This commit is contained in:
		
							parent
							
								
									dd6f04fb25
								
							
						
					
					
						commit
						20fb2135c7
					
				
					 16 changed files with 322 additions and 64 deletions
				
			
		
							
								
								
									
										10
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
									
										
									
									
									
								
							|  | @ -1,3 +1,13 @@ | |||
| # ??? | ||||
| - `vaporwave`: Transforms input into full-width text | ||||
| - `eco post`: A play on `eco get` | ||||
| - `admin set prefix <prefix> (<@bot>)`: Allows you to target a bot when setting a prefix if two bots have conflicting prefixes | ||||
| - `party`: Sets the bot's status to streaming with a certain URL | ||||
| - `eco award`: Awards users with Mons, only accessible by that person | ||||
| - `thonk`: A result can now be discarded if the person who called the command reacts with ❌ | ||||
| - `scanemotes forcereset`: Removes the cooldown on `scanemotes`, only accessible by bot support and up | ||||
| - `urban`: Bug fixes | ||||
| 
 | ||||
| # 3.2.0 - Internal refactor, more subcommand types, and more command type guards (2021-??-??) | ||||
| - The custom logger changed: `$.log` no longer exists, it's just `console.log`. Now you don't have to do `import $ from "../core/lib"` at the top of every file that uses the custom logger. | ||||
| - Utility functions are no longer attached to the command menu. Stuff like `$.paginate()` and `$(5).pluralise()` instead need to be imported and used as regular functions. | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ import {Command, NamedCommand, callMemberByUsername} from "../../core"; | |||
| import {isAuthorized, getMoneyEmbed} from "./modules/eco-utils"; | ||||
| import {DailyCommand, PayCommand, GuildCommand, LeaderboardCommand} from "./modules/eco-core"; | ||||
| import {BuyCommand, ShopCommand} from "./modules/eco-shop"; | ||||
| import {MondayCommand} from "./modules/eco-extras"; | ||||
| import {MondayCommand, AwardCommand} from "./modules/eco-extras"; | ||||
| import {BetCommand} from "./modules/eco-bet"; | ||||
| 
 | ||||
| export default new NamedCommand({ | ||||
|  | @ -18,7 +18,12 @@ export default new NamedCommand({ | |||
|         buy: BuyCommand, | ||||
|         shop: ShopCommand, | ||||
|         monday: MondayCommand, | ||||
|         bet: BetCommand | ||||
|         bet: BetCommand, | ||||
|         award: AwardCommand, | ||||
|         post: new NamedCommand({ | ||||
|             description: "A play on `eco get`", | ||||
|             run: "`405 Method Not Allowed`" | ||||
|         }) | ||||
|     }, | ||||
|     id: "user", | ||||
|     user: new Command({ | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| import {Command, NamedCommand} from "../../../core"; | ||||
| import {Storage} from "../../../structures"; | ||||
| import {isAuthorized, getMoneyEmbed} from "./eco-utils"; | ||||
| import {User} from "discord.js"; | ||||
| import {pluralise} from "../../../lib"; | ||||
| 
 | ||||
| const WEEKDAY = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; | ||||
| 
 | ||||
|  | @ -32,3 +34,45 @@ export const MondayCommand = new NamedCommand({ | |||
|         } | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| export const AwardCommand = new NamedCommand({ | ||||
|     description: "Only usable by Mon, awards one or a specified amount of Mons to the user.", | ||||
|     usage: "<user> (<amount>)", | ||||
|     aliases: ["give"], | ||||
|     run: "You need to specify a user!", | ||||
|     user: new Command({ | ||||
|         async run({message, channel, guild, author, member, client, args}) { | ||||
|             if (author.id === "394808963356688394" || IS_DEV_MODE) { | ||||
|                 const target = args[0] as User; | ||||
|                 const user = Storage.getUser(target.id); | ||||
|                 user.money++; | ||||
|                 Storage.save(); | ||||
|                 channel.send(`1 Mon given to ${target.username}.`, getMoneyEmbed(target)); | ||||
|             } else { | ||||
|                 channel.send("This command is restricted to the bean."); | ||||
|             } | ||||
|         }, | ||||
|         number: new Command({ | ||||
|             async run({message, channel, guild, author, member, client, args}) { | ||||
|                 if (author.id === "394808963356688394" || IS_DEV_MODE) { | ||||
|                     const target = args[0] as User; | ||||
|                     const amount = Math.floor(args[1]); | ||||
| 
 | ||||
|                     if (amount > 0) { | ||||
|                         const user = Storage.getUser(target.id); | ||||
|                         user.money += amount; | ||||
|                         Storage.save(); | ||||
|                         channel.send( | ||||
|                             `${pluralise(amount, "Mon", "s")} given to ${target.username}.`, | ||||
|                             getMoneyEmbed(target) | ||||
|                         ); | ||||
|                     } else { | ||||
|                         channel.send("You need to enter a number greater than 0."); | ||||
|                     } | ||||
|                 } else { | ||||
|                     channel.send("This command is restricted to the bean."); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|     }) | ||||
| }); | ||||
|  |  | |||
							
								
								
									
										13
									
								
								src/commands/fun/party.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/commands/fun/party.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| import {Command, NamedCommand} from "../../core"; | ||||
| 
 | ||||
| export default new NamedCommand({ | ||||
|     description: "Initiates a celebratory stream from the bot.", | ||||
|     async run({message, channel, guild, author, member, client, args}) { | ||||
|         channel.send("This calls for a celebration!"); | ||||
|         client.user!.setActivity({ | ||||
|             type: "STREAMING", | ||||
|             url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", | ||||
|             name: "Celebration!" | ||||
|         }); | ||||
|     } | ||||
| }); | ||||
|  | @ -36,6 +36,13 @@ export default new NamedCommand({ | |||
|     usage: "thonk ([text])", | ||||
|     async run({message, channel, guild, author, member, client, args}) { | ||||
|         if (args.length > 0) phrase = args.join(" "); | ||||
|         channel.send(transform(phrase)); | ||||
|         const msg = await channel.send(transform(phrase)); | ||||
|         msg.createReactionCollector( | ||||
|             (reaction, user) => { | ||||
|                 if (user.id === author.id && reaction.emoji.name === "❌") msg.delete(); | ||||
|                 return false; | ||||
|             }, | ||||
|             {time: 60000} | ||||
|         ); | ||||
|     } | ||||
| }); | ||||
|  |  | |||
|  | @ -1,27 +1,31 @@ | |||
| import {Command, NamedCommand} from "../../core"; | ||||
| import {MessageEmbed} from "discord.js"; | ||||
| // Anycasting Alert
 | ||||
| const urban = require("relevant-urban"); | ||||
| import urban from "relevant-urban"; | ||||
| 
 | ||||
| export default new NamedCommand({ | ||||
|     description: "Gives you a definition of the inputted word.", | ||||
|     run: "Please input a word.", | ||||
|     any: new Command({ | ||||
|         async run({message, channel, guild, author, member, client, args}) { | ||||
|         if (!args[0]) { | ||||
|             channel.send("Please input a word."); | ||||
|         } | ||||
|         const res = await urban(args.join(" ")).catch((e: Error) => { | ||||
|             return channel.send("Sorry, that word was not found."); | ||||
|         }); | ||||
|             // [Bug Fix]: Use encodeURIComponent() when emojis are used: "TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters"
 | ||||
|             urban(encodeURIComponent(args.join(" "))) | ||||
|                 .then((res) => { | ||||
|                     const embed = new MessageEmbed() | ||||
|                         .setColor(0x1d2439) | ||||
|                         .setTitle(res.word) | ||||
|                         .setURL(res.urbanURL) | ||||
|                         .setDescription(`**Definition:**\n*${res.definition}*\n\n**Example:**\n*${res.example}*`) | ||||
|             .addField("Author", res.author, true) | ||||
|                         // [Bug Fix] When an embed field is empty (if the author field is missing, like the top entry for "british"): "RangeError [EMBED_FIELD_VALUE]: MessageEmbed field values may not be empty."
 | ||||
|                         .addField("Author", res.author || "N/A", true) | ||||
|                         .addField("Rating", `**\`Upvotes: ${res.thumbsUp} | Downvotes: ${res.thumbsDown}\`**`); | ||||
|         if (res.tags.length > 0 && res.tags.join(" ").length < 1024) { | ||||
|                     if (res.tags && res.tags.length > 0 && res.tags.join(" ").length < 1024) | ||||
|                         embed.addField("Tags", res.tags.join(", "), true); | ||||
|         } | ||||
| 
 | ||||
|                     channel.send(embed); | ||||
|                 }) | ||||
|                 .catch(() => { | ||||
|                     channel.send("Sorry, that word was not found."); | ||||
|                 }); | ||||
|         } | ||||
|     }) | ||||
| }); | ||||
|  |  | |||
							
								
								
									
										34
									
								
								src/commands/fun/vaporwave.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/commands/fun/vaporwave.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| import {Command, NamedCommand} from "../../core"; | ||||
| 
 | ||||
| const vaporwave = (() => { | ||||
|     const map = new Map<string, string>(); | ||||
|     const vaporwave = | ||||
|         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!"#$%&'()*+,-./0123456789:;<=>?@[\]^_`{|}~ "; | ||||
|     const normal = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`{|}~ "; | ||||
|     if (vaporwave.length !== normal.length) console.error("Vaporwave text failed to load properly!"); | ||||
|     for (let i = 0; i < vaporwave.length; i++) map.set(normal[i], vaporwave[i]); | ||||
|     return map; | ||||
| })(); | ||||
| 
 | ||||
| function getVaporwaveText(text: string): string { | ||||
|     let output = ""; | ||||
| 
 | ||||
|     for (const c of text) { | ||||
|         const transformed = vaporwave.get(c); | ||||
|         if (transformed) output += transformed; | ||||
|     } | ||||
| 
 | ||||
|     return output; | ||||
| } | ||||
| 
 | ||||
| export default new NamedCommand({ | ||||
|     description: "Transforms your text into vaporwave.", | ||||
|     run: "You need to enter some text!", | ||||
|     any: new Command({ | ||||
|         async run({message, channel, guild, author, member, client, args}) { | ||||
|             const text = getVaporwaveText(args.join(" ")); | ||||
|             if (text !== "") channel.send(text); | ||||
|             else channel.send("Make sure to enter at least one valid character."); | ||||
|         } | ||||
|     }) | ||||
| }); | ||||
|  | @ -1,19 +1,20 @@ | |||
| import {Command, NamedCommand} from "../../core"; | ||||
| import {MessageEmbed} from "discord.js"; | ||||
| // Anycasting Alert
 | ||||
| const weather = require("weather-js"); | ||||
| import {find} from "weather-js"; | ||||
| 
 | ||||
| export default new NamedCommand({ | ||||
|     description: "Shows weather info of specified location.", | ||||
|     run: "You need to provide a city.", | ||||
|     any: new Command({ | ||||
|         async run({message, channel, guild, author, member, client, args}) { | ||||
|         if (args.length == 0) return channel.send("You need to provide a city."); | ||||
|         return weather.find( | ||||
|             find( | ||||
|                 { | ||||
|                     search: args.join(" "), | ||||
|                     degreeType: "C" | ||||
|                 }, | ||||
|             function (err: any, result: any) { | ||||
|                 if (err) channel.send(err); | ||||
|                 function (error, result) { | ||||
|                     if (error) return channel.send(error.toString()); | ||||
|                     if (result.length === 0) return channel.send("No city found by that name."); | ||||
|                     var current = result[0].current; | ||||
|                     var location = result[0].location; | ||||
|                     const embed = new MessageEmbed() | ||||
|  | @ -27,10 +28,11 @@ export default new NamedCommand({ | |||
|                         .addField("Feels like", `${current.feelslike} Degrees`, true) | ||||
|                         .addField("Winds", current.winddisplay, true) | ||||
|                         .addField("Humidity", `${current.humidity}%`, true); | ||||
|                 channel.send({ | ||||
|                     return channel.send({ | ||||
|                         embed | ||||
|                     }); | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
|     }) | ||||
| }); | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import {Command, NamedCommand, botHasPermission, getPermissionLevel, getPermissionName, CHANNEL_TYPE} from "../../core"; | ||||
| import {clean} from "../../lib"; | ||||
| import {Config, Storage} from "../../structures"; | ||||
| import {Permissions, TextChannel} from "discord.js"; | ||||
| import {Permissions, TextChannel, User} from "discord.js"; | ||||
| import {logs} from "../../modules/globals"; | ||||
| 
 | ||||
| function getLogBuffer(type: string) { | ||||
|  | @ -34,7 +34,7 @@ export default new NamedCommand({ | |||
|             subcommands: { | ||||
|                 prefix: new NamedCommand({ | ||||
|                     description: "Set a custom prefix for your guild. Removes your custom prefix if none is provided.", | ||||
|                     usage: "(<prefix>)", | ||||
|                     usage: "(<prefix>) (<@bot>)", | ||||
|                     async run({message, channel, guild, author, member, client, args}) { | ||||
|                         Storage.getGuild(guild!.id).prefix = null; | ||||
|                         Storage.save(); | ||||
|  | @ -47,7 +47,17 @@ export default new NamedCommand({ | |||
|                             Storage.getGuild(guild!.id).prefix = args[0]; | ||||
|                             Storage.save(); | ||||
|                             channel.send(`The custom prefix for this guild is now \`${args[0]}\`.`); | ||||
|                         }, | ||||
|                         user: new Command({ | ||||
|                             description: "Specifies the bot in case of conflicting prefixes.", | ||||
|                             async run({message, channel, guild, author, member, client, args}) { | ||||
|                                 if ((args[1] as User).id === client.user!.id) { | ||||
|                                     Storage.getGuild(guild!.id).prefix = args[0]; | ||||
|                                     Storage.save(); | ||||
|                                     channel.send(`The custom prefix for this guild is now \`${args[0]}\`.`); | ||||
|                                 } | ||||
|                             } | ||||
|                         }) | ||||
|                     }) | ||||
|                 }), | ||||
|                 welcome: new NamedCommand({ | ||||
|  |  | |||
|  | @ -2,8 +2,9 @@ import {Command, NamedCommand} from "../../core"; | |||
| import {processEmoteQueryFormatted} from "./modules/emote-utils"; | ||||
| 
 | ||||
| export default new NamedCommand({ | ||||
|     description: "Send the specified emote.", | ||||
|     run: "Please provide a command name.", | ||||
|     description: | ||||
|         "Send the specified emote list. Enter + to move an emote list to the next line, - to add a space, and _ to add a zero-width space.", | ||||
|     run: "Please provide a list of emotes.", | ||||
|     any: new Command({ | ||||
|         description: "The emote(s) to send.", | ||||
|         usage: "<emotes...>", | ||||
|  |  | |||
|  | @ -76,6 +76,7 @@ function processEmoteQuery(query: string[], isFormatted: boolean): string[] { | |||
|         if (isFormatted) { | ||||
|             if (emote == "-") return " "; | ||||
|             if (emote == "+") return "\n"; | ||||
|             if (emote == "_") return "\u200b"; | ||||
|         } | ||||
| 
 | ||||
|         // Selector number used for disambiguating multiple emotes with same name.
 | ||||
|  |  | |||
|  | @ -182,5 +182,15 @@ export default new NamedCommand({ | |||
|         } | ||||
| 
 | ||||
|         return await channel.send(lines, {split: true}); | ||||
|     }, | ||||
|     subcommands: { | ||||
|         forcereset: new NamedCommand({ | ||||
|             description: "Forces the cooldown timer to reset.", | ||||
|             permission: PERMISSIONS.BOT_SUPPORT, | ||||
|             async run({message, channel, guild, author, member, client, args}) { | ||||
|                 lastUsedTimestamps[guild!.id] = 0; | ||||
|                 channel.send("Reset the cooldown on `scanemotes`."); | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| }); | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| import {Command, NamedCommand} from "../../core"; | ||||
| // Anycasting Alert
 | ||||
| const translate = require("translate-google"); | ||||
| import translate from "translate-google"; | ||||
| 
 | ||||
| export default new NamedCommand({ | ||||
|     description: "Translates your input.", | ||||
|  | @ -11,7 +10,7 @@ export default new NamedCommand({ | |||
|         translate(input, { | ||||
|             to: lang | ||||
|         }) | ||||
|             .then((res: any) => { | ||||
|             .then((res) => { | ||||
|                 channel.send({ | ||||
|                     embed: { | ||||
|                         title: "Translation", | ||||
|  | @ -28,10 +27,10 @@ export default new NamedCommand({ | |||
|                     } | ||||
|                 }); | ||||
|             }) | ||||
|             .catch((err: any) => { | ||||
|                 console.error(err); | ||||
|             .catch((error) => { | ||||
|                 console.error(error); | ||||
|                 channel.send( | ||||
|                     `${err}\nPlease use the following list: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes` | ||||
|                     `${error}\nPlease use the following list: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes` | ||||
|                 ); | ||||
|             }); | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										9
									
								
								src/defs/translate.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/defs/translate.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| interface TranslateOptions { | ||||
|     from?: string; | ||||
|     to?: string; | ||||
| } | ||||
| 
 | ||||
| declare module "translate-google" { | ||||
|     function translate(input: string, options: TranslateOptions): Promise<string>; | ||||
|     export = translate; | ||||
| } | ||||
							
								
								
									
										17
									
								
								src/defs/urban.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/defs/urban.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| interface Definition { | ||||
|     id: number; | ||||
|     word: string; | ||||
|     thumbsUp: number; | ||||
|     thumbsDown: number; | ||||
|     author: string; | ||||
|     urbanURL: string; | ||||
|     example: string; | ||||
|     definition: string; | ||||
|     tags: string[] | null; | ||||
|     sounds: string[] | null; | ||||
| } | ||||
| 
 | ||||
| declare module "relevant-urban" { | ||||
|     function urban(query: string): Promise<Definition>; | ||||
|     export = urban; | ||||
| } | ||||
							
								
								
									
										92
									
								
								src/defs/weather.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/defs/weather.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| interface WeatherJSOptions { | ||||
|     search: string; | ||||
|     lang?: string; | ||||
|     degreeType?: string; | ||||
|     timeout?: number; | ||||
| } | ||||
| 
 | ||||
| interface WeatherJSResult { | ||||
|     location: { | ||||
|         name: string; | ||||
|         lat: string; | ||||
|         long: string; | ||||
|         timezone: string; | ||||
|         alert: string; | ||||
|         degreetype: string; | ||||
|         imagerelativeurl: string; | ||||
|     }; | ||||
|     current: { | ||||
|         temperature: string; | ||||
|         skycode: string; | ||||
|         skytext: string; | ||||
|         date: string; | ||||
|         observationtime: string; | ||||
|         observationpoint: string; | ||||
|         feelslike: string; | ||||
|         humidity: string; | ||||
|         winddisplay: string; | ||||
|         day: string; | ||||
|         shortday: string; | ||||
|         windspeed: string; | ||||
|         imageUrl: string; | ||||
|     }; | ||||
|     forecast: [ | ||||
|         { | ||||
|             low: string; | ||||
|             high: string; | ||||
|             skycodeday: string; | ||||
|             skytextday: string; | ||||
|             date: string; | ||||
|             day: string; | ||||
|             shortday: string; | ||||
|             precip: string; | ||||
|         }, | ||||
|         { | ||||
|             low: string; | ||||
|             high: string; | ||||
|             skycodeday: string; | ||||
|             skytextday: string; | ||||
|             date: string; | ||||
|             day: string; | ||||
|             shortday: string; | ||||
|             precip: string; | ||||
|         }, | ||||
|         { | ||||
|             low: string; | ||||
|             high: string; | ||||
|             skycodeday: string; | ||||
|             skytextday: string; | ||||
|             date: string; | ||||
|             day: string; | ||||
|             shortday: string; | ||||
|             precip: string; | ||||
|         }, | ||||
|         { | ||||
|             low: string; | ||||
|             high: string; | ||||
|             skycodeday: string; | ||||
|             skytextday: string; | ||||
|             date: string; | ||||
|             day: string; | ||||
|             shortday: string; | ||||
|             precip: string; | ||||
|         }, | ||||
|         { | ||||
|             low: string; | ||||
|             high: string; | ||||
|             skycodeday: string; | ||||
|             skytextday: string; | ||||
|             date: string; | ||||
|             day: string; | ||||
|             shortday: string; | ||||
|             precip: string; | ||||
|         } | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| declare module "weather-js" { | ||||
|     const find: ( | ||||
|         options: WeatherJSOptions, | ||||
|         callback: (error: Error | string | null, result: WeatherJSResult[]) => any | ||||
|     ) => void; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue