167 lines
No EOL
5.5 KiB
TypeScript
167 lines
No EOL
5.5 KiB
TypeScript
import { Image } from 'https://deno.land/x/imagescript@1.3.0/mod.ts';
|
|
import chalk from "https://deno.land/x/chalk_deno@v4.1.1-deno/source/index.js"
|
|
import { join } from "https://deno.land/std@0.224.0/path/mod.ts";
|
|
|
|
import { rooms, spawnRoom } from "./constants/world.ts";
|
|
import { Room, LocalPlayer, PlayerCrumb } from "./types.ts";
|
|
|
|
/** Condenses the local player variable into data that is sufficient enough for other clients */
|
|
export function makeCrumb(player: LocalPlayer, roomId: string): PlayerCrumb {
|
|
return {
|
|
i: player.playerId,
|
|
n: player.nickname,
|
|
c: player.critterId,
|
|
x: player.x,
|
|
y: player.y,
|
|
r: player.rotation,
|
|
g: player.gear,
|
|
|
|
// message & emote
|
|
m: "",
|
|
e: "",
|
|
|
|
_roomId: roomId
|
|
}
|
|
}
|
|
|
|
// TODO: use the correct triggers for the active party
|
|
export async function getTrigger(player: LocalPlayer, roomId: string, partyId: string) {
|
|
const room = rooms[roomId][partyId];
|
|
if (!room) {
|
|
console.log(chalk.red(`[!] Cannot find room: "${roomId}@${partyId}"!`));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
//@ts-ignore: Deno lint
|
|
const treasureBuffer = await Deno.readFile(room.media.treasure?.replace('..','public'));
|
|
const treasure = await Image.decode(treasureBuffer);
|
|
if (!treasure) throw new Error('Missing map server for room "' + roomId + '"!');
|
|
|
|
const pixel = treasure.getPixelAt(player.x, player.y);
|
|
const r = (pixel >> 24) & 0xFF, g = (pixel >> 16) & 0xFF, b = (pixel >> 8) & 0xFF;
|
|
const hexCode = ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0');
|
|
|
|
const trigger = room.triggers.find((trigger) => trigger.hex == hexCode);
|
|
if (trigger) {
|
|
return trigger.server;
|
|
} else {
|
|
return null;
|
|
}
|
|
} catch(e) {
|
|
console.warn(chalk.red('[!] Caught error while checking for activated trigger.'), e);
|
|
}
|
|
}
|
|
|
|
export function getNewCodeItem(player: LocalPlayer, items: Array<string>) {
|
|
const itemsSet = new Set(player.inventory);
|
|
const available = items.filter(item => !itemsSet.has(item));
|
|
return available.length === 0 ? null : available[Math.floor(Math.random() * available.length)];
|
|
}
|
|
|
|
/**
|
|
* Indexes the /media/rooms directory for all versions of all rooms
|
|
* @returns All versions of every room
|
|
*/
|
|
export async function indexRoomData() {
|
|
const _roomData: Record<string, Record<string, Room>> = {};
|
|
|
|
const basePath = join(Deno.cwd(), 'public', 'media', 'rooms');
|
|
const _rooms = Deno.readDir(basePath);
|
|
|
|
for await (const room of _rooms) {
|
|
if (room.isDirectory) {
|
|
_roomData[room.name] = {};
|
|
const roomPath = join(basePath, room.name);
|
|
const versions = Deno.readDir(roomPath);
|
|
for await (const version of versions) {
|
|
if (version.isDirectory) {
|
|
const versionPath = join(roomPath, version.name, 'data.json');
|
|
try {
|
|
const data = await Deno.readTextFile(versionPath);
|
|
_roomData[room.name][version.name] = JSON.parse(data);
|
|
} catch(_) {
|
|
console.log(chalk.red('[!] "%s@%s" is missing a data.json file'), room.name, version.name);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return _roomData
|
|
}
|
|
|
|
export async function getAccount(nickname?: string) {
|
|
let accounts = [];
|
|
try {
|
|
const data = await Deno.readTextFile('accounts.json');
|
|
accounts = JSON.parse(data);
|
|
} catch (error) {
|
|
if (error instanceof Deno.errors.NotFound) {
|
|
console.log(chalk.gray('Persistent login JSON is missing, using blank JSON array..'));
|
|
accounts = [];
|
|
} else {
|
|
console.log(chalk.red('[!] Failure to fetch persistent login data with nickname: '), nickname);
|
|
throw error;
|
|
};
|
|
}
|
|
|
|
if (nickname) {
|
|
const existingAccount = accounts.find((player: { nickname: string }) => player.nickname == nickname);
|
|
if (existingAccount) {
|
|
return {
|
|
all: accounts,
|
|
individual: existingAccount,
|
|
}
|
|
} else {
|
|
return {
|
|
all: accounts,
|
|
individual: null
|
|
}
|
|
}
|
|
} else {
|
|
return accounts;
|
|
}
|
|
}
|
|
|
|
export async function updateAccount(nickname: string, property: string, value: unknown) {
|
|
if (["x", "y", "rotation", "_partyId"].includes(property)) return;
|
|
const accounts = await getAccount(nickname);
|
|
|
|
accounts.individual[property] = value;
|
|
await Deno.writeTextFile('accounts.json', JSON.stringify(accounts.all, null, 2));
|
|
}
|
|
|
|
export function trimAccount(player: LocalPlayer) {
|
|
for (const key of [
|
|
"critterId",
|
|
"x",
|
|
"y",
|
|
"rotation",
|
|
"_partyId",
|
|
"_mods"
|
|
]) {
|
|
delete player[key];
|
|
}
|
|
return player;
|
|
}
|
|
|
|
export function expandAccount(player: LocalPlayer) {
|
|
const defaultPos = rooms[spawnRoom].default;
|
|
player.x = defaultPos.startX;
|
|
player.y = defaultPos.startY;
|
|
player.rotation = defaultPos.startR;
|
|
return player;
|
|
}
|
|
|
|
export function getDirection(x: number, y: number, targetX: number, targetY: number) {
|
|
const a = Math.floor((180 * Math.atan2(targetX - x, y - targetY)) / Math.PI);
|
|
return a < 0 ? a + 360 : a;
|
|
}
|
|
|
|
export async function createAccount(player: LocalPlayer) {
|
|
const accounts = await getAccount();
|
|
accounts.push(trimAccount(player));
|
|
|
|
await Deno.writeTextFile('accounts.json', JSON.stringify(accounts, null, 2));
|
|
} |