moved a bunch of files

This commit is contained in:
Olivier Gagnon
2021-09-25 14:42:57 -04:00
parent 07bc697477
commit 06f716c0fa
174 changed files with 236 additions and 236 deletions
+11
View File
@@ -0,0 +1,11 @@
import { getRandomByte } from "./helpers/getRandomByte";
/**
* Generate a random IP address
* Does not check to see if the IP already exists in the game
*/
export function createRandomIp(): string {
const ip: string = getRandomByte(99) + "." + getRandomByte(9) + "." + getRandomByte(9) + "." + getRandomByte(9);
return ip;
}
+80
View File
@@ -0,0 +1,80 @@
/* Generic Reviver, toJSON, and fromJSON functions used for saving and loading objects */
export interface IReviverValue {
ctor: string;
data: any;
}
// A generic "smart reviver" function.
// Looks for object values with a `ctor` property and
// a `data` property. If it finds them, and finds a matching
// constructor that has a `fromJSON` property on it, it hands
// off to that `fromJSON` fuunction, passing in the value.
export function Reviver(key: string, value: IReviverValue | null): any {
if (value == null) {
console.log("Reviver WRONGLY called with key: " + key + ", and value: " + value);
return 0;
}
if (typeof value === "object" && typeof value.ctor === "string" && typeof value.data !== "undefined") {
// Compatibility for version v0.43.1
// TODO Remove this eventually
if (value.ctor === "AllServersMap") {
console.log("Converting AllServersMap for v0.43.1");
return value.data;
}
const ctor = Reviver.constructors[value.ctor];
if (typeof ctor === "function" && typeof ctor.fromJSON === "function") {
return ctor.fromJSON(value);
}
}
return value;
}
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace Reviver {
export const constructors: { [key: string]: any } = {};
}
// A generic "toJSON" function that creates the data expected
// by Reviver.
// `ctorName` The name of the constructor to use to revive it
// `obj` The object being serialized
// `keys` (Optional) Array of the properties to serialize,
// if not given then all of the objects "own" properties
// that don't have function values will be serialized.
// (Note: If you list a property in `keys`, it will be serialized
// regardless of whether it's an "own" property.)
// Returns: The structure (which will then be turned into a string
// as part of the JSON.stringify algorithm)
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function Generic_toJSON(ctorName: string, obj: any, keys?: string[]): IReviverValue {
if (!keys) {
keys = Object.keys(obj); // Only "own" properties are included
}
const data: any = {};
for (let index = 0; index < keys.length; ++index) {
const key = keys[index];
data[key] = obj[key];
}
return { ctor: ctorName, data: data };
}
// A generic "fromJSON" function for use with Reviver: Just calls the
// constructor function with no arguments, then applies all of the
// key/value pairs from the raw data to the instance. Only useful for
// constructors that can be reasonably called without arguments!
// `ctor` The constructor to call
// `data` The data to apply
// Returns: The object
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function Generic_fromJSON<T>(ctor: new () => T, data: any): T {
const obj: any = new ctor();
for (const name in data) {
obj[name] = data[name];
}
return obj;
}
+1 -1
View File
@@ -2,7 +2,7 @@
* This is an object that is used to keep track of where all of the player's
* money is coming from (or going to)
*/
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "./JSONReviver";
export class MoneySourceTracker {
// eslint-disable-next-line @typescript-eslint/ban-types
+129
View File
@@ -0,0 +1,129 @@
import { EqualityFunc } from "../types";
import { isString } from "./helpers/isString";
// Netburner String helper functions
// Replaces the character at an index with a new character
function replaceAt(base: string, index: number, character: string): string {
return base.substr(0, index) + character + base.substr(index + character.length);
}
/*
Converts a date representing time in milliseconds to a string with the format H hours M minutes and S seconds
e.g. 10000 -> "10 seconds"
120000 -> "2 minutes and 0 seconds"
*/
function convertTimeMsToTimeElapsedString(time: number, showMilli = false): string {
time = Math.floor(time);
const millisecondsPerSecond = 1000;
const secondPerMinute = 60;
const minutesPerHours = 60;
const secondPerHours: number = secondPerMinute * minutesPerHours;
const hoursPerDays = 24;
const secondPerDay: number = secondPerHours * hoursPerDays;
// Convert ms to seconds, since we only have second-level precision
const totalSeconds: number = Math.floor(time / millisecondsPerSecond);
const days: number = Math.floor(totalSeconds / secondPerDay);
const secTruncDays: number = totalSeconds % secondPerDay;
const hours: number = Math.floor(secTruncDays / secondPerHours);
const secTruncHours: number = secTruncDays % secondPerHours;
const minutes: number = Math.floor(secTruncHours / secondPerMinute);
const secTruncMinutes: number = secTruncHours % secondPerMinute;
const milliTruncSec: string = (() => {
let str = `${time % millisecondsPerSecond}`;
while (str.length < 3) str = "0" + str;
return str;
})();
const seconds: string = showMilli ? `${secTruncMinutes}.${milliTruncSec}` : `${secTruncMinutes}`;
let res = "";
if (days > 0) {
res += `${days} days `;
}
if (hours > 0) {
res += `${hours} hours `;
}
if (minutes > 0) {
res += `${minutes} minutes `;
}
res += `${seconds} seconds`;
return res;
}
// Finds the longest common starting substring in a set of strings
function longestCommonStart(strings: string[]): string {
if (!containsAllStrings(strings)) {
return "";
}
if (strings.length === 0) {
return "";
}
const A: string[] = strings.concat().sort();
const a1: string = A[0];
const a2: string = A[A.length - 1];
const L: number = a1.length;
let i = 0;
const areEqualCaseInsensitive: EqualityFunc<string> = (a: string, b: string) => a.toUpperCase() === b.toUpperCase();
while (i < L && areEqualCaseInsensitive(a1.charAt(i), a2.charAt(i))) {
i++;
}
return a1.substring(0, i);
}
// Returns whether an array contains entirely of string objects
function containsAllStrings(arr: string[]): boolean {
return arr.every(isString);
}
// Formats a number with commas and a specific number of decimal digits
function formatNumber(num: number, numFractionDigits = 0): string {
return num.toLocaleString(undefined, {
maximumFractionDigits: numFractionDigits,
minimumFractionDigits: numFractionDigits,
});
}
// Checks if a string contains HTML elements
function isHTML(str: string): boolean {
const element: HTMLDivElement = document.createElement("div");
element.innerHTML = str;
const c: NodeListOf<Node & ChildNode> = element.childNodes;
for (let i: number = c.length - 1; i >= 0; i--) {
if (c[i].nodeType === 1) {
return true;
}
}
return false;
}
// Generates a random alphanumeric string with N characters
function generateRandomString(n: number): string {
let str = "";
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < n; i++) {
str += chars.charAt(Math.floor(Math.random() * chars.length));
}
return str;
}
export {
convertTimeMsToTimeElapsedString,
longestCommonStart,
containsAllStrings,
formatNumber,
isHTML,
generateRandomString,
replaceAt,
};
+23
View File
@@ -0,0 +1,23 @@
/**
* Adds a random offset to a number within a certain percentage
* @example
* // Returns between 95-105
* addOffset(100, 5);
* @example
* // Returns between 63-77
* addOffSet(70, 10);
* @param midpoint The number to be the midpoint of the offset range
* @param percentage The percentage (in a range of 0-100) to offset
*/
export function addOffset(midpoint: number, percentage: number): number {
const maxPercent = 100;
if (percentage < 0 || percentage > maxPercent) {
return midpoint;
}
const offset: number = midpoint * (percentage / maxPercent);
// Double the range to account for both sides of the midpoint.
// tslint:disable-next-line:no-magic-numbers
return midpoint + (Math.random() * (offset * 2) - offset);
}
+21
View File
@@ -0,0 +1,21 @@
/**
* Returns the input array as a comma separated string.
*
* Does several things that Array.toString() doesn't do
* - Adds brackets around the array
* - Adds quotation marks around strings
*/
export function arrayToString<T>(a: T[]): string {
const vals: any[] = [];
for (let i = 0; i < a.length; ++i) {
let elem: any = a[i];
if (Array.isArray(elem)) {
elem = arrayToString(elem);
} else if (typeof elem === "string") {
elem = `"${elem}"`;
}
vals.push(elem);
}
return `[${vals.join(", ")}]`;
}
+15
View File
@@ -0,0 +1,15 @@
/**
* Clears defined properties from an object.
* Does not delete up the prototype chain.
* @deprecated Look into using `Map` or `Set` rather than manipulating properties on an Object.
* @param obj the object to clear all properties
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function clearObject(obj: any): void {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
// tslint:disable-next-line:no-dynamic-delete
delete obj[key];
}
}
}
+29
View File
@@ -0,0 +1,29 @@
/**
* Does a shallow compare of two arrays to determine if they are equal.
* @param a1 The first array
* @param a2 The second array
*/
export function compareArrays<T>(a1: T[], a2: T[]): boolean {
if (a1.length !== a2.length) {
return false;
}
for (let i = 0; i < a1.length; ++i) {
if (Array.isArray(a1[i])) {
// If the other element is not an array, then these cannot be equal
if (!Array.isArray(a2[i])) {
return false;
}
const elem1 = a1[i] as any;
const elem2 = a2[i] as any;
if (!compareArrays(elem1, elem2)) {
return false;
}
} else if (a1[i] !== a2[i]) {
return false;
}
}
return true;
}
@@ -0,0 +1,47 @@
/**
* Represents the possible configuration values that can be provided when creating the progress bar text.
*/
interface IProgressBarConfiguration {
/**
* Current progress, taken as a decimal (i.e. '0.6' to represent '60%')
*/
progress?: number;
/**
* Total number of ticks in progress bar. Preferably a factor of 100.
*/
totalTicks?: number;
}
/**
* Represents concrete configuration values when creating the progress bar text.
*/
interface IProgressBarConfigurationMaterialized extends IProgressBarConfiguration {
progress: number;
totalTicks: number;
}
/**
* Creates a graphical "progress bar"
* e.g.: [||||---------------]
* @param params The configuration parameters for the progress bar
*/
export function createProgressBarText(params: IProgressBarConfiguration): string {
// Default values
const defaultParams: IProgressBarConfigurationMaterialized = {
progress: 0,
totalTicks: 20,
};
// tslint:disable-next-line:prefer-object-spread
const derived: IProgressBarConfigurationMaterialized = Object.assign({}, defaultParams, params);
// Ensure it is 0..1
derived.progress = Math.max(Math.min(derived.progress, 1), 0);
// This way there is always at least one bar filled in...
const bars: number = Math.max(Math.floor(derived.progress / (1 / derived.totalTicks)), 1);
const dashes: number = Math.max(derived.totalTicks - bars, 0);
// String.prototype.repeat isn't completley supported, but good enough for our purposes
return `[${"|".repeat(bars)}${"-".repeat(dashes)}]`;
}
+26
View File
@@ -0,0 +1,26 @@
import { dialogBoxCreate } from "../../ui/React/DialogBox";
interface IError {
fileName?: string;
lineNumber?: number;
}
export function exceptionAlert(e: IError | string): void {
console.error(e);
dialogBoxCreate(
"Caught an exception: " +
e +
"<br><br>" +
"Filename: " +
((e as any).fileName || "UNKNOWN FILE NAME") +
"<br><br>" +
"Line Number: " +
((e as any).lineNumber || "UNKNOWN LINE NUMBER") +
"<br><br>" +
"This is a bug, please report to game developer with this " +
"message as well as details about how to reproduce the bug.<br><br>" +
"If you want to be safe, I suggest refreshing the game WITHOUT saving so that your " +
"safe doesn't get corrupted",
false,
);
}
+13
View File
@@ -0,0 +1,13 @@
import { getRandomInt } from "./getRandomInt";
/**
* Gets a random value in the range of a byte (0 - 255), or up to the maximum.
* @param max The maximum value (up to 255).
*/
export function getRandomByte(max: number): number {
// Technically 2^8 is 256, but the values are 0-255, not 1-256.
const byteMaximum = 255;
const upper: number = Math.max(Math.min(max, byteMaximum), 0);
return getRandomInt(0, upper);
}
+11
View File
@@ -0,0 +1,11 @@
/**
* Gets a random integer bounded by the values passed in.
* @param min The minimum value in the range.
* @param max The maximum value in the range.
*/
export function getRandomInt(min: number, max: number): number {
const lower: number = Math.min(min, max);
const upper: number = Math.max(min, max);
return Math.floor(Math.random() * (upper - lower + 1)) + lower;
}
+12
View File
@@ -0,0 +1,12 @@
/**
* Returns a MM/DD HH:MM timestamp for the current time
*/
export function getTimestamp(): string {
const d: Date = new Date();
// A negative slice value takes from the end of the string rather than the beginning.
const stringWidth = -2;
const formattedHours: string = `0${d.getHours()}`.slice(stringWidth);
const formattedMinutes: string = `0${d.getMinutes()}`.slice(stringWidth);
return `${d.getMonth() + 1}/${d.getDate()} ${formattedHours}:${formattedMinutes}`;
}
+17
View File
@@ -0,0 +1,17 @@
/**
* Determines if the number is a power of 2
* @param n The number to check.
*/
export function isPowerOfTwo(n: number): boolean {
if (isNaN(n)) {
return false;
}
if (n === 0) {
return false;
}
// Disabiling the bitwise rule because it's honestly the most effecient way to check for this.
// tslint:disable-next-line:no-bitwise
return (n & (n - 1)) === 0;
}
+8
View File
@@ -0,0 +1,8 @@
/**
* Checks whether the value passed in can be considered a string.
* @param value The value to check if it is a string.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function isString(value: any): boolean {
return typeof value === "string" || value instanceof String;
}
+11
View File
@@ -0,0 +1,11 @@
/**
* Checks whether a IP Address string is valid.
* @param ipaddress A string representing a potential IP Address
*/
export function isValidIPAddress(ipaddress: string): boolean {
const byteRange = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
const regexStr = `^${byteRange}\.${byteRange}\.${byteRange}\.${byteRange}$`;
const ipAddressRegex = new RegExp(regexStr);
return ipAddressRegex.test(ipaddress);
}
+51
View File
@@ -0,0 +1,51 @@
import { IMap } from "../../types";
/**
* Keyboard key codes
*/
export const KEY: IMap<number> = {
CTRL: 17,
DOWNARROW: 40,
ENTER: 13,
ESC: 27,
TAB: 9,
UPARROW: 38,
"0": 48,
"1": 49,
"2": 50,
"3": 51,
"4": 52,
"5": 53,
"6": 54,
"7": 55,
"8": 56,
"9": 57,
A: 65,
B: 66,
C: 67,
D: 68,
E: 69,
F: 70,
G: 71,
H: 72,
I: 73,
J: 74,
K: 75,
L: 76,
M: 77,
N: 78,
O: 79,
P: 80,
Q: 81,
R: 82,
S: 83,
T: 84,
U: 85,
V: 86,
W: 87,
X: 88,
Y: 89,
Z: 90,
};
+9
View File
@@ -0,0 +1,9 @@
/**
* Rounds a number to two decimal places.
* @param decimal A decimal value to trim to two places.
*/
export function roundToTwo(decimal: number): number {
const leftShift: number = Math.round(parseFloat(`${decimal}e+2`));
return +`${leftShift}e-2`;
}