A Typescript server emulator for Box Critters, a defunct virtual world.
1import { Server, Socket } from "https://deno.land/x/socket_io@0.2.0/mod.ts";
2import z from "zod";
3
4import * as items from "@/constants/items.ts";
5import * as types from "@/types.ts";
6
7export function listen(
8 _io: Server,
9 socket: Socket,
10 ctx: types.SocketHandlerContext,
11) {
12 socket.on("getShop", () => {
13 const _shopItems = items.shop as unknown as types.ShopData;
14 socket.emit("getShop", {
15 lastItem: _shopItems.lastItem.itemId,
16 freeItem: _shopItems.freeItem.itemId,
17 nextItem: _shopItems.nextItem.itemId,
18 collection: _shopItems.collection.map((item) => item.itemId),
19 });
20 });
21
22 socket.on("buyItem", (itemId: string) => {
23 if (!ctx.localPlayer || !ctx.localCrumb) return;
24
25 if (
26 z.object({
27 itemId: z.string().nonempty(),
28 }).strict().safeParse({ itemId: itemId }).success == false
29 ) return;
30
31 // ? Free item is excluded from this list because the game just sends the "/freeitem" code
32 const currentShop = items.shop;
33 const _shopItems = [
34 currentShop.lastItem,
35 currentShop.nextItem,
36 ...currentShop.collection,
37 ];
38
39 const target = _shopItems.find((item) => item.itemId == itemId)!;
40 if (!target) {
41 console.log(
42 "> There is no item in this week's shop with itemId:",
43 itemId,
44 );
45 return;
46 }
47
48 if (
49 ctx.localPlayer.coins >= target.cost &&
50 !ctx.localPlayer.inventory.includes(itemId)
51 ) {
52 console.log(
53 "[+] Bought item: " + itemId + " for " + target.cost + " coins",
54 );
55 ctx.localPlayer.coins -= target.cost;
56 ctx.localPlayer.inventory.push(itemId);
57
58 socket.emit("buyItem", { itemId: itemId });
59 socket.emit("updateCoins", { balance: ctx.localPlayer.coins });
60 }
61 });
62}