Make fish work
This commit is contained in:
parent
fa844d37cb
commit
ccdc021e96
|
@ -40,3 +40,8 @@ model LocationObjectStorage {
|
|||
id String @id
|
||||
objects Json @default("[]")
|
||||
}
|
||||
|
||||
model KeyValueStore {
|
||||
id Int @id @default(0)
|
||||
json Json @default("{}")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { getFishing, startFishing } from "@server/fish/fishers";
|
||||
|
||||
export const fish = new Command(
|
||||
"fish",
|
||||
|
@ -7,6 +8,17 @@ export const fish = new Command(
|
|||
"fish",
|
||||
"command.fishing.fish",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
return "There is no fishing yet, please come back later when I write the code for it";
|
||||
const fishing = getFishing(id, part.id);
|
||||
|
||||
if (!fishing) {
|
||||
startFishing(id, part.id);
|
||||
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).`;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { getInventory } from "@server/data/inventory";
|
||||
import { getFishing, stopFishing } from "@server/fish/fishers";
|
||||
import { locations } from "@server/fish/locations";
|
||||
|
||||
export const reel = new Command(
|
||||
"reel",
|
||||
["reel"],
|
||||
"Reel in and stop fishing",
|
||||
"fishing",
|
||||
"command.fishing.reel",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
const fishing = getFishing(id, part.id);
|
||||
if (fishing) {
|
||||
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.`;
|
||||
}
|
||||
}
|
||||
);
|
|
@ -23,16 +23,20 @@ export const help = new Command(
|
|||
"command.general.help",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
if (!args[0]) {
|
||||
return `__Fishing:__\n${commandGroups
|
||||
.map(
|
||||
group =>
|
||||
`${group.displayName}: ${group.commands
|
||||
.map(cmd =>
|
||||
cmd.visible ? cmd.aliases[0] : "<hidden>"
|
||||
)
|
||||
.join(", ")}`
|
||||
)
|
||||
.join("\n")}`;
|
||||
const list = [];
|
||||
|
||||
for (const group of commandGroups) {
|
||||
let list2 = [];
|
||||
|
||||
for (const cmd of group.commands) {
|
||||
if (cmd.visible) list2.push(cmd.aliases[0]);
|
||||
}
|
||||
|
||||
if (list2.length > 0)
|
||||
list.push(`${group.displayName}: ${list2.join(", ")}`);
|
||||
}
|
||||
|
||||
return `__Fishing:__\n${list.join("\n")}`;
|
||||
} else {
|
||||
const commands = commandGroups.flatMap(group => group.commands);
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { getInventory } from "@server/data/inventory";
|
||||
|
||||
export const inventory = new Command(
|
||||
"inventory",
|
||||
["inventory", "inv"],
|
||||
"Look at your inventory",
|
||||
"data",
|
||||
"command.util.inventory",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
const inventory = await getInventory(user.inventoryId);
|
||||
if (!inventory) return;
|
||||
|
||||
const items = inventory.items as unknown as IItem[];
|
||||
|
||||
return `Inventory: ${items
|
||||
.map(
|
||||
item =>
|
||||
`${item.emoji || ""}${item.name}${
|
||||
item.count ? ` (x${item.count})` : ""
|
||||
}`
|
||||
)
|
||||
.join(", ")}`;
|
||||
}
|
||||
);
|
|
@ -7,8 +7,11 @@ import { location } from "./fishing/location";
|
|||
import { go } from "./fishing/go";
|
||||
import { nearby } from "./fishing/nearby";
|
||||
import { look } from "./fishing/look";
|
||||
import { take } from "./fishing/take";
|
||||
import { inventory } from "./general/inventory";
|
||||
import { take } from "./inventory/take";
|
||||
import { inventory } from "./inventory/inventory";
|
||||
import { eat } from "./inventory/eat";
|
||||
import { sack } from "./inventory/sack";
|
||||
import { reel } from "./fishing/reel";
|
||||
|
||||
interface ICommandGroup {
|
||||
id: string;
|
||||
|
@ -18,26 +21,34 @@ interface ICommandGroup {
|
|||
|
||||
export const commandGroups: ICommandGroup[] = [];
|
||||
|
||||
const general: ICommandGroup = {
|
||||
const generalGroup: ICommandGroup = {
|
||||
id: "general",
|
||||
displayName: "General",
|
||||
commands: [help, inventory]
|
||||
commands: [help]
|
||||
};
|
||||
|
||||
commandGroups.push(general);
|
||||
commandGroups.push(generalGroup);
|
||||
|
||||
const fishing: ICommandGroup = {
|
||||
const fishingGroup: ICommandGroup = {
|
||||
id: "fishing",
|
||||
displayName: "Fishing",
|
||||
commands: [fish, location, go, nearby, look, take]
|
||||
commands: [fish, reel, location, go, nearby, look]
|
||||
};
|
||||
|
||||
commandGroups.push(fishing);
|
||||
commandGroups.push(fishingGroup);
|
||||
|
||||
const util: ICommandGroup = {
|
||||
const inventoryGroup: ICommandGroup = {
|
||||
id: "inventory",
|
||||
displayName: "Inventory",
|
||||
commands: [inventory, take, eat, sack]
|
||||
};
|
||||
|
||||
commandGroups.push(inventoryGroup);
|
||||
|
||||
const utilGroup: ICommandGroup = {
|
||||
id: "util",
|
||||
displayName: "Utility",
|
||||
commands: [data, setcolor]
|
||||
};
|
||||
|
||||
commandGroups.push(util);
|
||||
commandGroups.push(utilGroup);
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
import { addBack } from "@server/backs";
|
||||
import Command from "@server/commands/Command";
|
||||
import { logger } from "@server/commands/handler";
|
||||
import { getInventory, updateInventory } from "@server/data/inventory";
|
||||
import { CosmicColor } from "@util/CosmicColor";
|
||||
|
||||
export const eat = new Command(
|
||||
"eat",
|
||||
["eat"],
|
||||
"Eat literally anything in your inventory",
|
||||
"eat <something>",
|
||||
"command.inventory.eat",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
const eating = args[0];
|
||||
if (!eating) return `What do you want to ${prefix}eat?`;
|
||||
const inventory = await getInventory(user.inventoryId);
|
||||
if (!inventory) return;
|
||||
|
||||
let foundObject: IObject | undefined;
|
||||
let tryChangingColor = false;
|
||||
|
||||
for (const item of inventory.items as unknown as IItem[]) {
|
||||
if (!item.name.toLowerCase().includes(eating.toLowerCase()))
|
||||
continue;
|
||||
|
||||
foundObject = item;
|
||||
|
||||
let shouldRemove = false;
|
||||
|
||||
if (item.count) {
|
||||
if (item.count > 1) {
|
||||
shouldRemove = false;
|
||||
((inventory.items as unknown as IItem[])[
|
||||
(inventory.items as unknown as IItem[]).indexOf(item)
|
||||
].count as number)--;
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
|
||||
if (shouldRemove)
|
||||
(inventory.items as unknown as IItem[]).splice(
|
||||
(inventory.items as unknown as IItem[]).indexOf(item, 1)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
for (const pokemon of inventory.pokemon as unknown as IPokemon[]) {
|
||||
if (!pokemon.name.toLowerCase().includes(eating.toLowerCase()))
|
||||
continue;
|
||||
|
||||
foundObject = pokemon as unknown as IObject;
|
||||
|
||||
let shouldRemove = false;
|
||||
|
||||
if (pokemon.count) {
|
||||
if (pokemon.count > 1) {
|
||||
shouldRemove = false;
|
||||
((inventory.pokemon as unknown as IPokemon[])[
|
||||
(inventory.pokemon as unknown as IPokemon[]).indexOf(
|
||||
pokemon
|
||||
)
|
||||
].count as number)--;
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
|
||||
if (shouldRemove)
|
||||
(inventory.pokemon as unknown as IPokemon[]).splice(
|
||||
(inventory.pokemon as unknown as IPokemon[]).indexOf(
|
||||
pokemon,
|
||||
1
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
for (const fish of inventory.fishSack as unknown as IFish[]) {
|
||||
if (!fish.name.toLowerCase().includes(eating.toLowerCase()))
|
||||
continue;
|
||||
|
||||
foundObject = fish as unknown as IObject;
|
||||
|
||||
let shouldRemove = false;
|
||||
|
||||
if (fish.count) {
|
||||
if (fish.count > 1) {
|
||||
shouldRemove = false;
|
||||
((inventory.fishSack as unknown as IFish[])[
|
||||
(inventory.fishSack as unknown as IFish[]).indexOf(fish)
|
||||
].count as number)--;
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
|
||||
if (shouldRemove)
|
||||
(inventory.fishSack as unknown as IFish[]).splice(
|
||||
(inventory.fishSack as unknown as IFish[]).indexOf(fish, 1)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundObject) return `You don't have "${eating}" to eat.`;
|
||||
if (foundObject.objtype == "fish") {
|
||||
tryChangingColor = true;
|
||||
}
|
||||
|
||||
await updateInventory(inventory);
|
||||
|
||||
if (!tryChangingColor) {
|
||||
if (foundObject.id == "sand") {
|
||||
return `Our friend ${part.name} ate of his/her ${foundObject.name}.`;
|
||||
} else {
|
||||
return `Our friend ${part.name} ate his/her ${foundObject.name}.`;
|
||||
}
|
||||
} else {
|
||||
const r = Math.random();
|
||||
|
||||
if (r < 0.3) {
|
||||
const color = new CosmicColor(
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255)
|
||||
);
|
||||
|
||||
addBack(id, {
|
||||
m: "color",
|
||||
id: part.id,
|
||||
color: color.toHexa()
|
||||
});
|
||||
|
||||
return `Our friend ${part.name} at his/her ${
|
||||
foundObject.name
|
||||
} and it made him/her turn ${color.getName().toLowerCase()}.`;
|
||||
} else {
|
||||
return `Our friend ${part.name} at his/her ${foundObject.name}.`;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,27 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { getInventory } from "@server/data/inventory";
|
||||
|
||||
export const inventory = new Command(
|
||||
"inventory",
|
||||
["inventory", "inv", "i"],
|
||||
"Look at your inventory",
|
||||
"inventory",
|
||||
"command.inventory.inventory",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
const inv = await getInventory(user.inventoryId);
|
||||
if (!inv) return;
|
||||
|
||||
const items = inv.items as unknown as IItem[];
|
||||
|
||||
return `Inventory: ${
|
||||
items
|
||||
.map(
|
||||
item =>
|
||||
`${item.emoji || ""}${item.name}${
|
||||
item.count ? ` (x${item.count})` : ""
|
||||
}`
|
||||
)
|
||||
.join(", ") || "(none)"
|
||||
}`;
|
||||
}
|
||||
);
|
|
@ -0,0 +1,27 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { getInventory } from "@server/data/inventory";
|
||||
|
||||
export const sack = new Command(
|
||||
"sack",
|
||||
["sack", "caught"],
|
||||
"Look at your fish sack",
|
||||
"sack",
|
||||
"command.inventory.sack",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
const inv = await getInventory(user.inventoryId);
|
||||
if (!inv) return;
|
||||
|
||||
const fishSack = inv.fishSack as TFishSack;
|
||||
|
||||
return `Contents of ${part.name}'s fish sack: ${
|
||||
fishSack
|
||||
.map(
|
||||
(fish: IFish) =>
|
||||
`${fish.emoji || ""}${fish.name}${
|
||||
fish.count ? ` (x${fish.count})` : ""
|
||||
}`
|
||||
)
|
||||
.join(", ") || "(none)"
|
||||
}`;
|
||||
}
|
||||
);
|
|
@ -1,8 +1,8 @@
|
|||
import Command from "@server/commands/Command";
|
||||
import { logger } from "@server/commands/handler";
|
||||
import { getInventory, updateInventory } from "@server/data/inventory";
|
||||
import { locations } from "@server/fish/locations";
|
||||
import { go } from "./go";
|
||||
import { locations, saveObjects } from "@server/fish/locations";
|
||||
import { go } from "../fishing/go";
|
||||
import { addItem } from "@server/items";
|
||||
|
||||
export const take = new Command(
|
||||
|
@ -10,7 +10,7 @@ export const take = new Command(
|
|||
["take"],
|
||||
"Take something from your surroundings",
|
||||
"take <something>",
|
||||
"command.fishing.take",
|
||||
"command.inventory.take",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
let taking = args[0];
|
||||
|
||||
|
@ -34,6 +34,9 @@ export const take = new Command(
|
|||
for (const obj of loc.objects) {
|
||||
if (obj.name.toLowerCase().includes(taking.toLowerCase()))
|
||||
foundObject = obj;
|
||||
|
||||
loc.objects.splice(loc.objects.indexOf(obj), 1);
|
||||
await saveObjects();
|
||||
}
|
||||
|
||||
if (!foundObject) return `There is no "${taking}" here.`;
|
||||
|
@ -57,6 +60,7 @@ export const take = new Command(
|
|||
(inventory as any).pokemon = pokemon;
|
||||
|
||||
await updateInventory(inventory);
|
||||
|
||||
return `You picked up the ${foundObject.name}.`;
|
||||
}
|
||||
);
|
|
@ -8,5 +8,6 @@ export const data = new Command(
|
|||
"command.util.data",
|
||||
async props => {
|
||||
return JSON.stringify(props);
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
|
|
@ -17,5 +17,6 @@ export const setcolor = new Command(
|
|||
});
|
||||
|
||||
return "Attempting to set color.";
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import prisma from "./prisma";
|
||||
|
||||
export async function createKeyValueStore() {
|
||||
return await prisma.keyValueStore.create({
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
|
||||
export async function getkvInternal() {
|
||||
const kv = await prisma.keyValueStore.findUnique({
|
||||
where: { id: 0 }
|
||||
});
|
||||
|
||||
if (!kv) return await createKeyValueStore();
|
||||
return kv;
|
||||
}
|
||||
|
||||
export async function kvSet(key: string, value: any) {
|
||||
const kv = await getkvInternal();
|
||||
|
||||
(kv.json as any)[key] = value;
|
||||
|
||||
return await prisma.keyValueStore.update({
|
||||
where: {
|
||||
id: 0
|
||||
},
|
||||
data: {
|
||||
json: kv.json as any
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function kvGet(key: string) {
|
||||
const kv = await getkvInternal();
|
||||
|
||||
return (kv.json as any)[key];
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
import { kvGet, kvSet } from "@server/data/keyValueStore";
|
||||
import { getObjectStorage } from "@server/data/location";
|
||||
import { addTickEvent, removeTickEvent } from "@util/tick";
|
||||
import { randomFish } from "./fish";
|
||||
import { getUser } from "@server/data/user";
|
||||
import { getInventory, updateInventory } from "@server/data/inventory";
|
||||
import { addItem } from "@server/items";
|
||||
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;
|
||||
}
|
||||
> = {};
|
||||
|
||||
let cooldown = Date.now() + 5000;
|
||||
|
||||
const logger = new Logger("Fishermen");
|
||||
|
||||
export async function tick() {
|
||||
if (Date.now() > cooldown) {
|
||||
cooldown = Date.now() + 5000;
|
||||
|
||||
let winner =
|
||||
Object.values(fishers)[
|
||||
Math.floor(Math.random() * Object.values(fishers).length)
|
||||
];
|
||||
|
||||
if (!winner) return;
|
||||
|
||||
const user = await getUser(winner.userId);
|
||||
|
||||
if (!user) {
|
||||
stopFishing(winner.id, winner.userId);
|
||||
return;
|
||||
}
|
||||
|
||||
const inventory = await getInventory(user.inventoryId);
|
||||
|
||||
if (!inventory) {
|
||||
stopFishing(winner.id, winner.userId);
|
||||
return;
|
||||
}
|
||||
|
||||
const r = Math.random();
|
||||
|
||||
if (r < 0.1) {
|
||||
stopFishing(winner.id, winner.userId);
|
||||
const animal = randomFish(inventory.location);
|
||||
addItem(inventory.fishSack as TFishSack, animal);
|
||||
await updateInventory(inventory);
|
||||
const size =
|
||||
animal.size < 30
|
||||
? "small"
|
||||
: animal.size < 60
|
||||
? "medium-sized"
|
||||
: animal.size < 75
|
||||
? "large"
|
||||
: animal.size < 100
|
||||
? "huge"
|
||||
: "massive";
|
||||
addBack(winner.id, {
|
||||
m: "sendchat",
|
||||
message: `Our good friend ${user.name} caught a ${size} ${
|
||||
animal.emoji || "🐟"
|
||||
}${animal.name}! ready to ${prefixes[0]}eat or ${
|
||||
prefixes[0]
|
||||
}fish again`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await kvSet("fishers", fishers);
|
||||
}
|
||||
|
||||
export async function startFisherTick() {
|
||||
let maybe = (await kvGet("fishers")) as Record<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
userId: string;
|
||||
t: number;
|
||||
}
|
||||
>;
|
||||
|
||||
if (maybe) fishers = maybe;
|
||||
|
||||
addTickEvent(tick);
|
||||
}
|
||||
|
||||
export function stopFisherTick() {
|
||||
removeTickEvent(tick);
|
||||
}
|
||||
|
||||
export function startFishing(id: string, userId: string) {
|
||||
fishers[id + "~" + userId] = { id, userId: userId, t: Date.now() };
|
||||
}
|
||||
|
||||
export function stopFishing(id: string, userId: string) {
|
||||
let key = id + "~" + userId;
|
||||
delete fishers[key];
|
||||
}
|
||||
|
||||
export function getFishing(id: string, userId: string) {
|
||||
return fishers[id + "~" + userId];
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
import "./api/server";
|
||||
import "./cli/readline";
|
||||
import { startFisherTick } from "./fish/fishers";
|
||||
import { startObjectTimers } from "./fish/locations";
|
||||
|
||||
startObjectTimers();
|
||||
await startFisherTick();
|
||||
|
|
|
@ -153,7 +153,7 @@ export class MPPNetBot {
|
|||
try {
|
||||
const backs = (await trpc.backs.query()) as IBack<unknown>[];
|
||||
if (backs.length > 0) {
|
||||
this.logger.debug(backs);
|
||||
// this.logger.debug(backs);
|
||||
for (const back of backs) {
|
||||
if (typeof back.m !== "string") return;
|
||||
this.b.emit(back.m, back);
|
||||
|
@ -175,6 +175,10 @@ export class MPPNetBot {
|
|||
}
|
||||
]);
|
||||
});
|
||||
|
||||
this.b.on("sendchat", msg => {
|
||||
this.sendChat(msg.message);
|
||||
});
|
||||
}
|
||||
|
||||
public sendChat(text: string, reply?: string) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,12 @@
|
|||
import { kvGet, kvSet } from "@server/data/keyValueStore";
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test("Key value store saves, loads, and deletes", async () => {
|
||||
await kvSet("test", 1);
|
||||
const val = await kvGet("test");
|
||||
expect(val).toBe(1);
|
||||
|
||||
await kvSet("test", undefined);
|
||||
const val2 = await kvGet("test");
|
||||
expect(val2).toBeUndefined();
|
||||
});
|
Loading…
Reference in New Issue