add Showdown calculator
This commit is contained in:
		
							
								
								
									
										145
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										145
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -11,3 +11,148 @@ htmlcov | ||||
| *.db | ||||
| cache/ | ||||
| token | ||||
|  | ||||
| # Created by https://www.toptal.com/developers/gitignore/api/node | ||||
| # Edit at https://www.toptal.com/developers/gitignore?templates=node | ||||
|  | ||||
| ### Node ### | ||||
| # Logs | ||||
| logs | ||||
| *.log | ||||
| npm-debug.log* | ||||
| yarn-debug.log* | ||||
| yarn-error.log* | ||||
| lerna-debug.log* | ||||
| .pnpm-debug.log* | ||||
|  | ||||
| # Diagnostic reports (https://nodejs.org/api/report.html) | ||||
| report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | ||||
|  | ||||
| # Runtime data | ||||
| pids | ||||
| *.pid | ||||
| *.seed | ||||
| *.pid.lock | ||||
|  | ||||
| # Directory for instrumented libs generated by jscoverage/JSCover | ||||
| lib-cov | ||||
|  | ||||
| # Coverage directory used by tools like istanbul | ||||
| coverage | ||||
| *.lcov | ||||
|  | ||||
| # nyc test coverage | ||||
| .nyc_output | ||||
|  | ||||
| # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | ||||
| .grunt | ||||
|  | ||||
| # Bower dependency directory (https://bower.io/) | ||||
| bower_components | ||||
|  | ||||
| # node-waf configuration | ||||
| .lock-wscript | ||||
|  | ||||
| # Compiled binary addons (https://nodejs.org/api/addons.html) | ||||
| build/Release | ||||
|  | ||||
| # Dependency directories | ||||
| node_modules/ | ||||
| jspm_packages/ | ||||
|  | ||||
| # Snowpack dependency directory (https://snowpack.dev/) | ||||
| web_modules/ | ||||
|  | ||||
| # TypeScript cache | ||||
| *.tsbuildinfo | ||||
|  | ||||
| # Optional npm cache directory | ||||
| .npm | ||||
|  | ||||
| # Optional eslint cache | ||||
| .eslintcache | ||||
|  | ||||
| # Optional stylelint cache | ||||
| .stylelintcache | ||||
|  | ||||
| # Microbundle cache | ||||
| .rpt2_cache/ | ||||
| .rts2_cache_cjs/ | ||||
| .rts2_cache_es/ | ||||
| .rts2_cache_umd/ | ||||
|  | ||||
| # Optional REPL history | ||||
| .node_repl_history | ||||
|  | ||||
| # Output of 'npm pack' | ||||
| *.tgz | ||||
|  | ||||
| # Yarn Integrity file | ||||
| .yarn-integrity | ||||
|  | ||||
| # dotenv environment variable files | ||||
| .env | ||||
| .env.development.local | ||||
| .env.test.local | ||||
| .env.production.local | ||||
| .env.local | ||||
|  | ||||
| # parcel-bundler cache (https://parceljs.org/) | ||||
| .cache | ||||
| .parcel-cache | ||||
|  | ||||
| # Next.js build output | ||||
| .next | ||||
| out | ||||
|  | ||||
| # Nuxt.js build / generate output | ||||
| .nuxt | ||||
| dist | ||||
|  | ||||
| # Gatsby files | ||||
| .cache/ | ||||
| # Comment in the public line in if your project uses Gatsby and not Next.js | ||||
| # https://nextjs.org/blog/next-9-1#public-directory-support | ||||
| # public | ||||
|  | ||||
| # vuepress build output | ||||
| .vuepress/dist | ||||
|  | ||||
| # vuepress v2.x temp and cache directory | ||||
| .temp | ||||
|  | ||||
| # Docusaurus cache and generated files | ||||
| .docusaurus | ||||
|  | ||||
| # Serverless directories | ||||
| .serverless/ | ||||
|  | ||||
| # FuseBox cache | ||||
| .fusebox/ | ||||
|  | ||||
| # DynamoDB Local files | ||||
| .dynamodb/ | ||||
|  | ||||
| # TernJS port file | ||||
| .tern-port | ||||
|  | ||||
| # Stores VSCode versions used for testing VSCode extensions | ||||
| .vscode-test | ||||
|  | ||||
| # yarn v2 | ||||
| .yarn/cache | ||||
| .yarn/unplugged | ||||
| .yarn/build-state.yml | ||||
| .yarn/install-state.gz | ||||
| .pnp.* | ||||
|  | ||||
| ### Node Patch ### | ||||
| # Serverless Webpack directories | ||||
| .webpack/ | ||||
|  | ||||
| # Optional stylelint cache | ||||
|  | ||||
| # SvelteKit build / generate output | ||||
| .svelte-kit | ||||
|  | ||||
| # End of https://www.toptal.com/developers/gitignore/api/node | ||||
|   | ||||
							
								
								
									
										21
									
								
								bot.py
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								bot.py
									
									
									
									
									
								
							| @@ -61,11 +61,30 @@ class BotClient(discord.Client): | ||||
