Implement autofishing and Pokédex
This commit is contained in:
parent
1f8ef214e3
commit
1fc6c43611
|
@ -3,7 +3,7 @@ import { argv } from "bun";
|
|||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import YAML from "yaml";
|
||||
|
||||
const logger = new Logger("Pokemon Converter");
|
||||
const logger = new Logger("Pokémon Converter");
|
||||
|
||||
const inFile = argv[2];
|
||||
const outFile = argv[3];
|
||||
|
|
|
@ -62,13 +62,21 @@ export const appRouter = router({
|
|||
id: z.string(),
|
||||
name: z.string(),
|
||||
color: z.string()
|
||||
})
|
||||
}),
|
||||
isDM: z.boolean().optional()
|
||||
})
|
||||
)
|
||||
.query(async opts => {
|
||||
const id = tokenToID(opts.ctx.token);
|
||||
const { command, args, prefix, user } = opts.input;
|
||||
const out = await handleCommand(id, command, args, prefix, user);
|
||||
const { command, args, prefix, user, isDM } = opts.input;
|
||||
const out = await handleCommand(
|
||||
id,
|
||||
command,
|
||||
args,
|
||||
prefix,
|
||||
user,
|
||||
isDM
|
||||
);
|
||||
|
||||
return out;
|
||||
}),
|
||||
|
|
|
@ -3,22 +3,24 @@ import { getFishing, startFishing } from "@server/fish/fishers";
|
|||
|
||||
export const fish = new Command(
|
||||
"fish",
|
||||
["fish", "fosh", "cast"],
|
||||
["fish", "fosh", "cast", "startfishing"],
|
||||
"Send your LURE into a water for catching fish",
|
||||
"fish",
|
||||
"command.fishing.fish",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
async ({ id, command, args, prefix, part, user, isDM }) => {
|
||||
const fishing = getFishing(id, part.id);
|
||||
|
||||
if (!fishing) {
|
||||
startFishing(id, part.id);
|
||||
startFishing(id, part.id, isDM);
|
||||
return `Our friend ${part.name} casts LURE into a water for catching fish.`;
|
||||
} else {
|
||||
return `Your lure is already in the water (since ${(
|
||||
(Date.now() - fishing.t) /
|
||||
1000 /
|
||||
60
|
||||
).toFixed(2)} minutes ago).`;
|
||||
).toFixed(2)} minutes ago).${
|
||||
fishing.autofish ? ` (AUTOFISH is enabled)` : ``
|
||||
}`;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -2,6 +2,8 @@ import Command from "@server/commands/Command";
|
|||
import { getInventory, updateInventory } from "@server/data/inventory";
|
||||
import { locations } from "@server/fish/locations";
|
||||
import { nearby } from "./nearby";
|
||||
import { getFishing, stopFishing } from "@server/fish/fishers";
|
||||
import { reel } from "./reel";
|
||||
|
||||
export const go = new Command(
|
||||
"go",
|
||||
|
@ -33,7 +35,12 @@ export const go = new Command(
|
|||
return `The place "${args[0]}" is not ${prefix}${nearby.aliases[0]}.`;
|
||||
|
||||
inventory.location = nextLoc.id;
|
||||
updateInventory(inventory);
|
||||
await updateInventory(inventory);
|
||||
|
||||
if (getFishing(id, user.id)) {
|
||||
stopFishing(id, user.id, false);
|
||||
return `You ${prefix}${reel.aliases[0]}ed your LURE in and went to ${nextLoc.name}.`;
|
||||
}
|
||||
|
||||
return `You went to ${nextLoc.name}.`;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import { locations } from "@server/fish/locations";
|
|||
|
||||
export const nearby = new Command(
|
||||
"nearby",
|
||||
["nearby"],
|
||||
["nearby", "noorby", "n"],
|
||||
"Look at nearby locations",
|
||||
"nearby",
|
||||
"command.fishing.nearby",
|
||||
|
|
|
@ -5,7 +5,7 @@ import { locations } from "@server/fish/locations";
|
|||
|
||||
export const reel = new Command(
|
||||
"reel",
|
||||
["reel"],
|
||||
["reel", "rool", "stopfishing", "stopfoshing"],
|
||||
"Reel in and stop fishing",
|
||||
"fishing",
|
||||
"command.fishing.reel",
|
||||
|
@ -15,7 +15,7 @@ export const reel = new Command(
|
|||
stopFishing(id, part.id);
|
||||
return `Our friend ${part.name} reel his/her lure back inside, temporarily decreasing his/her chances of catching a fish by 100%.`;
|
||||
} else {
|
||||
return `Friend ${part.name}: You haven't /casted it.`;
|
||||
return `Friend ${part.name}: You haven't ${prefix}casted it.`;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { commandGroups } from "..";
|
||||
import { logger } from "@server/commands/handler";
|
||||
import { CosmicColor } from "@util/CosmicColor";
|
||||
|
||||
export const color = new Command(
|
||||
"color",
|
||||
["color"],
|
||||
"Get the name of a color",
|
||||
"color",
|
||||
"command.general.color",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
let color = args[0];
|
||||
let out1 = `Friend ${part.name}: That color is`;
|
||||
|
||||
if (!color) {
|
||||
color = part.color;
|
||||
out1 = `Friend ${part.name}, your color is`;
|
||||
}
|
||||
|
||||
const c = new CosmicColor(color);
|
||||
return `${out1} ${c.getName().toLowerCase()}.`;
|
||||
}
|
||||
);
|
|
@ -13,6 +13,10 @@ import { eat } from "./inventory/eat";
|
|||
import { sack } from "./inventory/sack";
|
||||
import { reel } from "./fishing/reel";
|
||||
import { memory } from "./util/mem";
|
||||
import { pokemon } from "./inventory/pokemon";
|
||||
import { color } from "./general/color";
|
||||
import { autofish } from "./util/autofish";
|
||||
import { pokedex } from "./util/pokedex";
|
||||
|
||||
interface ICommandGroup {
|
||||
id: string;
|
||||
|
@ -25,7 +29,7 @@ export const commandGroups: ICommandGroup[] = [];
|
|||
const generalGroup: ICommandGroup = {
|
||||
id: "general",
|
||||
displayName: "General",
|
||||
commands: [help]
|
||||
commands: [help, color]
|
||||
};
|
||||
|
||||
commandGroups.push(generalGroup);
|
||||
|
@ -41,7 +45,7 @@ commandGroups.push(fishingGroup);
|
|||
const inventoryGroup: ICommandGroup = {
|
||||
id: "inventory",
|
||||
displayName: "Inventory",
|
||||
commands: [inventory, take, eat, sack]
|
||||
commands: [inventory, take, eat, sack, pokemon]
|
||||
};
|
||||
|
||||
commandGroups.push(inventoryGroup);
|
||||
|
@ -49,7 +53,7 @@ commandGroups.push(inventoryGroup);
|
|||
const utilGroup: ICommandGroup = {
|
||||
id: "util",
|
||||
displayName: "Utility",
|
||||
commands: [data, setcolor, memory]
|
||||
commands: [data, setcolor, memory, autofish, pokedex]
|
||||
};
|
||||
|
||||
commandGroups.push(utilGroup);
|
||||
|
|
|
@ -7,7 +7,7 @@ import { CosmicColor } from "@util/CosmicColor";
|
|||
export const eat = new Command(
|
||||
"eat",
|
||||
["eat", "oot"],
|
||||
"Eat literally anything in your inventory",
|
||||
"Eat literally anything you have (except non-fish animals)",
|
||||
"eat <something>",
|
||||
"command.inventory.eat",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
|
@ -48,30 +48,31 @@ export const eat = new Command(
|
|||
|
||||
i = 0;
|
||||
|
||||
for (const pokemon of inventory.pokemon as TPokemonSack) {
|
||||
if (!pokemon.name.toLowerCase().includes(eating.toLowerCase())) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// no more eating animals
|
||||
// for (const pokemon of inventory.pokemon as TPokemonSack) {
|
||||
// if (!pokemon.name.toLowerCase().includes(eating.toLowerCase())) {
|
||||
// i++;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
foundObject = pokemon as unknown as IObject;
|
||||
// foundObject = pokemon as unknown as IObject;
|
||||
|
||||
let shouldRemove = false;
|
||||
// let shouldRemove = false;
|
||||
|
||||
if (typeof pokemon.count !== "undefined") {
|
||||
if (pokemon.count > 1) {
|
||||
shouldRemove = false;
|
||||
((inventory.pokemon as TPokemonSack)[i].count as number)--;
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
// if (typeof pokemon.count !== "undefined") {
|
||||
// if (pokemon.count > 1) {
|
||||
// shouldRemove = false;
|
||||
// ((inventory.pokemon as TPokemonSack)[i].count as number)--;
|
||||
// } else {
|
||||
// shouldRemove = true;
|
||||
// }
|
||||
// } else {
|
||||
// shouldRemove = true;
|
||||
// }
|
||||
|
||||
if (shouldRemove) (inventory.pokemon as TPokemonSack).splice(i, 1);
|
||||
break;
|
||||
}
|
||||
// if (shouldRemove) (inventory.pokemon as TPokemonSack).splice(i, 1);
|
||||
// break;
|
||||
// }
|
||||
|
||||
i = 0;
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import type { User } from "@prisma/client";
|
||||
import Command from "@server/commands/Command";
|
||||
import { getInventory } from "@server/data/inventory";
|
||||
import prisma from "@server/data/prisma";
|
||||
|
||||
export const inventory = new Command(
|
||||
"inventory",
|
||||
|
@ -8,20 +10,59 @@ export const inventory = new Command(
|
|||
"inventory",
|
||||
"command.inventory.inventory",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
const inv = await getInventory(user.inventoryId);
|
||||
if (!inv) return;
|
||||
if (args[0]) {
|
||||
let decidedUser: User = user;
|
||||
decidedUser = (await prisma.user.findFirst({
|
||||
where: {
|
||||
name: {
|
||||
contains: args[0]
|
||||
}
|
||||
}
|
||||
})) as User;
|
||||
|
||||
const items = inv.items as unknown as IItem[];
|
||||
if (!decidedUser)
|
||||
decidedUser = (await prisma.user.findFirst({
|
||||
where: {
|
||||
id: {
|
||||
contains: args[0]
|
||||
}
|
||||
}
|
||||
})) as User;
|
||||
|
||||
return `Inventory: ${
|
||||
items
|
||||
.map(
|
||||
item =>
|
||||
`${item.emoji || ""}${item.name}${
|
||||
item.count ? ` (x${item.count})` : ""
|
||||
}`
|
||||
)
|
||||
.join(", ") || "(none)"
|
||||
}`;
|
||||
if (!decidedUser) return `User "${args[0]}" not found.`;
|
||||
|
||||
const inv = await getInventory(decidedUser.inventoryId);
|
||||
if (!inv)
|
||||
return `This message should be impossible to see because friend ${decidedUser.name}'s items inventory (and, by extension, their entire inventory) does not exist.`;
|
||||
|
||||
const items = inv.items as TInventoryItems;
|
||||
|
||||
return `Contents of ${decidedUser.name}'s inventory: ${
|
||||
items
|
||||
.map(
|
||||
(item: IItem) =>
|
||||
`${item.emoji || "📦"}${item.name}${
|
||||
item.count ? ` (x${item.count})` : ""
|
||||
}`
|
||||
)
|
||||
.join(", ") || "(none)"
|
||||
}`;
|
||||
} else {
|
||||
const inv = await getInventory(user.inventoryId);
|
||||
if (!inv)
|
||||
return `Apparently, you have no inventory. Not sure if that can be fixed, and I don't know how you got this message.`;
|
||||
const items = inv.items as TInventoryItems;
|
||||
|
||||
return `Contents of ${part.name}'s inventory: ${
|
||||
items
|
||||
.map(
|
||||
(item: IItem) =>
|
||||
`${item.emoji || "📦"}${item.name}${
|
||||
item.count ? ` (x${item.count})` : ""
|
||||
}`
|
||||
)
|
||||
.join(", ") || "(none)"
|
||||
}`;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { getInventory } from "@server/data/inventory";
|
||||
|
||||
export const pokemon = new Command(
|
||||
"pokemon",
|
||||
["pokemon"],
|
||||
"Look at your Pokemon",
|
||||
"pokemon",
|
||||
"command.inventory.pokemon",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
const inv = await getInventory(user.inventoryId);
|
||||
if (!inv) return;
|
||||
|
||||
const sack = inv.pokemon as TPokemonSack[];
|
||||
|
||||
return `Friend ${part.name}'s Pokémon: ${
|
||||
sack
|
||||
.map(
|
||||
(pokemon: IPokemon) =>
|
||||
`${pokemon.emoji || ""}${pokemon.name}${
|
||||
pokemon.count ? ` (x${pokemon.count})` : ""
|
||||
}`
|
||||
)
|
||||
.join(", ") || "(none)"
|
||||
}`;
|
||||
},
|
||||
true
|
||||
);
|
|
@ -49,7 +49,8 @@ export const take = new Command(
|
|||
addItem(fish, foundObject);
|
||||
break;
|
||||
case "pokemon":
|
||||
addItem(pokemon as unknown as IObject[], foundObject);
|
||||
// addItem(pokemon as unknown as IObject[], foundObject);
|
||||
return "Unlike other items, Pokémon have to be caught.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { prefixes } from "@server/commands/prefixes";
|
||||
import { getFishing, startFishing } from "@server/fish/fishers";
|
||||
import { reel } from "../fishing/reel";
|
||||
|
||||
export const autofish = new Command(
|
||||
"autofish",
|
||||
["autofish"],
|
||||
"Fish automatically",
|
||||
"data",
|
||||
"command.util.autofish",
|
||||
async props => {
|
||||
const fishing = getFishing(props.id, props.part.id);
|
||||
|
||||
if (!fishing) {
|
||||
startFishing(props.id, props.part.id, true, true);
|
||||
return `Our friend ${props.user.name} casts LURE into a water with AUTOFISH enabled. (${props.prefix}${reel.aliases[0]} to disable)`;
|
||||
} else {
|
||||
return `Your lure is already in the water (since ${(
|
||||
(Date.now() - fishing.t) /
|
||||
1000 /
|
||||
60
|
||||
).toFixed(2)} minutes ago).${
|
||||
fishing.autofish
|
||||
? ` (AUTOFISH is enabled)`
|
||||
: ` (${props.prefix}${reel.aliases[0]} in first to AUTOFISH)`
|
||||
}`;
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,30 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { getPokemonByID } from "@server/pokemon/pokedex";
|
||||
|
||||
export const pokedex = new Command(
|
||||
"pokedex",
|
||||
["pokedex", "dex"],
|
||||
"View a Pokémon in the Pokédex",
|
||||
"pokedex",
|
||||
"command.util.pokedex",
|
||||
async ({ args }) => {
|
||||
const num = parseInt(args[0]);
|
||||
if (isNaN(num)) return `Please provide a Pokémon ID.`;
|
||||
|
||||
const pokemon = getPokemonByID(num);
|
||||
|
||||
if (!pokemon) return `Pokémon with ID ${args[0]} not found.`;
|
||||
|
||||
return `ID: ${pokemon.pokeID} // Name: ${
|
||||
pokemon.name
|
||||
} // Type: ${pokemon.type.join("/")} // Base HP: ${
|
||||
pokemon.base.HP
|
||||
} // Base Attack: ${pokemon.base.Attack} // Base Defense: ${
|
||||
pokemon.base.Defense
|
||||
} // Base Sp. Attack: ${
|
||||
pokemon.base["Sp. Attack"]
|
||||
} // Base Sp. Defense: ${pokemon.base["Sp. Defense"]} // Base Speed: ${
|
||||
pokemon.base.Speed
|
||||
}`;
|
||||
}
|
||||
);
|
|
@ -11,7 +11,8 @@ export async function handleCommand(
|
|||
command: string,
|
||||
args: string[],
|
||||
prefix: string,
|
||||
part: IPart
|
||||
part: IPart,
|
||||
isDM: boolean = false
|
||||
): Promise<ICommandResponse | void> {
|
||||
let foundCommand: Command | undefined;
|
||||
|
||||
|
@ -60,7 +61,8 @@ export async function handleCommand(
|
|||
args,
|
||||
prefix,
|
||||
part,
|
||||
user
|
||||
user,
|
||||
isDM: isDM ?? false
|
||||
});
|
||||
|
||||
if (response) return { response };
|
||||
|
|
|
@ -9,14 +9,7 @@ import { addBack } from "@server/backs";
|
|||
import { prefixes } from "@server/commands/prefixes";
|
||||
import { Logger } from "@util/Logger";
|
||||
|
||||
export let fishers: Record<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
userId: string;
|
||||
t: number;
|
||||
}
|
||||
> = {};
|
||||
export let fishers: Record<string, TFisher> = {};
|
||||
|
||||
let cooldown = Date.now() + 5000;
|
||||
|
||||
|
@ -33,24 +26,24 @@ export async function tick() {
|
|||
|
||||
if (!winner) return;
|
||||
|
||||
const user = await getUser(winner.userId);
|
||||
const user = await getUser(winner.userID);
|
||||
|
||||
if (!user) {
|
||||
stopFishing(winner.id, winner.userId);
|
||||
stopFishing(winner.id, winner.userID, false);
|
||||
return;
|
||||
}
|
||||
|
||||
const inventory = await getInventory(user.inventoryId);
|
||||
|
||||
if (!inventory) {
|
||||
stopFishing(winner.id, winner.userId);
|
||||
stopFishing(winner.id, winner.userID, false);
|
||||
return;
|
||||
}
|
||||
|
||||
const r = Math.random();
|
||||
|
||||
if (r < 0.1) {
|
||||
stopFishing(winner.id, winner.userId);
|
||||
stopFishing(winner.id, winner.userID, winner.autofish);
|
||||
const animal = randomFish(inventory.location);
|
||||
addItem(inventory.fishSack as TFishSack, animal);
|
||||
await updateInventory(inventory);
|
||||
|
@ -63,14 +56,18 @@ export async function tick() {
|
|||
? "large"
|
||||
: animal.size < 100
|
||||
? "huge"
|
||||
: "massive";
|
||||
: animal.size < 200
|
||||
? "massive"
|
||||
: "gigantic";
|
||||
addBack(winner.id, {
|
||||
m: "sendchat",
|
||||
message: `Our good friend @${user.id} caught a ${size} ${
|
||||
animal.emoji || "🐟"
|
||||
}${animal.name}! ready to ${prefixes[0]}eat or ${
|
||||
prefixes[0]
|
||||
}fish again`
|
||||
}fish again${winner.autofish ? " (AUTOFISH is enabled)" : ""}`,
|
||||
isDM: winner.isDM,
|
||||
id: winner.userID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -79,14 +76,7 @@ export async function tick() {
|
|||
}
|
||||
|
||||
export async function startFisherTick() {
|
||||
let maybe = (await kvGet("fishers")) as Record<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
userId: string;
|
||||
t: number;
|
||||
}
|
||||
>;
|
||||
let maybe = (await kvGet("fishers")) as Record<string, TFisher>;
|
||||
|
||||
if (maybe) fishers = maybe;
|
||||
|
||||
|
@ -97,13 +87,33 @@ export function stopFisherTick() {
|
|||
removeTickEvent(tick);
|
||||
}
|
||||
|
||||
export function startFishing(id: string, userId: string) {
|
||||
fishers[id + "~" + userId] = { id, userId: userId, t: Date.now() };
|
||||
export function startFishing(
|
||||
id: string,
|
||||
userId: string,
|
||||
isDM: boolean = false,
|
||||
autofish: boolean = false
|
||||
) {
|
||||
fishers[id + "~" + userId] = {
|
||||
id,
|
||||
userID: userId,
|
||||
t: Date.now(),
|
||||
isDM,
|
||||
autofish
|
||||
};
|
||||
}
|
||||
|
||||
export function stopFishing(id: string, userId: string) {
|
||||
export function stopFishing(
|
||||
id: string,
|
||||
userId: string,
|
||||
autofish: boolean = false
|
||||
) {
|
||||
let key = id + "~" + userId;
|
||||
let fisher = fishers[key];
|
||||
delete fishers[key];
|
||||
|
||||
if (autofish) {
|
||||
startFishing(id, userId, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
export function getFishing(id: string, userId: string) {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import { Logger } from "@util/Logger";
|
||||
import { loadConfig } from "@util/config";
|
||||
|
||||
export const pokedex = loadConfig<TPokedex>("config/pokedex.yml", []);
|
||||
|
||||
const logger = new Logger("Pokédex");
|
||||
|
||||
export function getPokemonByID(id: number) {
|
||||
return pokedex.find(p => p.pokeID == id);
|
||||
}
|
|
@ -141,7 +141,8 @@ export class MPPNetBot {
|
|||
id: msg.sender._id,
|
||||
name: msg.sender.name,
|
||||
color: msg.sender.color
|
||||
}
|
||||
},
|
||||
isDM: true
|
||||
});
|
||||
|
||||
if (!command) return;
|
||||
|
@ -178,7 +179,12 @@ export class MPPNetBot {
|
|||
});
|
||||
|
||||
this.b.on("sendchat", msg => {
|
||||
this.sendChat(msg.message);
|
||||
// this.logger.debug("sendchat message:", msg);
|
||||
if (msg.isDM) {
|
||||
this.sendDM(msg.message, msg.id);
|
||||
} else {
|
||||
this.sendChat(msg.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -218,7 +224,7 @@ export class MPPNetBot {
|
|||
.split("\r")
|
||||
.join("")}`,
|
||||
_id: dm,
|
||||
reply_to: reply_to
|
||||
reply_to
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,7 @@ type TCommandCallback<User> = (props: {
|
|||
prefix: string;
|
||||
part: IPart;
|
||||
user: User;
|
||||
isDM: boolean;
|
||||
}) => Promise<string | void>;
|
||||
|
||||
interface CountComponent {
|
||||
|
@ -51,6 +52,7 @@ interface IFish extends IObject {
|
|||
|
||||
interface IPokemon extends IObject {
|
||||
id: number;
|
||||
pokeID: number;
|
||||
objtype: "pokemon";
|
||||
emoji?: string;
|
||||
name: string;
|
||||
|
@ -98,3 +100,13 @@ interface ILocation {
|
|||
objects: IObject[];
|
||||
hasSand: boolean;
|
||||
}
|
||||
|
||||
interface TFisher {
|
||||
id: string;
|
||||
userID: string;
|
||||
t: number;
|
||||
isDM: boolean;
|
||||
autofish: boolean;
|
||||
}
|
||||
|
||||
type TPokedex = IPokemon[];
|
||||
|
|
Loading…
Reference in New Issue