Compare commits
14 Commits
bf1793e561
...
70141b162f
Author | SHA1 | Date | |
---|---|---|---|
70141b162f | |||
6d92cb4deb | |||
32e142b8cb | |||
c6249b1b9b | |||
4f1e84ba8e | |||
225cac02c0 | |||
a1f2f175cd | |||
4b07aeb10c | |||
699a833285 | |||
648deb83db | |||
a926461f8f | |||
a65137307b | |||
0afca583b0 | |||
dc668c67a0 |
145
.gitignore
vendored
145
.gitignore
vendored
@ -11,3 +11,148 @@ htmlcov
|
|||||||
*.db
|
*.db
|
||||||
cache/
|
cache/
|
||||||
token
|
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
|
||||||
|
28
bot.py
28
bot.py
@ -61,11 +61,37 @@ class BotClient(discord.Client):
|
|||||||
|
|
||||||
async def on_message(self, message: discord.Message):
|
async def on_message(self, message: discord.Message):
|
||||||
content = message.content
|
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)
|
await self.on_replay(message)
|
||||||
elif self.is_leaguefact(message):
|
elif self.is_leaguefact(message):
|
||||||
await self.on_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):
|
||||||
|
match message.content.split(" "):
|
||||||
|
case ["%calc", *args]:
|
||||||
|
try:
|
||||||
|
calc = await self._calculate(args)
|
||||||
|
await message.reply(content=calc.strip())
|
||||||
|
except Exception as e:
|
||||||
|
await message.reply(
|
||||||
|
content="```\n" + str(e) + "\n```", delete_after=30
|
||||||
|
)
|
||||||
|
case _:
|
||||||
|
_log.info(f"Unrecognised command {command}")
|
||||||
|
|
||||||
|
async def _calculate(self, args: list[str]) -> str:
|
||||||
|
proc = sp.run(
|
||||||
|
["node", "calc_main.js", "--"] + args, stdout=sp.PIPE, stderr=sp.PIPE
|
||||||
|
)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
raise Exception(proc.stderr.decode())
|
||||||
|
return proc.stdout.decode()
|
||||||
|
|
||||||
def is_replay(self, message: discord.Message) -> bool:
|
def is_replay(self, message: discord.Message) -> bool:
|
||||||
if re.match("https://replay.pokemonshowdown.com/dl-.*", message.content):
|
if re.match("https://replay.pokemonshowdown.com/dl-.*", message.content):
|
||||||
return True
|
return True
|
||||||
|
304
calc.js
Normal file
304
calc.js
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
import {
|
||||||
|
calculate,
|
||||||
|
Field,
|
||||||
|
Generations,
|
||||||
|
Move,
|
||||||
|
Pokemon,
|
||||||
|
Result,
|
||||||
|
} from "@ajhyndman/smogon-calc";
|
||||||
|
import assert from "assert";
|
||||||
|
import { createToken, Lexer } from "chevrotain";
|
||||||
|
|
||||||
|
const gen = Generations.get(9);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a lexer.
|
||||||
|
*
|
||||||
|
* @returns {Lexer}
|
||||||
|
*/
|
||||||
|
function buildLexer() {
|
||||||
|
const Boost = createToken({ name: "Boost", pattern: /[+-]\d+/ });
|
||||||
|
const EV = createToken({ name: "EV", pattern: /\d+[+-]?/ });
|
||||||
|
const Stat = createToken({
|
||||||
|
name: "Stat",
|
||||||
|
pattern: /HP|Atk|Def|SpA|SpD|Spe/,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Item = createToken({
|
||||||
|
name: "Item",
|
||||||
|
pattern: new RegExp([...gen.items].map((i) => i.name).join("|")),
|
||||||
|
});
|
||||||
|
const Ability = createToken({
|
||||||
|
name: "Ability",
|
||||||
|
pattern: new RegExp([...gen.abilities].map((a) => a.name).join("|")),
|
||||||
|
});
|
||||||
|
|
||||||
|
const Pokemon = createToken({
|
||||||
|
name: "Pokemon",
|
||||||
|
pattern: new RegExp([...gen.species].map((s) => s.name).join("|")),
|
||||||
|
});
|
||||||
|
const Move = createToken({
|
||||||
|
name: "Move",
|
||||||
|
pattern: new RegExp([...gen.moves].map((m) => m.name).join("|")),
|
||||||
|
});
|
||||||
|
|
||||||
|
const whitespace = createToken({
|
||||||
|
name: "Whitespace",
|
||||||
|
pattern: /\s+/,
|
||||||
|
group: Lexer.SKIPPED,
|
||||||
|
});
|
||||||
|
const div = createToken({
|
||||||
|
name: "div",
|
||||||
|
pattern: "/",
|
||||||
|
group: Lexer.SKIPPED,
|
||||||
|
});
|
||||||
|
const vs = createToken({
|
||||||
|
name: "vs",
|
||||||
|
pattern: /vs\.?/,
|
||||||
|
});
|
||||||
|
|
||||||
|
const terrainEnter = createToken({
|
||||||
|
name: "terrainEnter",
|
||||||
|
pattern: "in",
|
||||||
|
push_mode: "terrain_mode",
|
||||||
|
});
|
||||||
|
const Weather = createToken({
|
||||||
|
name: "Weather",
|
||||||
|
pattern: /Sun|Rain|Sand|Snow/,
|
||||||
|
});
|
||||||
|
const Terrain = createToken({
|
||||||
|
name: "Terrain",
|
||||||
|
pattern: /(Electric|Grassy|Misty|Psychic) Terrain/,
|
||||||
|
});
|
||||||
|
|
||||||
|
const screenEnter = 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 {import("chevrotain").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 {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 {import("@ajhyndman/smogon-calc").State.Pokemon} */
|
||||||
|
var attackerOpts = {};
|
||||||
|
/** @type {import("@ajhyndman/smogon-calc").State.Pokemon} */
|
||||||
|
var defenderOpts = {};
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
|
var move;
|
||||||
|
/** @type {import("@ajhyndman/smogon-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("Impossible 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-checking before the calculator throws unreadable errors.
|
||||||
|
if (!gen.species.get(attacker.toLowerCase()))
|
||||||
|
throw Error(`No species named ${attacker}`);
|
||||||
|
if (!gen.species.get(defender.toLowerCase()))
|
||||||
|
throw Error(`No species named ${defender}`);
|
||||||
|
if (!gen.moves.get(move.toLowerCase())) throw Error(`No move named ${move}`);
|
||||||
|
|
||||||
|
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
|
ps.requests
|
||||||
]);
|
]);
|
||||||
in
|
in
|
||||||
[ python pkgs.sqlite ];
|
[
|
||||||
|
pkgs.nodejs
|
||||||
|
python
|
||||||
|
pkgs.sqlite
|
||||||
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
82
package-lock.json
generated
Normal file
82
package-lock.json
generated
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"name": "hhirls",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "hhirls",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "WTFPL",
|
||||||
|
"dependencies": {
|
||||||
|
"@ajhyndman/smogon-calc": "^0.8.0",
|
||||||
|
"chevrotain": "^10.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ajhyndman/smogon-calc": {
|
||||||
|
"version": "0.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ajhyndman/smogon-calc/-/smogon-calc-0.8.0.tgz",
|
||||||
|
"integrity": "sha512-jx/gY1uSD70skzE0xE7+lUPp7KxKKqj3PcyRLMCejbd9A68PwnBKfbDP3pW5ILX9Dy+9R9m6OkiPCa9K4qi/pQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^18.14.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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/@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/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/lodash": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
|
},
|
||||||
|
"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=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
package.json
Normal file
17
package.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"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": {
|
||||||
|
"@ajhyndman/smogon-calc": "^0.8.0",
|
||||||
|
"chevrotain": "^10.5.0"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user