|  | ||||
|     async def on_message(self, message: discord.Message): | ||||
|         content = message.content | ||||
|         if self.is_replay(message): | ||||
|         if self.is_command(message): | ||||
|             await self.on_command(message) | ||||
|         elif self.is_replay(message): | ||||
|             await self.on_replay(message) | ||||
|         elif self.is_leaguefact(message): | ||||
|             await self.on_leaguefact(message) | ||||
|  | ||||
|     def is_command(self, message: discord.Message) -> bool: | ||||
|         return message.content.startswith("%") | ||||
|  | ||||
|     async def on_command(self, message: discord.Message): | ||||
|         command = discord.message.split(" ")[0] | ||||
|         match command: | ||||
|             case "%calc": | ||||
|                 reply = await _calculate(command[1:]) | ||||
|                 await message.reply(content=reply) | ||||
|             case _: | ||||
|                 _log.info(f"Unrecognised command {command}") | ||||
|  | ||||
|     async def _calculate(args: list[str]) -> str: | ||||
|         proc = sp.run(["node", "calc_main.js", "--"] + args) | ||||
|         msg = proc.stdout | ||||
|         return msg.strip() | ||||
|  | ||||
|     def is_replay(self, message: discord.Message) -> bool: | ||||
|         if re.match("https://replay.pokemonshowdown.com/dl-.*", message.content): | ||||
|             return True | ||||
|   | ||||
							
								
								
									
										299
									
								
								calc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								calc.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| import calc, { | ||||
|   calculate, | ||||
|   Generations, | ||||
|   Field, | ||||
|   Move, | ||||
|   Pokemon, | ||||
| } from "@smogon/calc"; | ||||
| import assert from "assert"; | ||||
| import chev, { Lexer } from "chevrotain"; | ||||
|  | ||||
| /** | ||||
|  * Creates a lexer. | ||||
|  * | ||||
|  * @returns {Lexer} | ||||
|  */ | ||||
| function buildLexer() { | ||||
|   const Boost = chev.createToken({ name: "Boost", pattern: /[+-]\d+/ }); | ||||
|   const EV = chev.createToken({ name: "EV", pattern: /\d+[+-]?/ }); | ||||
|   const Stat = chev.createToken({ | ||||
|     name: "Stat", | ||||
|     pattern: /HP|Atk|Def|SpA|SpD|Spe/, | ||||
|   }); | ||||
|  | ||||
|   const Item = chev.createToken({ | ||||
|     name: "Item", | ||||
|     pattern: new RegExp(calc.ITEMS.flatMap((gen) => gen).join("|")), | ||||
|   }); | ||||
|   const Ability = chev.createToken({ | ||||
|     name: "Ability", | ||||
|     pattern: new RegExp(calc.ABILITIES.flatMap((gen) => gen).join("|")), | ||||
|   }); | ||||
|  | ||||
|   const Pokemon = chev.createToken({ | ||||
|     name: "Pokemon", | ||||
|     pattern: new RegExp( | ||||
|       calc.SPECIES.flatMap((gen) => Object.keys(gen)).join("|") | ||||
|     ), | ||||
|   }); | ||||
|   const Move = chev.createToken({ | ||||
|     name: "Move", | ||||
|     pattern: new RegExp( | ||||
|       calc.MOVES.flatMap((gen) => Object.keys(gen)).join("|") | ||||
|     ), | ||||
|   }); | ||||
|  | ||||
|   const whitespace = chev.createToken({ | ||||
|     name: "Whitespace", | ||||
|     pattern: /\s+/, | ||||
|     group: Lexer.SKIPPED, | ||||
|   }); | ||||
|   const div = chev.createToken({ | ||||
|     name: "div", | ||||
|     pattern: "/", | ||||
|     group: Lexer.SKIPPED, | ||||
|   }); | ||||
|   const vs = chev.createToken({ | ||||
|     name: "vs", | ||||
|     pattern: "vs.", | ||||
|   }); | ||||
|  | ||||
|   const terrainEnter = chev.createToken({ | ||||
|     name: "terrainEnter", | ||||
|     pattern: "in", | ||||
|     push_mode: "terrain_mode", | ||||
|   }); | ||||
|   const Weather = chev.createToken({ | ||||
|     name: "Weather", | ||||
|     pattern: /Sun|Rain|Sand|Snow/, | ||||
|   }); | ||||
|   const Terrain = chev.createToken({ | ||||
|     name: "Terrain", | ||||
|     pattern: /(Electric|Grassy|Misty|Psychic) Terrain/, | ||||
|   }); | ||||
|  | ||||
|   const screenEnter = chev.createToken({ | ||||
|     name: "screenEnter", | ||||
|     pattern: "through", | ||||
|     push_mode: "screen_mode", | ||||
|   }); | ||||
|  | ||||
|   return new Lexer({ | ||||
|     modes: { | ||||
|       default_mode: [ | ||||
|         whitespace, | ||||
|         div, | ||||
|         vs, | ||||
|         Boost, | ||||
|         EV, | ||||
|         Stat, | ||||
|         Item, | ||||
|         Ability, | ||||
|         Pokemon, | ||||
|         Move, | ||||
|         terrainEnter, | ||||
|         screenEnter, | ||||
|       ], | ||||
|       terrain_mode: [whitespace, screenEnter, Weather, Terrain], | ||||
|       screen_mode: [whitespace, Move], | ||||
|     }, | ||||
|     defaultMode: "default_mode", | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @generator | ||||
|  * @template T item type | ||||
|  * @param {T[]} arr | ||||
|  * @yields {T} item | ||||
|  */ | ||||
| function* iterate(arr) { | ||||
|   for (const a of arr) { | ||||
|     yield a; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} type token type | ||||
|  * @param {chev.IToken} token token | ||||
|  * @return {string} matched token | ||||
|  */ | ||||
| function unwrapToken(type, token) { | ||||
|   assert( | ||||
|     token.tokenType.name == type, | ||||
|     "expected token %s, got %s", | ||||
|     type, | ||||
|     token.tokenType.name | ||||
|   ); | ||||
|   return token.image; | ||||
| } | ||||
|  | ||||
| const POS_NATURES = { | ||||
|   atk: "Adamant", | ||||
|   def: "Bold", | ||||
|   spa: "Modest", | ||||
|   spd: "Calm", | ||||
|   spe: "Jolly", | ||||
| }; | ||||
|  | ||||
| const NEG_NATURES = { | ||||
|   atk: "Modest", | ||||
|   def: "Lonely", | ||||
|   spa: "Adamant", | ||||
|   spd: "Rash", | ||||
|   spe: "Brave", | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Parses a Smogon calculator output: | ||||
|  * | ||||
|  * -2 8 SpA Choice Specs Torkoal vs. | ||||
|  * 252 HP / 4+ SpD Assault Vest Abomasnow | ||||
|  * in Sun | ||||
|  * through Light Screen | ||||
|  * | ||||
|  * @param {string} line textual line | ||||
|  * @return {calc.Result} calculation result | ||||
|  */ | ||||
| function parseAndCalculate(line) { | ||||
|   const lexer = buildLexer(); | ||||
|   const result = lexer.tokenize(line); | ||||
|   if (result.errors && result.errors.length > 0) { | ||||
|     console.error("Unparsed tokens: %o", result.errors); | ||||
|   } | ||||
|  | ||||
|   /** @type {string} */ | ||||
|   var attacker; | ||||
|   /** @type {string} */ | ||||
|   var defender; | ||||
|  | ||||
|   /** @type {calc.State.Pokemon} */ | ||||
|   var attackerOpts = {}; | ||||
|   /** @type {calc.State.Pokemon} */ | ||||
|   var defenderOpts = {}; | ||||
|  | ||||
|   /** @type {string} */ | ||||
|   var move; | ||||
|   /** @type {calc.State.Field} */ | ||||
|   var field = {}; | ||||
|  | ||||
|   // Tokenising state. | ||||
|   var isAttacker = true; | ||||
|   var it = iterate(result.tokens); | ||||
|  | ||||
|   const opts = () => (isAttacker ? attackerOpts : defenderOpts); | ||||
|  | ||||
|   while (true) { | ||||
|     let item = it.next().value; | ||||
|     if (!item) break; | ||||
|     switch (item.tokenType.name) { | ||||
|       case "Boost": | ||||
|         { | ||||
|           let boost = unwrapToken("Boost", item); | ||||
|           let ev = unwrapToken("EV", it.next().value); | ||||
|           let stat = unwrapToken("Stat", it.next().value).toLowerCase(); | ||||
|           opts().boosts = { [stat]: parseInt(boost), ...opts().boosts }; | ||||
|           opts().evs = { [stat]: parseInt(ev), ...opts().evs }; | ||||
|           if (ev.endsWith("+")) { | ||||
|             opts().nature = POS_NATURES[stat]; | ||||
|           } else if (ev.endsWith("-")) { | ||||
|             opts().nature = NEG_NATURES[stat]; | ||||
|           } | ||||
|         } | ||||
|         break; | ||||
|       case "EV": | ||||
|         { | ||||
|           let ev = unwrapToken("EV", item); | ||||
|           let stat = unwrapToken("Stat", it.next().value).toLowerCase(); | ||||
|           opts().evs = { [stat]: parseInt(ev), ...opts().evs }; | ||||
|           if (ev.endsWith("+")) { | ||||
|             opts().nature = POS_NATURES[stat]; | ||||
|           } else if (ev.endsWith("-")) { | ||||
|             opts().nature = NEG_NATURES[stat]; | ||||
|           } | ||||
|         } | ||||
|         break; | ||||
|       case "Stat": | ||||
|         throw Error("Impossibel state: bare Stat"); | ||||
|       case "Item": | ||||
|         opts().item = unwrapToken("Item", item); | ||||
|         break; | ||||
|       case "Pokemon": | ||||
|         { | ||||
|           let name = unwrapToken("Pokemon", item); | ||||
|           if (isAttacker) attacker = name; | ||||
|           else defender = name; | ||||
|         } | ||||
|         break; | ||||
|       case "Move": | ||||
|         move = unwrapToken("Move", item); | ||||
|         break; | ||||
|       case "terrainEnter": | ||||
|         { | ||||
|           let next = it.next().value; | ||||
|           switch (next.tokenType.name) { | ||||
|             case "Weather": | ||||
|               field.weather = next.image; | ||||
|               break; | ||||
|             case "Terrain": | ||||
|               field.terrain = next.image; | ||||
|               break; | ||||
|             default: | ||||
|               throw Error( | ||||
|                 "Unhandled terrain %s: %s", | ||||
|                 next.tokenType.name, | ||||
|                 next.image | ||||
|               ); | ||||
|           } | ||||
|         } | ||||
|         break; | ||||
|       case "screenEnter": | ||||
|         { | ||||
|           let screen = unwrapToken("Move", it.next().value); | ||||
|           field.defenderSide = field.defenderSide || {}; | ||||
|           field.defenderSide.isLightScreen = screen === "Light Screen"; | ||||
|           field.defenderSide.isReflect = screen === "Reflect"; | ||||
|           field.defenderSide.isAuroraVeil = screen === "Aurora Veil"; | ||||
|           field.defenderSide.is; | ||||
|         } | ||||
|         break; | ||||
|       case "vs": | ||||
|         isAttacker = false; | ||||
|         break; | ||||
|       default: | ||||
|         console.error("unmatched token type: %s", item.tokenType.name); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   const gen = Generations.get(8); | ||||
|   return calculate( | ||||
|     gen, | ||||
|     new Pokemon(gen, attacker, attackerOpts), | ||||
|     new Pokemon(gen, defender, defenderOpts), | ||||
|     new Move(gen, move), | ||||
|     new Field(field) | ||||
|   ); | ||||
| } | ||||
|  | ||||
| function test() { | ||||
|   const text = | ||||
|     "-2 8 SpA Choice Specs Torkoal Overheat vs. 252 HP / 4+ SpD Assault Vest Abomasnow in Sun through Light Screen"; | ||||
|   const res = parseAndCalculate(text); | ||||
|  | ||||
|   assert(res.attacker.boosts.spa === -2, "should have -2 SpA"); | ||||
|   assert(res.attacker.evs.spa === 8, "should have 8 SpA EVs"); | ||||
|   assert(res.attacker.item === "Choice Specs", "should have Choice Specs"); | ||||
|   assert(res.attacker.name === "Torkoal", "should be Torkoal"); | ||||
|   assert(res.move.name === "Overheat", "should be Overheat"); | ||||
|   assert(res.defender.evs.hp === 252, "should have 252 HP EVs"); | ||||
|   assert(res.defender.evs.spd === 4, "should have 4 SpD EVs"); | ||||
|   assert(res.field.weather === "Sun", "should be in sun"); | ||||
|  | ||||
|   assert( | ||||
|     res.desc().replace(/:.*/, "") === text, | ||||
|     "non-damage text should be equivalent to input" | ||||
|   ); | ||||
| } | ||||
|  | ||||
| export { parseAndCalculate, test }; | ||||
							
								
								
									
										8
									
								
								calc_main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								calc_main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| import { parseAndCalculate } from "./calc.js"; | ||||
|  | ||||
| // FIXME: issue with using execArgv. | ||||
| let args = process.argv.slice(2); | ||||
| if (args[0] === "--") args = args.slice(1); | ||||
| const line = args.join(" "); | ||||
| const res = parseAndCalculate(line); | ||||
| console.log(res.fullDesc()); | ||||
| @@ -17,7 +17,11 @@ | ||||
|                   ps.requests | ||||
|                 ]); | ||||
|               in | ||||
|               [ python pkgs.sqlite ]; | ||||
|               [ | ||||
|                 pkgs.nodejs | ||||
|                 python | ||||
|                 pkgs.sqlite | ||||
|               ]; | ||||
|           }; | ||||
|         }); | ||||
| } | ||||
|   | ||||
							
								
								
									
										431
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										431
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,431 @@ | ||||
| { | ||||
|   "name": "hhirls", | ||||
|   "version": "1.0.0", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "hhirls", | ||||
|       "version": "1.0.0", | ||||
|       "license": "WTFPL", | ||||
|       "dependencies": { | ||||
|         "@smogon/calc": "^0.7.0", | ||||
|         "chevrotain": "^10.5.0", | ||||
|         "discord.js": "^14.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@chevrotain/cst-dts-gen": { | ||||
|       "version": "10.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.5.0.tgz", | ||||
|       "integrity": "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==", | ||||
|       "dependencies": { | ||||
|         "@chevrotain/gast": "10.5.0", | ||||
|         "@chevrotain/types": "10.5.0", | ||||
|         "lodash": "4.17.21" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@chevrotain/gast": { | ||||
|       "version": "10.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.5.0.tgz", | ||||
|       "integrity": "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==", | ||||
|       "dependencies": { | ||||
|         "@chevrotain/types": "10.5.0", | ||||
|         "lodash": "4.17.21" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@chevrotain/types": { | ||||
|       "version": "10.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.5.0.tgz", | ||||
|       "integrity": "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==" | ||||
|     }, | ||||
|     "node_modules/@chevrotain/utils": { | ||||
|       "version": "10.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.5.0.tgz", | ||||
|       "integrity": "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==" | ||||
|     }, | ||||
|     "node_modules/@discordjs/builders": { | ||||
|       "version": "1.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.1.tgz", | ||||
|       "integrity": "sha512-CCcLwn/8ANhlAbhlE18fcaN0hfXTen53/JiwZs1t9oE/Cqa9maA8ZRarkCIsXF4J7J/MYnd0J6IsxeKsq+f6mw==", | ||||
|       "dependencies": { | ||||
|         "@discordjs/formatters": "^0.3.0", | ||||
|         "@discordjs/util": "^0.2.0", | ||||
|         "@sapphire/shapeshift": "^3.8.1", | ||||
|         "discord-api-types": "^0.37.37", | ||||
|         "fast-deep-equal": "^3.1.3", | ||||
|         "ts-mixer": "^6.0.3", | ||||
|         "tslib": "^2.5.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=16.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@discordjs/collection": { | ||||
|       "version": "1.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.0.tgz", | ||||
|       "integrity": "sha512-suyVndkEAAWrGxyw/CPGdtXoRRU6AUNkibtnbJevQzpelkJh3Q1gQqWDpqf5i39CnAn5+LrN0YS+cULeEjq2Yw==", | ||||
|       "engines": { | ||||
|         "node": ">=16.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@discordjs/formatters": { | ||||
|       "version": "0.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.0.tgz", | ||||
|       "integrity": "sha512-Fc4MomalbP8HMKEMor3qUiboAKDtR7PSBoPjwm7WYghVRwgJlj5WYvUsriLsxeKk8+Qq2oy+HJlGTUkGvX0YnA==", | ||||
|       "dependencies": { | ||||
|         "discord-api-types": "^0.37.37" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=16.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@discordjs/rest": { | ||||
|       "version": "1.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.0.tgz", | ||||
|       "integrity": "sha512-r2HzmznRIo8IDGYBWqQfkEaGN1LrFfWQd3dSyC4tOpMU8nuVvFUEw6V/lwnG44jyOq+vgyDny2fxeUDMt9I4aQ==", | ||||
|       "dependencies": { | ||||
|         "@discordjs/collection": "^1.5.0", | ||||
|         "@discordjs/util": "^0.2.0", | ||||
|         "@sapphire/async-queue": "^1.5.0", | ||||
|         "@sapphire/snowflake": "^3.4.0", | ||||
|         "discord-api-types": "^0.37.37", | ||||
|         "file-type": "^18.2.1", | ||||
|         "tslib": "^2.5.0", | ||||
|         "undici": "^5.21.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=16.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@discordjs/util": { | ||||
|       "version": "0.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.2.0.tgz", | ||||
|       "integrity": "sha512-/8qNbebFzLWKOOg+UV+RB8itp4SmU5jw0tBUD3ifElW6rYNOj1Ku5JaSW7lLl/WgjjxF01l/1uQPCzkwr110vg==", | ||||
|       "engines": { | ||||
|         "node": ">=16.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@sapphire/async-queue": { | ||||
|       "version": "1.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", | ||||
|       "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", | ||||
|       "engines": { | ||||
|         "node": ">=v14.0.0", | ||||
|         "npm": ">=7.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@sapphire/shapeshift": { | ||||
|       "version": "3.8.2", | ||||
|       "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.8.2.tgz", | ||||
|       "integrity": "sha512-NXpnJAsxN3/h9TqQPntOeVWZrpIuucqXI3IWF6tj2fWCoRLCuVK5wx7Dtg7pRrtkYfsMUbDqgKoX26vrC5iYfA==", | ||||
|       "dependencies": { | ||||
|         "fast-deep-equal": "^3.1.3", | ||||
|         "lodash": "^4.17.21" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=v14.0.0", | ||||
|         "npm": ">=7.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@sapphire/snowflake": { | ||||
|       "version": "3.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.4.2.tgz", | ||||
|       "integrity": "sha512-KJwlv5gkGjs1uFV7/xx81n3tqgBwBJvH94n1xDyH3q+JSmtsMeSleJffarEBfG2yAFeJiFA4BnGOK6FFPHc19g==", | ||||
|       "engines": { | ||||
|         "node": ">=v14.0.0", | ||||
|         "npm": ">=7.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@smogon/calc": { | ||||
|       "version": "0.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/@smogon/calc/-/calc-0.7.0.tgz", | ||||
|       "integrity": "sha512-2+AGILYtqwRBceIIYkxH1dvtLwzSdyEwAAFWDfjYVwwNohmsNKjU5RVsDal8matpmNJptHF2FekSbHONNZTlUg==", | ||||
|       "dependencies": { | ||||
|         "@types/node": "^18.11.9" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@tokenizer/token": { | ||||
|       "version": "0.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", | ||||
|       "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" | ||||
|     }, | ||||
|     "node_modules/@types/node": { | ||||
|       "version": "18.16.1", | ||||
|       "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.1.tgz", | ||||
|       "integrity": "sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==" | ||||
|     }, | ||||
|     "node_modules/@types/ws": { | ||||
|       "version": "8.5.4", | ||||
|       "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", | ||||
|       "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", | ||||
|       "dependencies": { | ||||
|         "@types/node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/busboy": { | ||||
|       "version": "1.6.0", | ||||
|       "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", | ||||
|       "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", | ||||
|       "dependencies": { | ||||
|         "streamsearch": "^1.1.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10.16.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/chevrotain": { | ||||
|       "version": "10.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.5.0.tgz", | ||||
|       "integrity": "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==", | ||||
|       "dependencies": { | ||||
|         "@chevrotain/cst-dts-gen": "10.5.0", | ||||
|         "@chevrotain/gast": "10.5.0", | ||||
|         "@chevrotain/types": "10.5.0", | ||||
|         "@chevrotain/utils": "10.5.0", | ||||
|         "lodash": "4.17.21", | ||||
|         "regexp-to-ast": "0.5.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/discord-api-types": { | ||||
|       "version": "0.37.40", | ||||
|       "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.40.tgz", | ||||
|       "integrity": "sha512-LMALvtO+p6ERK8rwWoaI490NfIE/egbqjR4/rfLL1z9gQE1gqLiTpIUUDIunfAtKYzeH6ucyXhaXXWpfZh/Q6g==" | ||||
|     }, | ||||
|     "node_modules/discord.js": { | ||||
|       "version": "14.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.9.0.tgz", | ||||
|       "integrity": "sha512-ygGms5xP4hG+QrrY9k7d/OYCzMltSMtdl/2Snzq/nLCiZo+Sna91Ulv9l0+B5Jd/Czcq37B7wJAnmja7GOa+bg==", | ||||
|       "dependencies": { | ||||
|         "@discordjs/builders": "^1.6.0", | ||||
|         "@discordjs/collection": "^1.5.0", | ||||
|         "@discordjs/formatters": "^0.3.0", | ||||
|         "@discordjs/rest": "^1.7.0", | ||||
|         "@discordjs/util": "^0.2.0", | ||||
|         "@sapphire/snowflake": "^3.4.0", | ||||
|         "@types/ws": "^8.5.4", | ||||
|         "discord-api-types": "^0.37.37", | ||||
|         "fast-deep-equal": "^3.1.3", | ||||
|         "lodash.snakecase": "^4.1.1", | ||||
|         "tslib": "^2.5.0", | ||||
|         "undici": "^5.21.0", | ||||
|         "ws": "^8.13.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=16.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/fast-deep-equal": { | ||||
|       "version": "3.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | ||||
|       "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" | ||||
|     }, | ||||
|     "node_modules/file-type": { | ||||
|       "version": "18.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.3.0.tgz", | ||||
|       "integrity": "sha512-pkPZ5OGIq0TYb37b8bHDLNeQSe1H2KlaQ2ySGpJkkr2KZdaWsO4QhPzHA0mQcsUW2cSqJk+4gM/UyLz/UFbXdQ==", | ||||
|       "dependencies": { | ||||
|         "readable-web-to-node-stream": "^3.0.2", | ||||
|         "strtok3": "^7.0.0", | ||||
|         "token-types": "^5.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.16" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sindresorhus/file-type?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ieee754": { | ||||
|       "version": "1.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", | ||||
|       "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "patreon", | ||||
|           "url": "https://www.patreon.com/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "consulting", | ||||
|           "url": "https://feross.org/support" | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/inherits": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | ||||
|       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" | ||||
|     }, | ||||
|     "node_modules/lodash": { | ||||
|       "version": "4.17.21", | ||||
|       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", | ||||
|       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" | ||||
|     }, | ||||
|     "node_modules/lodash.snakecase": { | ||||
|       "version": "4.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", | ||||
|       "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" | ||||
|     }, | ||||
|     "node_modules/peek-readable": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", | ||||
|       "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", | ||||
|       "engines": { | ||||
|         "node": ">=14.16" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "github", | ||||
|         "url": "https://github.com/sponsors/Borewit" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/readable-stream": { | ||||
|       "version": "3.6.2", | ||||
|       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", | ||||
|       "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", | ||||
|       "dependencies": { | ||||
|         "inherits": "^2.0.3", | ||||
|         "string_decoder": "^1.1.1", | ||||
|         "util-deprecate": "^1.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/readable-web-to-node-stream": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", | ||||
|       "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", | ||||
|       "dependencies": { | ||||
|         "readable-stream": "^3.6.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "github", | ||||
|         "url": "https://github.com/sponsors/Borewit" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/regexp-to-ast": { | ||||
|       "version": "0.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", | ||||
|       "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==" | ||||
|     }, | ||||
|     "node_modules/safe-buffer": { | ||||
|       "version": "5.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | ||||
|       "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "patreon", | ||||
|           "url": "https://www.patreon.com/feross" | ||||
|         }, | ||||
|         { | ||||
|           "type": "consulting", | ||||
|           "url": "https://feross.org/support" | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/streamsearch": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", | ||||
|       "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", | ||||
|       "engines": { | ||||
|         "node": ">=10.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/string_decoder": { | ||||
|       "version": "1.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", | ||||
|       "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", | ||||
|       "dependencies": { | ||||
|         "safe-buffer": "~5.2.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/strtok3": { | ||||
|       "version": "7.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", | ||||
|       "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", | ||||
|       "dependencies": { | ||||
|         "@tokenizer/token": "^0.3.0", | ||||
|         "peek-readable": "^5.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.16" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "github", | ||||
|         "url": "https://github.com/sponsors/Borewit" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/token-types": { | ||||
|       "version": "5.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", | ||||
|       "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", | ||||
|       "dependencies": { | ||||
|         "@tokenizer/token": "^0.3.0", | ||||
|         "ieee754": "^1.2.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.16" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "github", | ||||
|         "url": "https://github.com/sponsors/Borewit" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ts-mixer": { | ||||
|       "version": "6.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", | ||||
|       "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" | ||||
|     }, | ||||
|     "node_modules/tslib": { | ||||
|       "version": "2.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", | ||||
|       "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" | ||||
|     }, | ||||
|     "node_modules/undici": { | ||||
|       "version": "5.22.0", | ||||
|       "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", | ||||
|       "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", | ||||
|       "dependencies": { | ||||
|         "busboy": "^1.6.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/util-deprecate": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | ||||
|       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" | ||||
|     }, | ||||
|     "node_modules/ws": { | ||||
|       "version": "8.13.0", | ||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", | ||||
|       "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", | ||||
|       "engines": { | ||||
|         "node": ">=10.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "bufferutil": "^4.0.1", | ||||
|         "utf-8-validate": ">=5.0.2" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "bufferutil": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "utf-8-validate": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										18
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| { | ||||
|   "name": "hhirls", | ||||
|   "version": "1.0.0", | ||||
|   "description": "Pokemon Showdown data processing, mostly for HHIRLLL's Pokemon league. Ugly as fuck.", | ||||
|   "main": "calc.js", | ||||
|   "type": "module", | ||||
|   "scripts": { | ||||
|     "calc": "node calc_main.js", | ||||
|     "test": "node -e 'import(\"./calc.js\").then(mod => mod.test())'" | ||||
|   }, | ||||
|   "author": "", | ||||
|   "license": "WTFPL", | ||||
|   "dependencies": { | ||||
|     "@smogon/calc": "^0.7.0", | ||||
|     "chevrotain": "^10.5.0", | ||||
|     "discord.js": "^14.9.0" | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user