Implement autofishing and Pokédex

This commit is contained in:
Hri7566 2024-02-24 11:12:23 -05:00
parent 1f8ef214e3
commit 1fc6c43611
19 changed files with 296 additions and 80 deletions

View File

@ -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];

View File

@ -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;
}),

View File

@ -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)` : ``
}`;
}
}
);

View File

@ -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}.`;
}

View File

@ -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",

View File

@ -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.`;
}
}
);

View File

@ -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()}.`;
}
);

View File

@ -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);

View File

@ -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;

View File

@ -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)"
}`;
}
}
);

View File

@ -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
);

View File

@ -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;

View File

@ -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)`
}`;
}
}
);

View File

@ -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
}`;
}
);

View File

@ -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 };

View File

@ -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) {

View File

@ -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);
}

View File

@ -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 {

12
src/util/types.d.ts vendored
View File

@ -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[];