Merge branch 'dev'

This commit is contained in:
Hri7566 2024-09-23 18:17:03 -04:00
commit 1a8a272c87
14 changed files with 175 additions and 69 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -2,7 +2,3 @@
channel: channel:
id: "✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧" id: "✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧"
allowColorChanging: true allowColorChanging: true
- uri: wss://mppclone.com:8443
channel:
id: "test/fishing"
allowColorChanging: true

View File

@ -8,22 +8,22 @@
"start-discord": "bun src/discord/index.ts" "start-discord": "bun src/discord/index.ts"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.1.6" "@types/bun": "^1.1.9"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5.3.3" "typescript": "^5.3.3"
}, },
"dependencies": { "dependencies": {
"@prisma/client": "^5.16.1", "@prisma/client": "^5.19.1",
"@trpc/client": "next", "@trpc/client": "next",
"@trpc/server": "next", "@trpc/server": "next",
"@types/node": "^20.14.10", "@types/node": "^20.16.5",
"cli-markdown": "^3.4.0", "cli-markdown": "^3.4.0",
"discord.js": "^14.15.3", "discord.js": "^14.16.2",
"mpp-client-net": "^1.2.0", "mpp-client-net": "^1.2.3",
"prisma": "^5.16.1", "prisma": "^5.19.1",
"trpc-bun-adapter": "^1.1.1", "trpc-bun-adapter": "^1.1.2",
"yaml": "^2.4.5", "yaml": "^2.5.1",
"zod": "^3.23.8" "zod": "^3.23.8"
} }
} }

View File

