refactors
This commit is contained in:
@@ -17,13 +17,22 @@ import { Player } from "./player.js";
|
|||||||
/** @typedef {import("./item.js").ItemBlueprint} ItemBlueprint */
|
/** @typedef {import("./item.js").ItemBlueprint} ItemBlueprint */
|
||||||
|
|
||||||
export class Game {
|
export class Game {
|
||||||
_counter = 1_000_000;
|
#counter = 1_000_000;
|
||||||
|
get counter() {
|
||||||
|
return this.#counter;
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {Map<string,ItemBlueprint>} List of all item blueprints in the game */
|
/** @type {Map<string,ItemBlueprint>} List of all item blueprints in the game */
|
||||||
_itemBlueprints = new Map();
|
#itemBlueprints = new Map();
|
||||||
|
get itemBlueprints() {
|
||||||
|
return this.#itemBlueprints;
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {Map<string,Location>} The list of locations in the game */
|
/** @type {Map<string,Location>} The list of locations in the game */
|
||||||
_locations = new Map();
|
#locations = new Map();
|
||||||
|
get locations() {
|
||||||
|
return this.#locations;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The characters in the game.
|
* The characters in the game.
|
||||||
@@ -31,34 +40,40 @@ export class Game {
|
|||||||
* @protected
|
* @protected
|
||||||
* @type {Map<string,Character>}
|
* @type {Map<string,Character>}
|
||||||
*/
|
*/
|
||||||
_characters = new Map();
|
#characters = new Map();
|
||||||
|
get characters() {
|
||||||
|
return this.#characters;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @protected
|
* @protected
|
||||||
* @type {Map<string,Player>} Map of users in the game username->Player
|
* @type {Map<string,Player>} Map of users in the game username->Player
|
||||||
*/
|
*/
|
||||||
_players = new Map();
|
#players = new Map();
|
||||||
|
get players() {
|
||||||
|
return this.#players;
|
||||||
|
}
|
||||||
|
|
||||||
/** @protected @type {Xorshift32} */
|
/** @protected @type {Xorshift32} */
|
||||||
_random;
|
#random;
|
||||||
|
|
||||||
/** @type {Xorshift32} */
|
/** @type {Xorshift32} */
|
||||||
get random() {
|
get random() {
|
||||||
return this._random;
|
return this.#random;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {number} rngSeed Seed number used for randomization */
|
/** @param {number} rngSeed Seed number used for randomization */
|
||||||
constructor() {
|
constructor(rngSeed) {
|
||||||
this.rngSeed = Date.now();
|
this.seedRNG(rngSeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
set rngSeed(rngSeed) {
|
seedRNG(rngSeed) {
|
||||||
this._random = new Xorshift32(rngSeed);
|
this.#random = new Xorshift32(rngSeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlayerByUsername(username) {
|
getPlayerByUsername(username) {
|
||||||
console.log("GETTING PLAYER: `%s`", username);
|
console.log("GETTING PLAYER: `%s`", username);
|
||||||
return this._players.get(username);
|
return this.#players.get(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,7 +86,7 @@ export class Game {
|
|||||||
* @returns {Player|null} Returns the player if username wasn't already taken, or null otherwise.
|
* @returns {Player|null} Returns the player if username wasn't already taken, or null otherwise.
|
||||||
*/
|
*/
|
||||||
createPlayer(username, passwordHash = undefined, salt = undefined) {
|
createPlayer(username, passwordHash = undefined, salt = undefined) {
|
||||||
if (this._players.has(username)) {
|
if (this.#players.has(username)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +96,7 @@ export class Game {
|
|||||||
typeof salt === "string" && salt.length > 0 ? salt : miniUid(),
|
typeof salt === "string" && salt.length > 0 ? salt : miniUid(),
|
||||||
);
|
);
|
||||||
|
|
||||||
this._players.set(username, player);
|
this.#players.set(username, player);
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
@@ -99,7 +114,7 @@ export class Game {
|
|||||||
throw new Error("Invalid blueprintId!");
|
throw new Error("Invalid blueprintId!");
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = this._itemBlueprints.get(blueprintId);
|
const existing = this.#itemBlueprints.get(blueprintId);
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
console.warn("we tried to create the same item blueprint more than once", blueprintId, attributes);
|
console.warn("we tried to create the same item blueprint more than once", blueprintId, attributes);
|
||||||
@@ -110,7 +125,7 @@ export class Game {
|
|||||||
|
|
||||||
const result = new ItemBlueprint(attributes);
|
const result = new ItemBlueprint(attributes);
|
||||||
|
|
||||||
this._itemBlueprints.set(blueprintId, result);
|
this.#itemBlueprints.set(blueprintId, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -123,6 +138,6 @@ export class Game {
|
|||||||
if (!isIdSane(blueprintId)) {
|
if (!isIdSane(blueprintId)) {
|
||||||
throw new Error(`blueprintId >>${blueprintId}<< is not a valid id`);
|
throw new Error(`blueprintId >>${blueprintId}<< is not a valid id`);
|
||||||
}
|
}
|
||||||
return this._itemBlueprints.get(blueprintId);
|
return this.#itemBlueprints.get(blueprintId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
|
import { Config } from "../config.js";
|
||||||
import { Game } from "./game.js";
|
import { Game } from "./game.js";
|
||||||
|
|
||||||
/** @constant @readonly @type {Game} Global instance of Game */
|
/** @constant @readonly @type {Game} Global instance of Game */
|
||||||
export const gGame = new Game();
|
export const gGame = new Game(Config.rngSeed);
|
||||||
|
|||||||
@@ -9,28 +9,28 @@
|
|||||||
* or magical portals to distant locations.
|
* or magical portals to distant locations.
|
||||||
*/
|
*/
|
||||||
export class Location {
|
export class Location {
|
||||||
/** @protected @type {string} */
|
/** @type {string} */
|
||||||
_id;
|
#id;
|
||||||
get id() {
|
get id() {
|
||||||
return this._id;
|
return this.#id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @protected @type {string} */
|
/** @type {string} */
|
||||||
_name;
|
#name;
|
||||||
get name() {
|
get name() {
|
||||||
return this._name;
|
return this.#name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @protected @type {string} */
|
/** @type {string} */
|
||||||
_description;
|
#description;
|
||||||
get description() {
|
get description() {
|
||||||
return this._description;
|
return this.#description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @protected @type {Map<string,Portal>} */
|
/** @type {Map<string,Portal>} */
|
||||||
_portals = new Map();
|
#portals = new Map();
|
||||||
get portals() {
|
get portals() {
|
||||||
return this._portals;
|
return this.#portals;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,8 +39,8 @@ export class Location {
|
|||||||
* @param {string} description
|
* @param {string} description
|
||||||
*/
|
*/
|
||||||
constructor(id, name, description) {
|
constructor(id, name, description) {
|
||||||
this._id = id;
|
this.#id = id;
|
||||||
this._name = name;
|
this.#name = name;
|
||||||
this._description = description;
|
this.#description = description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export class CharacterSeeder {
|
|||||||
c.name =
|
c.name =
|
||||||
gGame.random.oneOf("sir ", "madam ", "mister ", "miss ", "", "", "") + // prefix
|
gGame.random.oneOf("sir ", "madam ", "mister ", "miss ", "", "", "") + // prefix
|
||||||
"random " + // name
|
"random " + // name
|
||||||
gGame.random.get().toString(); // suffix
|
gGame.random.next().toString(); // suffix
|
||||||
|
|
||||||
c.awareness = roll.d6() + 2;
|
c.awareness = roll.d6() + 2;
|
||||||
c.grit = roll.d6() + 2;
|
c.grit = roll.d6() + 2;
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
* using the xorshift32 method.
|
* using the xorshift32 method.
|
||||||
*/
|
*/
|
||||||
export class Xorshift32 {
|
export class Xorshift32 {
|
||||||
/* @type {number} */
|
|
||||||
initialSeed;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State holds a single uint32.
|
* State holds a single uint32.
|
||||||
* It's useful for staying within modulo 2**32.
|
* It's useful for staying within modulo 2**32.
|
||||||
*
|
*
|
||||||
* @type {Uint32Array}
|
* @type {Uint32Array}
|
||||||
*/
|
*/
|
||||||
state;
|
#state;
|
||||||
|
get state() {
|
||||||
|
return this.#state;
|
||||||
|
}
|
||||||
|
|
||||||
/** @param {number} seed */
|
/** @param {number} seed */
|
||||||
constructor(seed) {
|
constructor(seed) {
|
||||||
@@ -21,41 +21,44 @@ export class Xorshift32 {
|
|||||||
seed = Math.floor(Math.random() * (maxInt32 - 1)) + 1;
|
seed = Math.floor(Math.random() * (maxInt32 - 1)) + 1;
|
||||||
}
|
}
|
||||||
seed = seed | 0;
|
seed = seed | 0;
|
||||||
this.state = Uint32Array.of(seed);
|
this.#state = Uint32Array.of(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @protected Shuffle the internal state. */
|
/** @protected Shuffle the internal state. */
|
||||||
shuffle() {
|
shuffle() {
|
||||||
this.state[0] ^= this.state[0] << 13;
|
this.#state[0] ^= this.#state[0] << 13;
|
||||||
this.state[0] ^= this.state[0] >>> 17;
|
this.#state[0] ^= this.#state[0] >>> 17;
|
||||||
this.state[0] ^= this.state[0] << 5;
|
this.#state[0] ^= this.#state[0] << 5;
|
||||||
|
|
||||||
// We could also do something like this:
|
// We could also do something like this:
|
||||||
// x ^= x << 13;
|
// x ^= x << 13;
|
||||||
// x ^= x >> 17;
|
// x ^= x >>> 17;
|
||||||
// x ^= x << 5;
|
// x ^= x << 5;
|
||||||
// return x;
|
// return x;
|
||||||
// But we'd have to xor the x with 2^32 after every op,
|
// And even though bitwise operations coerce numbers
|
||||||
// we get that "for free" by using the uint32array
|
// into int32 (except >>> which converts into uint32).
|
||||||
|
// But using Uint32Array ensures the number stays
|
||||||
|
// uint32 all the way through, thus avoiding the pitfalls
|
||||||
|
// of potentially dipping into negative number territory
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a random number and shuffle the internal state.
|
* Get a random number and shuffle the internal state.
|
||||||
* @returns {number} a pseudo-random positive integer.
|
* @returns {number} a pseudo-random positive integer.
|
||||||
*/
|
*/
|
||||||
get() {
|
next() {
|
||||||
this.shuffle();
|
this.shuffle();
|
||||||
return this.state[0];
|
return this.#state[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {number} x @returns {number} a positive integer lower than x */
|
/** @param {number} x @returns {number} a positive integer lower than x */
|
||||||
lowerThan(x) {
|
lowerThan(x) {
|
||||||
return this.get() % x;
|
return this.next() % x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {number} x @returns {number} a positive integer lower than or equal to x */
|
/** @param {number} x @returns {number} a positive integer lower than or equal to x */
|
||||||
lowerThanOrEqual(x) {
|
lowerThanOrEqual(x) {
|
||||||
return this.get() % (x + 1);
|
return this.next() % (x + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user