add Showdown calculator
This commit is contained in:
parent
bf1793e561
commit
dc668c67a0
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"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user