@ -25,6 +25,7 @@ import { fid } from "./util/fid";
import { chance } from "./util/chance"; import { chance } from "./util/chance";
import { info } from "./general/info"; import { info } from "./general/info";
import { burger } from "./util/burger"; import { burger } from "./util/burger";
import { daily } from "./pokemon/daily";
// import { give } from "./inventory/give"; // import { give } from "./inventory/give";
interface ICommandGroup { interface ICommandGroup {
@ -54,15 +55,23 @@ commandGroups.push(fishingGroup);
const inventoryGroup: ICommandGroup = { const inventoryGroup: ICommandGroup = {
id: "inventory", id: "inventory",
displayName: "Inventory", displayName: "Inventory",
commands: [inventory, take, eat, sack, pokemon, yeet, burger /* give */] commands: [inventory, sack, pokemon, take, eat, yeet, burger /* give */]
}; };
commandGroups.push(inventoryGroup); commandGroups.push(inventoryGroup);
const pokemonGroup: ICommandGroup = {
id: "pokemon",
displayName: "Pokémon",
commands: [daily, pokedex]
};
commandGroups.push(pokemonGroup);
const utilGroup: ICommandGroup = { const utilGroup: ICommandGroup = {
id: "util", id: "util",
displayName: "Utility", displayName: "Utility",
commands: [data, setcolor, memory, autofish, pokedex, fid, chance] commands: [data, setcolor, memory, autofish, fid, chance]
}; };
commandGroups.push(utilGroup); commandGroups.push(utilGroup);

View File

@ -1,5 +1,7 @@
import Command from "@server/commands/Command"; import Command from "@server/commands/Command";
import { logger } from "@server/commands/handler";
import { getInventory, updateInventory } from "@server/data/inventory"; import { getInventory, updateInventory } from "@server/data/inventory";
import { removeItem } from "@server/items";
import { itemBehaviorMap, runBehavior } from "@server/items/behavior"; import { itemBehaviorMap, runBehavior } from "@server/items/behavior";
export const eat = new Command( export const eat = new Command(
@ -62,45 +64,9 @@ export const eat = new Command(
if (shouldRemove) { if (shouldRemove) {
if (foundObject.objtype == "fish") { if (foundObject.objtype == "fish") {
i = 0; removeItem(inventory.fishSack, foundObject);
for (const fish of inventory.fishSack as TFishSack) {
if (typeof fish.count !== "undefined") {
if (fish.count > 1) {
shouldRemove = false;
((inventory.fishSack as TFishSack)[i]
.count as number)--;
} else {
shouldRemove = true;
}
} else {
shouldRemove = true;
}
if (shouldRemove)
(inventory.fishSack as TFishSack).splice(i, 1);
break;
}
} else if (foundObject.objtype == "item") { } else if (foundObject.objtype == "item") {
i = 0; removeItem(inventory.items, foundObject);
for (const item of inventory.items as unknown as IItem[]) {
if (typeof item.count == "number") {
if (item.count > 1) {
shouldRemove = false;
((inventory.items as TInventoryItems)[i]
.count as number)--;
} else {
shouldRemove = true;
}
} else {
shouldRemove = true;
}
if (shouldRemove)
(inventory.items as TInventoryItems).splice(i, 1);
break;
}
} }
await updateInventory(inventory); await updateInventory(inventory);

View File

@ -0,0 +1,21 @@
import Command from "@server/commands/Command";
import { logger } from "@server/commands/handler";
import { claimDailyPokemon } from "@server/pokemon/daily";
export const daily = new Command(
"daily",
["daily", "dailypokemon"],
"Claim your daily Pokémon reward",
"daily",
"command.inventory.daily",
async ({ id, command, args, prefix, part, user }) => {
try {
const message = await claimDailyPokemon(user.id);
return message;
} catch (err) {
logger.error("Unable to perform daily claim:", err);
return `Congratulations, you broke the bot. Your daily reward might not work now.`;
}
},
true
);

View File

@ -1,15 +1,16 @@
import type { User } from "@prisma/client";
import prisma from "./prisma"; import prisma from "./prisma";
export async function createInventory(inventory: Partial<IInventory>) { export async function createInventory(inventory: Partial<IInventory>) {
return await prisma.inventory.create({ return (await prisma.inventory.create({
data: inventory data: inventory
}); })) as IInventory;
} }
export async function getInventory(id: IInventory["id"]) { export async function getInventory(id: IInventory["id"]) {
return await prisma.inventory.findUnique({ return (await prisma.inventory.findUnique({
where: { id } where: { id }
}); })) as IInventory;
} }
export async function updateInventory(inventory: Partial<IInventory>) { export async function updateInventory(inventory: Partial<IInventory>) {

View File

@ -108,7 +108,11 @@ export function hasFishTime(
export function getSizeString(cm: number) { export function getSizeString(cm: number) {
const size = const size =
cm < 30 cm < 5
? "microscopic"
: cm < 10
? "tiny"
: cm < 30
? "small" ? "small"
: cm < 60 : cm < 60
? "medium-sized" ? "medium-sized"

View File

@ -23,3 +23,26 @@ export function addItem(arr: IObject[], item: IObject) {
(arr[i].count as number) += inc; (arr[i].count as number) += inc;
} }
} }
export function removeItem(arr: IObject[], item: IObject, count = 1) {
let found = false;
let i = 0;
for (i = 0; i < arr.length; i++) {
if (item.id == arr[i].id) {
found = true;
break;
}
}
const foundItem = arr[i];
if (!found || !foundItem) return false;
if (typeof foundItem.count == "number" && foundItem.count > 1) {
foundItem.count -= count;
} else {
arr.splice(i, 1);
}
return true;
}

62
src/api/pokemon/daily.ts Normal file
View File

@ -0,0 +1,62 @@
import { kvGet, kvSet } from "@server/data/keyValueStore";
import { Logger } from "@util/Logger";
import { getRandomPokemon } from "./pokedex";
import { getInventory, updateInventory } from "@server/data/inventory";
import { getUser } from "@server/data/user";
import { addItem } from "@server/items";
import { getHHMMSS } from "@util/time";
const logger = new Logger("Daily Pokemon Manager");
const oneDay = 1000 * 60 * 60 * 24;
export async function claimDailyPokemon(userID: string) {
// Get the last daily timestamp
let timestampS = await kvGet(`pokedaily~${userID}`);
let timestamp = 0;
if (typeof timestampS == "string") {
try {
timestamp = parseInt(timestampS);
} catch (err) {
logger.warn("Unable to parse JSON:", err);
}
}
logger.debug("Time remaining:", Date.now() - timestamp);
// Check if it has been over a day
if (Date.now() - timestamp > oneDay) {
// Give them a random pokemon and set new timestamp
const pokemon = getRandomPokemon();
const item = {
id: pokemon.pokeID.toString(),
name: pokemon.name,
pokeID: pokemon.pokeID,
base: pokemon.base,
type: pokemon.type,
count: 1,
objtype: "pokemon"
} as IPokemon;
const user = await getUser(userID);
if (!user) throw new Error("No user found");
const inventory = await getInventory(user.inventoryId);
if (!inventory) throw new Error("No inventory found");
addItem(inventory.pokemon, pokemon);
await updateInventory(inventory);
kvSet(`pokedaily~${userID}`, Date.now().toString());
return `You claimed your daily Pokémon reward and got: ${
item.emoji || "📦"
}${item.name}${item.count ? ` (x${item.count})` : ""}`;
} else {
// or tell them no
return `You already claimed today! Time remaining: ${getHHMMSS(
oneDay - (Date.now() - timestamp),
false
)}`;
}
}

View File

@ -8,3 +8,8 @@ const logger = new Logger("Pokédex");
export function getPokemonByID(id: number) { export function getPokemonByID(id: number) {
return pokedex.find(p => p.pokeID == id); return pokedex.find(p => p.pokeID == id);
} }
export function getRandomPokemon() {
const r = Math.floor(Math.random() * pokedex.length);
return pokedex[r];
}

View File

@ -1,8 +1,9 @@
import { Logger } from "@util/Logger"; import { Logger } from "@util/Logger";
import { createInterface } from "readline"; import { createInterface } from "readline";
import { EventEmitter } from "events"; import { EventEmitter } from "node:events";
import gettRPC from "@util/api/trpc"; import gettRPC from "@util/api/trpc";
import { startAutorestart } from "@util/autorestart"; import { startAutorestart } from "@util/autorestart";
import { CosmicColor } from "@util/CosmicColor";
const trpc = gettRPC(process.env.CLI_FISHING_TOKEN as string); const trpc = gettRPC(process.env.CLI_FISHING_TOKEN as string);
@ -15,7 +16,7 @@ const b = new EventEmitter();
const rl = createInterface({ const rl = createInterface({
input: process.stdin, input: process.stdin,
output: process.stdout output: process.stdout
}); } as any);
const user = { const user = {
_id: "stdin", _id: "stdin",
@ -26,6 +27,12 @@ const user = {
(globalThis as unknown as any).rl = rl; (globalThis as unknown as any).rl = rl;
rl.setPrompt("> "); rl.setPrompt("> ");
rl.prompt(); rl.prompt();
setPrompt();
function setPrompt() {
const color = new CosmicColor(user.color);
rl.setPrompt(`\x1b[38;2;${color.r};${color.g};${color.b}m> `);
}
rl.on("line", async line => { rl.on("line", async line => {
if (line == "stop" || line == "exit") process.exit(); if (line == "stop" || line == "exit") process.exit();
@ -94,6 +101,7 @@ setInterval(async () => {
b.on("color", msg => { b.on("color", msg => {
if (typeof msg.color !== "string" || typeof msg.id !== "string") return; if (typeof msg.color !== "string" || typeof msg.id !== "string") return;
user.color = msg.color; user.color = msg.color;
setPrompt();
}); });
b.on("sendchat", msg => { b.on("sendchat", msg => {

View File

@ -1,22 +1,32 @@
export function getHHMMSS() { export function getTime(t = Date.now(), twelveHour = true) {
const now = Date.now(); const now = t;
const s = now / 1000; const s = now / 1000;
const m = s / 60; const m = s / 60;
const h = m / 60; const h = m / 60;
const hh = Math.floor(h % 12) const hours = Math.floor(h % (twelveHour ? 12 : 24))
.toString() .toString()
.padStart(2, "0"); .padStart(2, "0");
const mm = Math.floor(m % 60) const minutes = Math.floor(m % 60)
.toString() .toString()
.padStart(2, "0"); .padStart(2, "0");
const ss = Math.floor(s % 60) const seconds = Math.floor(s % 60)
.toString() .toString()
.padStart(2, "0"); .padStart(2, "0");
const ms = Math.floor(now % 1000) const milliseconds = Math.floor(now % 1000)
.toString() .toString()
.padStart(3, "0"); .padStart(3, "0");
return `${hh}:${mm}:${ss}.${ms}`; return {
hours,
minutes,
seconds,
milliseconds
};
}
export function getHHMMSS(t = Date.now(), twelveHour = true) {
const { hours, minutes, seconds, milliseconds } = getTime(t, twelveHour);
return `${hours}:${minutes}:${seconds}.${milliseconds}`;
} }

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

@ -21,7 +21,7 @@ interface IContextProps {
type TCommandCallback<User> = (props: IContextProps) => Promise<string | void>; type TCommandCallback<User> = (props: IContextProps) => Promise<string | void>;
interface CountComponent { interface ICountComponent {
count: number; count: number;
} }
@ -54,7 +54,7 @@ interface IFish extends IObject {
} }
interface IPokemon extends IObject { interface IPokemon extends IObject {
id: number; id: string;
pokeID: number; pokeID: number;
objtype: "pokemon"; objtype: "pokemon";
emoji?: string; emoji?: string;
@ -78,6 +78,7 @@ type TPokemonSack = JsonArray & IPokemon[];
interface IInventory { interface IInventory {
id: number; id: number;
balance: number; balance: number;
location: string;
items: TInventoryItems; items: TInventoryItems;
fishSack: TFishSack; fishSack: TFishSack;
@ -90,7 +91,7 @@ interface IBack<T extends string | unknown> extends Record<string, unknown> {
m: T; m: T;
} }
interface Backs extends Record<string, IBack<unknown>> { interface IBacks extends Record<string, IBack<unknown>> {
color: { color: {
m: "color"; m: "color";
}; };