From 87f8add86462abced54a749788a496d6fa0e8880 Mon Sep 17 00:00:00 2001 From: Kim Ravn Hansen Date: Tue, 4 Nov 2025 08:57:59 +0100 Subject: [PATCH] refactor --- .gitignore | 2 + frontend/dungeon_studio.js | 104 +++++++++++++++++++++---------------- models/player.js | 7 +-- models/session.js | 9 ++-- seeders/characerSeeder.js | 4 +- server.js | 1 + utils/id.js | 6 +-- utils/regex.js | 2 +- utils/tui.js | 2 +- 9 files changed, 78 insertions(+), 59 deletions(-) diff --git a/.gitignore b/.gitignore index 9a5aced..092d7a1 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +resources + # Logs logs *.log diff --git a/frontend/dungeon_studio.js b/frontend/dungeon_studio.js index 866c0e3..e20b804 100755 --- a/frontend/dungeon_studio.js +++ b/frontend/dungeon_studio.js @@ -13,35 +13,47 @@ import { Orientation } from "./ascii_types"; /** Dungeon Generator - generates TileMaps populated with rooms, traps, encounters, etc. */ class DungeonFactory { /** @type {number} */ - roomCount; + #roomCount; /** @type {RoomConfig[]} */ - rooms; + #rooms; /** @type {TileMap} */ - map; + #map; + + get roomCount() { + return this.#roomCount; + } + + get rooms() { + return this.#rooms; + } + + get map() { + return this.#map; + } get width() { - return this.map.width; + return this.#map.width; } get height() { - return this.map.height; + return this.#map.height; } /** * @param {number} width * @param {number} height - * @param {number} roomCount + * @param {number} #roomCount */ constructor(width, height, roomCount) { - this.roomCount = roomCount | 0; - this.rooms = []; + this.#roomCount = roomCount | 0; + this.#rooms = []; // 2d array of pure wall tiles const tiles = new Array(height | 0).fill().map(() => Array(width | 0).fill(Tile.createWall())); - this.map = new TileMap(tiles); + this.#map = new TileMap(tiles); } generate() { @@ -52,18 +64,18 @@ class DungeonFactory { this.addFeatures(); this.addPlayerStart(); this.addPortals(); - return this.map.toString(CharType.TYPE_ID); + return this.#map.toString(CharType.TYPE_ID); } generateRooms() { - this.rooms = []; - const maxAttempts = this.roomCount * 10; + this.#rooms = []; + const maxAttempts = this.#roomCount * 10; let attempts = 0; - while (this.rooms.length < this.roomCount && attempts < maxAttempts) { + while (this.#rooms.length < this.#roomCount && attempts < maxAttempts) { const room = this.generateRoom(); if (room && !this.roomOverlaps(room)) { - this.rooms.push(room); + this.#rooms.push(room); this.carveRoom(room); } attempts++; @@ -83,7 +95,7 @@ class DungeonFactory { } roomOverlaps(newRoom) { - return this.rooms.some( + return this.#rooms.some( (room) => newRoom.x < room.x + room.width + 2 && newRoom.x + newRoom.width + 2 > room.x && @@ -95,26 +107,26 @@ class DungeonFactory { carveRoom(room) { for (let y = room.y; y < room.y + room.height; y++) { for (let x = room.x; x < room.x + room.width; x++) { - this.map.tiles[y][x] = Tile.createFloor(); + this.#map.tiles[y][x] = Tile.createFloor(); } } } connectRooms() { - if (this.rooms.length < 2) return; + if (this.#rooms.length < 2) return; // Connect each room to at least one other room - for (let i = 1; i < this.rooms.length >> 1; i++) { - const roomA = this.rooms[i - 1]; - const roomB = this.rooms[i]; + for (let i = 1; i < this.#rooms.length >> 1; i++) { + const roomA = this.#rooms[i - 1]; + const roomB = this.#rooms[i]; this.createCorridor(roomA, roomB); } // Add some extra connections for more interesting layouts - const extraConnections = Math.floor(this.rooms.length / 3); + const extraConnections = Math.floor(this.#rooms.length / 3); for (let i = 0; i < extraConnections; i++) { - const roomA = this.rooms[this.random(0, this.rooms.length - 1)]; - const roomB = this.rooms[this.random(0, this.rooms.length - 1)]; + const roomA = this.#rooms[this.random(0, this.#rooms.length - 1)]; + const roomB = this.#rooms[this.random(0, this.#rooms.length - 1)]; if (roomA !== roomB) { this.createCorridor(roomA, roomB); } @@ -138,7 +150,7 @@ class DungeonFactory { for (let x = 0; x < this.width; x++) { // - if (this.map.get(x, y).isWall()) { + if (this.#map.get(x, y).isWall()) { continue; } @@ -180,7 +192,7 @@ class DungeonFactory { row.push(Tile.createWall()); // Initial wall tile on this row for (let x = dungeonStartX; x <= dungeonEndX; x++) { /**/ - const tile = this.map.get(x, y); + const tile = this.#map.get(x, y); row.push(tile); } row.push(Tile.createWall()); // Final wall tile on this row @@ -190,7 +202,7 @@ class DungeonFactory { // Final row is all walls newTiles.push(new Array(newWidth).fill(Tile.createWall())); - this.map = new TileMap(newTiles); + this.#map = new TileMap(newTiles); } createCorridor(roomA, roomB) { @@ -220,7 +232,7 @@ class DungeonFactory { while (x !== x2 || y !== y2) { if (x >= 0 && x < this.width && y >= 0 && y < this.height) { - this.map.tiles[y][x] = Tile.createFloor(); + this.#map.tiles[y][x] = Tile.createFloor(); } if (x !== x2) x += dx; @@ -229,7 +241,7 @@ class DungeonFactory { // Ensure endpoint is carved if (x2 >= 0 && x2 < this.width && y2 >= 0 && y2 < this.height) { - this.map.tiles[y2][x2] = Tile.createFloor(); + this.#map.tiles[y2][x2] = Tile.createFloor(); } } @@ -238,14 +250,14 @@ class DungeonFactory { for (let y = 1; y < this.height - 1; y++) { // for (let x = 1; x < this.width - 1; x++) { - const cell = this.map.get(x, y); + const cell = this.#map.get(x, y); if (!cell) { console.warn("out of bounds [%d, %d] (%s)", x, y, typeof cell); continue; } - if (this.map.get(x, y).isFloor()) { + if (this.#map.get(x, y).isFloor()) { walkabilityCache.push([x, y]); } } @@ -263,7 +275,7 @@ class DungeonFactory { for (let [x, y] of walkabilityCache) { // - const walkable = (offsetX, offsetY) => this.map.isFloorLike(x + offsetX, y + offsetY); + const walkable = (offsetX, offsetY) => this.#map.isFloorLike(x + offsetX, y + offsetY); const surroundingFloorCount = 0 + @@ -283,7 +295,7 @@ class DungeonFactory { if (surroundingFloorCount >= 7) { // MAGIC NUMBER 7 - this.map.tiles[y][x] = Tile.createWall(); + this.#map.tiles[y][x] = Tile.createWall(); } } } @@ -293,14 +305,14 @@ class DungeonFactory { for (let y = 1; y < this.height - 1; y++) { // for (let x = 1; x < this.width - 1; x++) { - const cell = this.map.get(x, y); + const cell = this.#map.get(x, y); if (!cell) { console.warn("out of bounds [%d, %d] (%s)", x, y, typeof cell); continue; } - if (this.map.isFloorLike(x, y)) { + if (this.#map.isFloorLike(x, y)) { walkabilityCache.push([x, y]); } } @@ -309,7 +321,7 @@ class DungeonFactory { const idx = this.random(0, walkabilityCache.length - 1); const [x, y] = walkabilityCache[idx]; - const walkable = (offsetX, offsetY) => this.map.isFloorLike(x + offsetX, y + offsetY); + const walkable = (offsetX, offsetY) => this.#map.isFloorLike(x + offsetX, y + offsetY); // // When spawning in, which direction should the player be oriented? @@ -324,23 +336,23 @@ class DungeonFactory { // they don't face a wall upon spawning. const dirIdx = this.random(0, directions.length - 1); - this.map.tiles[y][x] = Tile.createPlayerStart(directions[dirIdx]); + this.#map.tiles[y][x] = Tile.createPlayerStart(directions[dirIdx]); } // Add portals to isolated areas addPortals() { - let traversableTileCount = this.map.getFloorlikeTileCount(); + let traversableTileCount = this.#map.getFloorlikeTileCount(); // // Find the player's start point, and let this be the // bases of area 0 - const [x, y] = this.map.forEach((tile, x, y) => { + const [x, y] = this.#map.forEach((tile, x, y) => { if (tile.typeId === TileChars.PLAYER_START_POINT) { return [x, y]; } }); - const result = this.map.getAllTraversableTilesConnectedTo(x, y); + const result = this.#map.getAllTraversableTilesConnectedTo(x, y); if (result.size === traversableTileCount) { // There are no isolated areas, return @@ -385,7 +397,7 @@ class DungeonFactory { const floorTiles = []; for (let y = 0; y < this.height; y++) { for (let x = 0; x < this.width; x++) { - if (this.map.get(x, y).isFloor()) { + if (this.#map.get(x, y).isFloor()) { floorTiles.push({ x, y }); } } @@ -405,11 +417,11 @@ class DungeonFactory { // } // Add monsters - const encouterCount = Math.min(5, this.rooms.length); + const encouterCount = Math.min(5, this.#rooms.length); for (let i = 0; i < encouterCount; i++) { const pos = floorTiles[this.random(0, floorTiles.length - 1)]; - if (this.map.tiles[pos.y][pos.x].isFloor()) { - this.map.tiles[pos.y][pos.x] = Tile.createEncounterStartPoint("PLACEHOLDER_ENCOUNTER_ID"); + if (this.#map.tiles[pos.y][pos.x].isFloor()) { + this.#map.tiles[pos.y][pos.x] = Tile.createEncounterStartPoint("PLACEHOLDER_ENCOUNTER_ID"); // TODO: Add encounter to the dungeon's "roaming entities" array. } } @@ -468,15 +480,15 @@ export const downloadDungeon = () => { URL.revokeObjectURL(url); }; -widthEl.addEventListener("input", function () { +widthEl.addEventListener("input", function() { document.getElementById("widthValue").textContent = this.value; }); -heightEl.addEventListener("input", function () { +heightEl.addEventListener("input", function() { document.getElementById("heightValue").textContent = this.value; }); -roomCountEl.addEventListener("input", function () { +roomCountEl.addEventListener("input", function() { document.getElementById("roomCountValue").textContent = this.value; }); diff --git a/models/player.js b/models/player.js index b064b01..6bdcbef 100755 --- a/models/player.js +++ b/models/player.js @@ -1,7 +1,8 @@ -import WebSocket from "ws"; -import { Character } from "./character.js"; import { Config } from "./../config.js"; -import { Scene } from "../scenes/scene.js"; + +/** @typedef {import("../scenes/scene.js").Scene} Scene */ +/** @typedef {import("./characer.js").Character} Character */ +/** @typedef {import("ws").Websocket} Websocket */ /** * Player Account. diff --git a/models/session.js b/models/session.js index 8165b89..1565086 100755 --- a/models/session.js +++ b/models/session.js @@ -42,6 +42,7 @@ export class Session { * @param {Scene} scene */ setScene(scene) { + this.frankofil = stil; console.debug("Changing scene", { scene: scene.constructor.name }); if (!(scene instanceof Scene)) { throw new Error(`Expected instance of Scene, got a ${typeof scene}: >>${scene}<<`); @@ -99,10 +100,10 @@ export class Session { * @param {string|string[]} text The prompt message (the request to get the user to enter some info). * @param {string?} context */ /** - * @overload - * @param {string|string[]} text The prompt message (the request to get the user to enter some info). - * @param {object?} options Any options for the text (client side text formatting, color-, font-, or style info, etc.). - */ + * @overload + * @param {string|string[]} text The prompt message (the request to get the user to enter some info). + * @param {object?} options Any options for the text (client side text formatting, color-, font-, or style info, etc.). + */ sendPrompt(text, options) { options = options || {}; diff --git a/seeders/characerSeeder.js b/seeders/characerSeeder.js index 346b89c..13fc600 100755 --- a/seeders/characerSeeder.js +++ b/seeders/characerSeeder.js @@ -256,8 +256,10 @@ export class CharacterSeeder { // // Stats c.maxHitPoints = c.currentHitPoints = 15; + c.meleeCombat = Math.max(c.meleeCombat, 10); - c.magic = Math.min(c.magic, 10); + c.awareness = Math.max(c.awareness, 10) + c.skulduggery = Math.min(c.skulduggery, 10); // // Skills diff --git a/server.js b/server.js index 732a298..e37c481 100755 --- a/server.js +++ b/server.js @@ -9,6 +9,7 @@ import { gGame } from "./models/globals.js"; import { AuthenticationScene } from "./scenes/authentication/authenticationScene.js"; import { MessageType, WebsocketMessage, formatMessage } from "./utils/messages.js"; + // __ __ _ _ ____ ____ // | \/ | | | | _ \ / ___| ___ _ ____ _____ _ __ // | |\/| | | | | | | | \___ \ / _ \ '__\ \ / / _ \ '__| diff --git a/utils/id.js b/utils/id.js index ffc1d41..fcb63d0 100755 --- a/utils/id.js +++ b/utils/id.js @@ -1,10 +1,10 @@ import * as regex from "./regex.js"; -const MINI_UID_REGEX = regex.pretty( +const MINI_UID_REGEX = regex.compileMultilineRegex( "\.uid\.", // Mini-uids always begin with ".uid." "[a-z0-9]{6,}$", // Terminated by 6 or more random numbers and lowercase letters. ); -const ID_SANITY_REGEX = regex.pretty( +const ID_SANITY_REGEX = regex.compileMultilineRegex( "^:", // All ids start with a colon "([a-z0-9]+\.)*?", // Middle -optional- part :myid.gogle.thing.thang.thong "[a-z0-9_]+$", // The terminating part of the id is numbers, lowercase letters, and -notably- underscores. @@ -33,7 +33,7 @@ export function isIdSane(id) { } /** - * @returns {string} crypto-unsafe pseudo random numbe"r. + * @returns {string} crypto-unsafe pseudo random number. * * Generate a random number, convert it to base36, and return it as a string with 7-8 characters. */ diff --git a/utils/regex.js b/utils/regex.js index a3bee62..e9f03cc 100755 --- a/utils/regex.js +++ b/utils/regex.js @@ -4,7 +4,7 @@ * @param {...string} args * @returns {Regexp} */ -export function pretty(...args) { +export function compileMultilineRegex(...args) { const regexprStr = args.join(""); return new RegExp(regexprStr); } diff --git a/utils/tui.js b/utils/tui.js index 59d86ee..a3ed4e3 100755 --- a/utils/tui.js +++ b/utils/tui.js @@ -97,7 +97,7 @@ export class FramingOptions { frameChars = FrameType.values.Double; /** - * @param {object} o + * @param {FramingOptions} o * @returns {FramingOptions} */ static fromObject(o) {