diff --git a/src/lib/server/ably-server.ts b/src/lib/server/ably-server.ts index 4baa34b..665c5aa 100644 --- a/src/lib/server/ably-server.ts +++ b/src/lib/server/ably-server.ts @@ -62,3 +62,19 @@ export async function moveRoom( svgRef: room.svgRef, }); } + +export async function unclaimRooms( + gameId: number, + rooms: { roomId: bigint; svgRef: bigint }[], +) { + await prisma.claimedRoom.deleteMany({ + where: { + gameId, + roomId: { in: rooms.map((room) => Number(room.roomId)) }, + }, + }); + ablyServer.channels.get("game:" + gameId + ":positions").publish( + "unclaim", + rooms.map((room) => room.svgRef), + ); +} diff --git a/src/routes/game/[gameId=id]/+page.svelte b/src/routes/game/[gameId=id]/+page.svelte index b059753..564b9f2 100644 --- a/src/routes/game/[gameId=id]/+page.svelte +++ b/src/routes/game/[gameId=id]/+page.svelte @@ -24,7 +24,13 @@ currSvgRef: $positionsMessage.data.svgRef, }; } - movePlayer($positionsMessage.data.userId, $positionsMessage.data.svgRef); + const svgRef = $positionsMessage.data.svgRef; + if (!data.claimedRooms.includes(svgRef)) { + data.claimedRooms.push(svgRef); + const pointIcon = map.getElmWhere("point", svgRef) as SVGImageElement; + if (pointIcon) map.removeIcon(pointIcon); + } + movePlayer($positionsMessage.data.userId, svgRef); } const playerMessage = getChannel( "player:" + $page.params.gameId + ":" + data.userId, @@ -36,11 +42,6 @@ function movePlayer(userId: number, svgRef: number) { data.players[userId].currSvgRef = svgRef; - if (!data.claimedRooms.includes(svgRef)) { - data.claimedRooms.push(svgRef); - const pointIcon = map.getElmWhere("point", svgRef) as SVGImageElement; - if (pointIcon) map.removeIcon(pointIcon); - } // A position update could occur before the map has finished loading. // This is common for the player's own position after they answer a question // since they are redirected to this page before the new position is published diff --git a/src/routes/game/[gameId=id]/shop/[itemId=id]/buy/+server.ts b/src/routes/game/[gameId=id]/shop/[itemId=id]/buy/+server.ts index 0aa081f..a30f7d1 100644 --- a/src/routes/game/[gameId=id]/shop/[itemId=id]/buy/+server.ts +++ b/src/routes/game/[gameId=id]/shop/[itemId=id]/buy/+server.ts @@ -1,6 +1,10 @@ import { error } from "@sveltejs/kit"; import prisma from "$lib/server/prisma"; -import { moveRoom, updateRealtimePoints } from "$lib/server/ably-server"; +import { + moveRoom, + unclaimRooms, + updateRealtimePoints, +} from "$lib/server/ably-server"; import type { User } from "@prisma/client"; type ActionDetails = { @@ -101,6 +105,7 @@ const ACTIONS: { [key: string]: (details: ActionDetails) => Promise } = { ); }, + // actionParams is an integer number of points to subtract subtractRandPlayerPoints: async ({ playerId, gameId, actionParams }) => { const randPlayers: { id: bigint; @@ -122,6 +127,33 @@ const ACTIONS: { [key: string]: (details: ActionDetails) => Promise } = { }); updateRealtimePoints(gameId, Number(randPlayer.userId), newPoints); }, + + // actionParams is an integer number of rooms (e.g: "5" -> unclaim 5 rooms) + unclaimAbsoluteRooms: async ({ gameId, actionParams }) => { + const rooms: { roomId: bigint; svgRef: bigint }[] = await prisma.$queryRaw` + SELECT roomId + FROM ClaimedRoom + WHERE gameId = ${gameId} + ORDER BY rand() + LIMIT ${+actionParams}`; + if (rooms.length === 0) error(400, "No rooms available to unclaim!"); + await unclaimRooms(gameId, rooms); + }, + + // actionParams is a float percentage (e.g: "50" -> unclaim 50% of rooms) + unclaimPercentageRooms: async ({ gameId, actionParams }) => { + const rooms: { roomId: bigint; svgRef: bigint }[] = await prisma.$queryRaw` + SELECT roomId + FROM ClaimedRoom + WHERE gameId = ${gameId} + ORDER BY rand()`; + if (rooms.length === 0) error(400, "No rooms available to unclaim!"); + // MySQL doesn't support dynamic limits, so need to limit from Javascript + await unclaimRooms( + gameId, + rooms.slice(0, (rooms.length * +actionParams) / 100), + ); + }, }; export const GET = async ({ params, locals }) => {