mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-19 04:35:46 +01:00
Started server code refactor
This commit is contained in:
parent
af3323a111
commit
e1b8a23f1e
32
src/Message/Message.ts
Normal file
32
src/Message/Message.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Reviver,
|
||||||
|
Generic_toJSON,
|
||||||
|
Generic_fromJSON } from "../../utils/JSONReviver";
|
||||||
|
|
||||||
|
export class Message {
|
||||||
|
// Initializes a Message Object from a JSON save state
|
||||||
|
static fromJSON(value: any): Message {
|
||||||
|
return Generic_fromJSON(Message, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name of Message file
|
||||||
|
filename: string = "";
|
||||||
|
|
||||||
|
// The text contains in the Message
|
||||||
|
msg: string = "":
|
||||||
|
|
||||||
|
// Flag indicating whether this Message has been received by the player
|
||||||
|
recvd: boolean = false;
|
||||||
|
|
||||||
|
constructor(filename="", msg="") {
|
||||||
|
this.filename = filename;
|
||||||
|
this.msg = msg;
|
||||||
|
this.recvd = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize the current object to a JSON save state
|
||||||
|
toJSON(): any {
|
||||||
|
return Generic_toJSON("Message", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.Message = Message;
|
@ -1,34 +1,15 @@
|
|||||||
import { Augmentatation } from "./Augmentation/Augmentation";
|
import { Message } from "./Message";
|
||||||
import { Augmentations } from "./Augmentation/Augmentations";
|
import { Augmentatation } from "../Augmentation/Augmentation";
|
||||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
import { Augmentations } from "../Augmentation/Augmentations";
|
||||||
import { Programs } from "./Programs/Programs";
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||||
import { inMission } from "./Missions";
|
import { Programs } from "../Programs/Programs";
|
||||||
import { Player } from "./Player";
|
import { inMission } from "../Missions";
|
||||||
import { redPillFlag } from "./RedPill";
|
import { Player } from "../Player";
|
||||||
import { GetServerByHostname } from "./Server";
|
import { redPillFlag } from "../RedPill";
|
||||||
import { Settings } from "./Settings/Settings";
|
import { GetServerByHostname } from "../Server";
|
||||||
|
import { Settings } from "../Settings/Settings";
|
||||||
import { dialogBoxCreate,
|
import { dialogBoxCreate,
|
||||||
dialogBoxOpened} from "../utils/DialogBox";
|
dialogBoxOpened} from "../../utils/DialogBox";
|
||||||
import {Reviver, Generic_toJSON,
|
|
||||||
Generic_fromJSON} from "../utils/JSONReviver";
|
|
||||||
|
|
||||||
/* Message.js */
|
|
||||||
function Message(filename="", msg="") {
|
|
||||||
this.filename = filename;
|
|
||||||
this.msg = msg;
|
|
||||||
this.recvd = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Message.prototype.toJSON = function() {
|
|
||||||
return Generic_toJSON("Message", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Message.fromJSON = function(value) {
|
|
||||||
return Generic_fromJSON(Message, value.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reviver.constructors.Message = Message;
|
|
||||||
|
|
||||||
//Sends message to player, including a pop up
|
//Sends message to player, including a pop up
|
||||||
function sendMessage(msg, forced=false) {
|
function sendMessage(msg, forced=false) {
|
155
src/Script/RunningScript.ts
Normal file
155
src/Script/RunningScript.ts
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// Class representing a Script instance that is actively running.
|
||||||
|
// A Script can have multiple active instances
|
||||||
|
import { Script } from "./Script";
|
||||||
|
import { IMap } from "../types";
|
||||||
|
import { Generic_fromJSON,
|
||||||
|
Generic_toJSON,
|
||||||
|
Reviver } from "../../utils/JSONReviver";
|
||||||
|
|
||||||
|
export class RunningScript {
|
||||||
|
// Initializes a RunningScript Object from a JSON save state
|
||||||
|
static fromJSON(value: any): RunningScript {
|
||||||
|
return Generic_fromJSON(RunningScript, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Script arguments
|
||||||
|
args: any[] = [];
|
||||||
|
|
||||||
|
// Holds a map of servers hacked, where server = key and the value for each
|
||||||
|
// server is an array of four numbers. The four numbers represent:
|
||||||
|
// [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||||
|
// This data is used for offline progress
|
||||||
|
dataMap: IMap<number[]> = {};
|
||||||
|
|
||||||
|
// Script filename
|
||||||
|
filename: string = "";
|
||||||
|
|
||||||
|
// This script's logs. An array of log entries
|
||||||
|
logs: string[] = [];
|
||||||
|
|
||||||
|
// Flag indicating whether the logs have been updated since
|
||||||
|
// the last time the UI was updated
|
||||||
|
logUpd: boolean = false;
|
||||||
|
|
||||||
|
// Total amount of hacking experience earned from this script when offline
|
||||||
|
offlineExpGained: number = 0;
|
||||||
|
|
||||||
|
// Total amount of money made by this script when offline
|
||||||
|
offlineMoneyMade: number = 0;
|
||||||
|
|
||||||
|
// Number of seconds that the script has been running offline
|
||||||
|
offlineRunningTime: number = 0.01;
|
||||||
|
|
||||||
|
// Total amount of hacking experience earned from this script when online
|
||||||
|
onlineExpGained: number = 0;
|
||||||
|
|
||||||
|
// Total amount of money made by this script when online
|
||||||
|
onlineMoneyMade: number = 0;
|
||||||
|
|
||||||
|
// Number of seconds that this script has been running online
|
||||||
|
onlineRunningTime: number = 0.01;
|
||||||
|
|
||||||
|
// How much RAM this script uses for ONE thread
|
||||||
|
ramUsage: number = 0;
|
||||||
|
|
||||||
|
// IP of the server on which this script is running
|
||||||
|
server: string = "";
|
||||||
|
|
||||||
|
// Number of threads that this script is running with
|
||||||
|
threads: number = 1;
|
||||||
|
|
||||||
|
constructor(script: Script | null = null, args: any[] = []) {
|
||||||
|
if (script == null) { return; }
|
||||||
|
this.filename = script.filename;
|
||||||
|
this.args = args;
|
||||||
|
|
||||||
|
this.server = script.server; //IP Address only
|
||||||
|
this.ramUsage = script.ramUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.getCode = function() {
|
||||||
|
const server = AllServers[this.server];
|
||||||
|
if (server == null) { return ""; }
|
||||||
|
for (let i = 0; i < server.scripts.length; ++i) {
|
||||||
|
if (server.scripts[i].filename === this.filename) {
|
||||||
|
return server.scripts[i].code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.getRamUsage = function() {
|
||||||
|
if (this.ramUsage != null && this.ramUsage > 0) { return this.ramUsage; } // Use cached value
|
||||||
|
|
||||||
|
const server = AllServers[this.server];
|
||||||
|
if (server == null) { return 0; }
|
||||||
|
for (let i = 0; i < server.scripts.length; ++i) {
|
||||||
|
if (server.scripts[i].filename === this.filename) {
|
||||||
|
// Cache the ram usage for the next call
|
||||||
|
this.ramUsage = server.scripts[i].ramUsage;
|
||||||
|
return this.ramUsage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.log = function(txt) {
|
||||||
|
if (this.logs.length > Settings.MaxLogCapacity) {
|
||||||
|
//Delete first element and add new log entry to the end.
|
||||||
|
//TODO Eventually it might be better to replace this with circular array
|
||||||
|
//to improve performance
|
||||||
|
this.logs.shift();
|
||||||
|
}
|
||||||
|
let logEntry = txt;
|
||||||
|
if (FconfSettings.ENABLE_TIMESTAMPS) {
|
||||||
|
logEntry = "[" + getTimestamp() + "] " + logEntry;
|
||||||
|
}
|
||||||
|
this.logs.push(logEntry);
|
||||||
|
this.logUpd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.displayLog = function() {
|
||||||
|
for (var i = 0; i < this.logs.length; ++i) {
|
||||||
|
post(this.logs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.clearLog = function() {
|
||||||
|
this.logs.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the moneyStolen and numTimesHack maps when hacking
|
||||||
|
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
||||||
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
|
}
|
||||||
|
this.dataMap[serverIp][0] += moneyGained;
|
||||||
|
this.dataMap[serverIp][1] += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the grow map when calling grow()
|
||||||
|
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
||||||
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
|
}
|
||||||
|
this.dataMap[serverIp][2] += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the weaken map when calling weaken() {
|
||||||
|
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
||||||
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
|
}
|
||||||
|
this.dataMap[serverIp][3] += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize the current object to a JSON save state
|
||||||
|
toJSON(): any {
|
||||||
|
return Generic_toJSON("RunningScript", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.RunningScript = RunningScript;
|
104
src/Script/Script.ts
Normal file
104
src/Script/Script.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Class representing a script file
|
||||||
|
// This does NOT represent a script that is actively running and
|
||||||
|
// being evaluated. See RunningScript for that
|
||||||
|
import { Page,
|
||||||
|
routing } from "../ui/navigationTracking";
|
||||||
|
import { setTimeoutRef } from "../utils/SetTimeoutRef";
|
||||||
|
import { Generic_fromJSON,
|
||||||
|
Generic_toJSON,
|
||||||
|
Reviver } from "../../utils/JSONReviver";
|
||||||
|
import { roundToTwo } from "../../utils/helpers/roundToTwo";
|
||||||
|
|
||||||
|
export class Script {
|
||||||
|
// Initializes a Script Object from a JSON save state
|
||||||
|
static fromJSON(value: any): Script {
|
||||||
|
return Generic_fromJSON(Script, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code for this script
|
||||||
|
code: string = "";
|
||||||
|
|
||||||
|
// Filename for the script file
|
||||||
|
filename: string = "";
|
||||||
|
|
||||||
|
// The dynamic module generated for this script when it is run.
|
||||||
|
// This is only applicable for NetscriptJS
|
||||||
|
module: any = "";
|
||||||
|
|
||||||
|
// Amount of RAM this Script requres to run
|
||||||
|
ramUsage: number = 0;
|
||||||
|
|
||||||
|
// IP of server that this script is on.
|
||||||
|
server: string = "";
|
||||||
|
|
||||||
|
|
||||||
|
constructor(fn: string = "", code: string = "", server: string = "") {
|
||||||
|
this.filename = fn;
|
||||||
|
this.code = code;
|
||||||
|
this.ramUsage = 0;
|
||||||
|
this.server = server; // IP of server this script is on
|
||||||
|
this.module = "";
|
||||||
|
if (this.code !== "") {this.updateRamUsage();}
|
||||||
|
};
|
||||||
|
|
||||||
|
download(): void {
|
||||||
|
const filename = this.filename + ".js";
|
||||||
|
const file = new Blob([this.code], {type: 'text/plain'});
|
||||||
|
if (window.navigator.msSaveOrOpenBlob) {// IE10+
|
||||||
|
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||||
|
} else { // Others
|
||||||
|
var a = document.createElement("a"),
|
||||||
|
url = URL.createObjectURL(file);
|
||||||
|
a.href = url;
|
||||||
|
a.download = filename;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
setTimeoutRef(function() {
|
||||||
|
document.body.removeChild(a);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save a script FROM THE SCRIPT EDITOR
|
||||||
|
saveScript(): void {
|
||||||
|
if (routing.isOn(Page.ScriptEditor)) {
|
||||||
|
//Update code and filename
|
||||||
|
const code = getCurrentEditor().getCode();
|
||||||
|
this.code = code.replace(/^\s+|\s+$/g, '');
|
||||||
|
|
||||||
|
const filenameElem: HTMLInputElement | null = document.getElementById("script-editor-filename") as HTMLInputElement;
|
||||||
|
if (filenameElem == null) {
|
||||||
|
console.error(`Failed to get Script filename DOM element`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.filename = filenameElem!.value;
|
||||||
|
|
||||||
|
// Server
|
||||||
|
this.server = Player.currentServer;
|
||||||
|
|
||||||
|
//Calculate/update ram usage, execution time, etc.
|
||||||
|
this.updateRamUsage();
|
||||||
|
|
||||||
|
this.module = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the script's RAM usage based on its code
|
||||||
|
async updateRamUsage(): void {
|
||||||
|
// TODO Commented this out because I think its unnecessary
|
||||||
|
// DOuble check/Test
|
||||||
|
// var codeCopy = this.code.repeat(1);
|
||||||
|
var res = await calculateRamUsage(this.code);
|
||||||
|
if (res !== -1) {
|
||||||
|
this.ramUsage = roundToTwo(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize the current object to a JSON save state
|
||||||
|
toJSON(): any {
|
||||||
|
return Generic_toJSON("Script", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.Script = Script;
|
187
src/Script.js → src/Script/ScriptHelpers.js
Executable file → Normal file
187
src/Script.js → src/Script/ScriptHelpers.js
Executable file → Normal file
@ -308,44 +308,6 @@ function checkValidFilename(filename) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Script(fn = "", code = "", server = "") {
|
|
||||||
this.filename = fn;
|
|
||||||
this.code = code;
|
|
||||||
this.ramUsage = 0;
|
|
||||||
this.server = server; //IP of server this script is on
|
|
||||||
this.module = "";
|
|
||||||
if (this.code !== "") {this.updateRamUsage();}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Get the script data from the Script Editor and save it to the object
|
|
||||||
Script.prototype.saveScript = function() {
|
|
||||||
if (routing.isOn(Page.ScriptEditor)) {
|
|
||||||
//Update code and filename
|
|
||||||
const code = getCurrentEditor().getCode();
|
|
||||||
this.code = code.replace(/^\s+|\s+$/g, '');
|
|
||||||
|
|
||||||
var filename = document.getElementById("script-editor-filename").value;
|
|
||||||
this.filename = filename;
|
|
||||||
|
|
||||||
//Server
|
|
||||||
this.server = Player.currentServer;
|
|
||||||
|
|
||||||
//Calculate/update ram usage, execution time, etc.
|
|
||||||
this.updateRamUsage();
|
|
||||||
|
|
||||||
this.module = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Updates how much RAM the script uses when it is running.
|
|
||||||
Script.prototype.updateRamUsage = async function() {
|
|
||||||
var codeCopy = this.code.repeat(1);
|
|
||||||
var res = await calculateRamUsage(codeCopy);
|
|
||||||
if (res !== -1) {
|
|
||||||
this.ramUsage = roundToTwo(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These special strings are used to reference the presence of a given logical
|
// These special strings are used to reference the presence of a given logical
|
||||||
// construct within a user script.
|
// construct within a user script.
|
||||||
const specialReferenceIF = "__SPECIAL_referenceIf";
|
const specialReferenceIF = "__SPECIAL_referenceIf";
|
||||||
@ -747,36 +709,6 @@ async function calculateRamUsage(codeCopy) {
|
|||||||
return ramUsage;
|
return ramUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.prototype.download = function() {
|
|
||||||
var filename = this.filename + ".js";
|
|
||||||
var file = new Blob([this.code], {type: 'text/plain'});
|
|
||||||
if (window.navigator.msSaveOrOpenBlob) {// IE10+
|
|
||||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
|
||||||
} else { // Others
|
|
||||||
var a = document.createElement("a"),
|
|
||||||
url = URL.createObjectURL(file);
|
|
||||||
a.href = url;
|
|
||||||
a.download = filename;
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
setTimeoutRef(function() {
|
|
||||||
document.body.removeChild(a);
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Script.prototype.toJSON = function() {
|
|
||||||
return Generic_toJSON("Script", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Script.fromJSON = function(value) {
|
|
||||||
return Generic_fromJSON(Script, value.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reviver.constructors.Script = Script;
|
|
||||||
|
|
||||||
//Called when the game is loaded. Loads all running scripts (from all servers)
|
//Called when the game is loaded. Loads all running scripts (from all servers)
|
||||||
//into worker scripts so that they will start running
|
//into worker scripts so that they will start running
|
||||||
function loadAllRunningScripts() {
|
function loadAllRunningScripts() {
|
||||||
@ -916,122 +848,5 @@ function findRunningScript(filename, args, server) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RunningScript(script, args) {
|
|
||||||
if (script == null || script == undefined) { return; }
|
|
||||||
this.filename = script.filename;
|
|
||||||
this.args = args;
|
|
||||||
this.server = script.server; //IP Address only
|
|
||||||
this.ramUsage = script.ramUsage;
|
|
||||||
|
|
||||||
this.logs = []; //Script logging. Array of strings, with each element being a log entry
|
|
||||||
this.logUpd = false;
|
|
||||||
|
|
||||||
//Stats to display on the Scripts menu, and used to determine offline progress
|
|
||||||
this.offlineRunningTime = 0.01; //Seconds
|
|
||||||
this.offlineMoneyMade = 0;
|
|
||||||
this.offlineExpGained = 0;
|
|
||||||
this.onlineRunningTime = 0.01; //Seconds
|
|
||||||
this.onlineMoneyMade = 0;
|
|
||||||
this.onlineExpGained = 0;
|
|
||||||
|
|
||||||
this.threads = 1;
|
|
||||||
|
|
||||||
// Holds a map of all servers, where server = key and the value for each
|
|
||||||
// server is an array of four numbers. The four numbers represent:
|
|
||||||
// [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
|
||||||
// This data is used for offline progress
|
|
||||||
this.dataMap = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
RunningScript.prototype.getCode = function() {
|
|
||||||
const server = AllServers[this.server];
|
|
||||||
if (server == null) { return ""; }
|
|
||||||
for (let i = 0; i < server.scripts.length; ++i) {
|
|
||||||
if (server.scripts[i].filename === this.filename) {
|
|
||||||
return server.scripts[i].code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
RunningScript.prototype.getRamUsage = function() {
|
|
||||||
if (this.ramUsage != null && this.ramUsage > 0) { return this.ramUsage; } // Use cached value
|
|
||||||
|
|
||||||
const server = AllServers[this.server];
|
|
||||||
if (server == null) { return 0; }
|
|
||||||
for (let i = 0; i < server.scripts.length; ++i) {
|
|
||||||
if (server.scripts[i].filename === this.filename) {
|
|
||||||
// Cache the ram usage for the next call
|
|
||||||
this.ramUsage = server.scripts[i].ramUsage;
|
|
||||||
return this.ramUsage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
RunningScript.prototype.log = function(txt) {
|
|
||||||
if (this.logs.length > Settings.MaxLogCapacity) {
|
|
||||||
//Delete first element and add new log entry to the end.
|
|
||||||
//TODO Eventually it might be better to replace this with circular array
|
|
||||||
//to improve performance
|
|
||||||
this.logs.shift();
|
|
||||||
}
|
|
||||||
let logEntry = txt;
|
|
||||||
if (FconfSettings.ENABLE_TIMESTAMPS) {
|
|
||||||
logEntry = "[" + getTimestamp() + "] " + logEntry;
|
|
||||||
}
|
|
||||||
this.logs.push(logEntry);
|
|
||||||
this.logUpd = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RunningScript.prototype.displayLog = function() {
|
|
||||||
for (var i = 0; i < this.logs.length; ++i) {
|
|
||||||
post(this.logs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RunningScript.prototype.clearLog = function() {
|
|
||||||
this.logs.length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Update the moneyStolen and numTimesHack maps when hacking
|
|
||||||
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
|
||||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
|
||||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
|
||||||
}
|
|
||||||
this.dataMap[serverIp][0] += moneyGained;
|
|
||||||
this.dataMap[serverIp][1] += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Update the grow map when calling grow()
|
|
||||||
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
|
||||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
|
||||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
|
||||||
}
|
|
||||||
this.dataMap[serverIp][2] += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Update the weaken map when calling weaken() {
|
|
||||||
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
|
||||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
|
||||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
|
||||||
}
|
|
||||||
this.dataMap[serverIp][3] += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
RunningScript.prototype.toJSON = function() {
|
|
||||||
return Generic_toJSON("RunningScript", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RunningScript.fromJSON = function(value) {
|
|
||||||
return Generic_fromJSON(RunningScript, value.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reviver.constructors.RunningScript = RunningScript;
|
|
||||||
|
|
||||||
export {loadAllRunningScripts, findRunningScript,
|
export {loadAllRunningScripts, findRunningScript,
|
||||||
RunningScript, Script, scriptEditorInit, isScriptFilename};
|
scriptEditorInit, isScriptFilename};
|
468
src/Server.js
468
src/Server.js
@ -1,468 +0,0 @@
|
|||||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
|
||||||
import { CodingContract,
|
|
||||||
ContractTypes } from "./CodingContracts";
|
|
||||||
import { CONSTANTS } from "./Constants";
|
|
||||||
import { Script,
|
|
||||||
isScriptFilename } from "./Script";
|
|
||||||
import { Player } from "./Player";
|
|
||||||
import { Programs } from "./Programs/Programs";
|
|
||||||
import { SpecialServerIps } from "./SpecialServerIps";
|
|
||||||
import { TextFile } from "./TextFile";
|
|
||||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
|
||||||
import { createRandomIp,
|
|
||||||
ipExists } from "../utils/IPAddress";
|
|
||||||
import { serverMetadata } from "./data/servers";
|
|
||||||
import { Reviver,
|
|
||||||
Generic_toJSON,
|
|
||||||
Generic_fromJSON} from "../utils/JSONReviver";
|
|
||||||
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
|
||||||
|
|
||||||
function Server(params={ip:createRandomIp(), hostname:""}) {
|
|
||||||
/* Properties */
|
|
||||||
//Connection information
|
|
||||||
this.ip = params.ip ? params.ip : createRandomIp();
|
|
||||||
|
|
||||||
var hostname = params.hostname;
|
|
||||||
var i = 0;
|
|
||||||
var suffix = "";
|
|
||||||
while (GetServerByHostname(hostname+suffix) != null) {
|
|
||||||
//Server already exists
|
|
||||||
suffix = "-" + i;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
this.hostname = hostname + suffix;
|
|
||||||
this.organizationName = params.organizationName != null ? params.organizationName : "";
|
|
||||||
this.isConnectedTo = params.isConnectedTo != null ? params.isConnectedTo : false;
|
|
||||||
|
|
||||||
//Access information
|
|
||||||
this.hasAdminRights = params.adminRights != null ? params.adminRights : false;
|
|
||||||
this.purchasedByPlayer = params.purchasedByPlayer != null ? params.purchasedByPlayer : false;
|
|
||||||
this.manuallyHacked = false; //Flag that tracks whether or not the server has been hacked at least once
|
|
||||||
|
|
||||||
//RAM, CPU speed and Scripts
|
|
||||||
this.maxRam = params.maxRam != null ? params.maxRam : 0; //GB
|
|
||||||
this.ramUsed = 0;
|
|
||||||
this.cpuCores = 1; //Max of 8, affects hacking times and Hacking Mission starting Cores
|
|
||||||
|
|
||||||
this.scripts = [];
|
|
||||||
this.runningScripts = []; //Stores RunningScript objects
|
|
||||||
this.programs = [];
|
|
||||||
this.messages = [];
|
|
||||||
this.textFiles = [];
|
|
||||||
this.contracts = [];
|
|
||||||
this.dir = 0; //new Directory(this, null, ""); TODO
|
|
||||||
|
|
||||||
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
|
|
||||||
this.requiredHackingSkill = params.requiredHackingSkill != null ? params.requiredHackingSkill : 1;
|
|
||||||
this.moneyAvailable = params.moneyAvailable != null ? params.moneyAvailable * BitNodeMultipliers.ServerStartingMoney : 0;
|
|
||||||
this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney;
|
|
||||||
|
|
||||||
//Hack Difficulty is synonymous with server security. Base Difficulty = Starting difficulty
|
|
||||||
this.hackDifficulty = params.hackDifficulty != null ? params.hackDifficulty * BitNodeMultipliers.ServerStartingSecurity : 1;
|
|
||||||
this.baseDifficulty = this.hackDifficulty;
|
|
||||||
this.minDifficulty = Math.max(1, Math.round(this.hackDifficulty / 3));
|
|
||||||
this.serverGrowth = params.serverGrowth != null ? params.serverGrowth : 1; //Integer from 0 to 100. Affects money increase from grow()
|
|
||||||
|
|
||||||
//The IP's of all servers reachable from this one (what shows up if you run scan/netstat)
|
|
||||||
// NOTE: Only contains IP and not the Server objects themselves
|
|
||||||
this.serversOnNetwork = [];
|
|
||||||
|
|
||||||
//Port information, required for porthacking servers to get admin rights
|
|
||||||
this.numOpenPortsRequired = params.numOpenPortsRequired != null ? params.numOpenPortsRequired : 5;
|
|
||||||
this.sshPortOpen = false; //Port 22
|
|
||||||
this.ftpPortOpen = false; //Port 21
|
|
||||||
this.smtpPortOpen = false; //Port 25
|
|
||||||
this.httpPortOpen = false; //Port 80
|
|
||||||
this.sqlPortOpen = false; //Port 1433
|
|
||||||
this.openPortCount = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Server.prototype.setMaxRam = function(ram) {
|
|
||||||
this.maxRam = ram;
|
|
||||||
}
|
|
||||||
|
|
||||||
//The serverOnNetwork array holds the IP of all the servers. This function
|
|
||||||
//returns the actual Server objects
|
|
||||||
Server.prototype.getServerOnNetwork = function(i) {
|
|
||||||
if (i > this.serversOnNetwork.length) {
|
|
||||||
console.log("Tried to get server on network that was out of range");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return AllServers[this.serversOnNetwork[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Given the name of the script, returns the corresponding
|
|
||||||
//script object on the server (if it exists)
|
|
||||||
Server.prototype.getScript = function(scriptName) {
|
|
||||||
for (var i = 0; i < this.scripts.length; i++) {
|
|
||||||
if (this.scripts[i].filename == scriptName) {
|
|
||||||
return this.scripts[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.prototype.capDifficulty = function() {
|
|
||||||
if (this.hackDifficulty < this.minDifficulty) {this.hackDifficulty = this.minDifficulty;}
|
|
||||||
if (this.hackDifficulty < 1) {this.hackDifficulty = 1;}
|
|
||||||
//Place some arbitrarily limit that realistically should never happen unless someone is
|
|
||||||
//screwing around with the game
|
|
||||||
if (this.hackDifficulty > 1000000) {this.hackDifficulty = 1000000;}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Strengthens a server's security level (difficulty) by the specified amount
|
|
||||||
Server.prototype.fortify = function(amt) {
|
|
||||||
this.hackDifficulty += amt;
|
|
||||||
this.capDifficulty();
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.prototype.weaken = function(amt) {
|
|
||||||
this.hackDifficulty -= (amt * BitNodeMultipliers.ServerWeakenRate);
|
|
||||||
this.capDifficulty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write to a script file
|
|
||||||
// Overwrites existing files. Creates new files if the script does not eixst
|
|
||||||
Server.prototype.writeToScriptFile = function(fn, code) {
|
|
||||||
var ret = {success: false, overwritten: false};
|
|
||||||
if (!isScriptFilename(fn)) { return ret; }
|
|
||||||
|
|
||||||
//Check if the script already exists, and overwrite it if it does
|
|
||||||
for (let i = 0; i < this.scripts.length; ++i) {
|
|
||||||
if (fn === this.scripts[i].filename) {
|
|
||||||
let script = this.scripts[i];
|
|
||||||
script.code = code;
|
|
||||||
script.updateRamUsage();
|
|
||||||
script.module = "";
|
|
||||||
ret.overwritten = true;
|
|
||||||
ret.success = true;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Otherwise, create a new script
|
|
||||||
var newScript = new Script();
|
|
||||||
newScript.filename = fn;
|
|
||||||
newScript.code = code;
|
|
||||||
newScript.updateRamUsage();
|
|
||||||
newScript.server = this.ip;
|
|
||||||
this.scripts.push(newScript);
|
|
||||||
ret.success = true;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write to a text file
|
|
||||||
// Overwrites existing files. Creates new files if the text file does not exist
|
|
||||||
Server.prototype.writeToTextFile = function(fn, txt) {
|
|
||||||
var ret = {success: false, overwritten: false};
|
|
||||||
if (!fn.endsWith("txt")) { return ret; }
|
|
||||||
|
|
||||||
//Check if the text file already exists, and overwrite if it does
|
|
||||||
for (let i = 0; i < this.textFiles.length; ++i) {
|
|
||||||
if (this.textFiles[i].fn === fn) {
|
|
||||||
ret.overwritten = true;
|
|
||||||
this.textFiles[i].text = txt;
|
|
||||||
ret.success = true;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Otherwise create a new text file
|
|
||||||
var newFile = new TextFile(fn, txt);
|
|
||||||
this.textFiles.push(newFile);
|
|
||||||
ret.success = true;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.prototype.addContract = function(contract) {
|
|
||||||
this.contracts.push(contract);
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.prototype.removeContract = function(contract) {
|
|
||||||
if (contract instanceof CodingContract) {
|
|
||||||
this.contracts = this.contracts.filter((c) => {
|
|
||||||
return c.fn !== contract.fn;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.contracts = this.contracts.filter((c) => {
|
|
||||||
return c.fn !== contract;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.prototype.getContract = function(contractName) {
|
|
||||||
for (const contract of this.contracts) {
|
|
||||||
if (contract.fn === contractName) {
|
|
||||||
return contract;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Functions for loading and saving a Server
|
|
||||||
Server.prototype.toJSON = function() {
|
|
||||||
return Generic_toJSON("Server", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.fromJSON = function(value) {
|
|
||||||
return Generic_fromJSON(Server, value.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reviver.constructors.Server = Server;
|
|
||||||
|
|
||||||
export function initForeignServers() {
|
|
||||||
/* Create a randomized network for all the foreign servers */
|
|
||||||
//Groupings for creating a randomized network
|
|
||||||
const networkLayers = [];
|
|
||||||
for (let i = 0; i < 15; i++) {
|
|
||||||
networkLayers.push([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Essentially any property that is of type 'number | IMinMaxRange'
|
|
||||||
const propertiesToPatternMatch = [
|
|
||||||
"hackDifficulty",
|
|
||||||
"moneyAvailable",
|
|
||||||
"requiredHackingSkill",
|
|
||||||
"serverGrowth"
|
|
||||||
];
|
|
||||||
|
|
||||||
const toNumber = (value) => {
|
|
||||||
switch (typeof value) {
|
|
||||||
case 'number':
|
|
||||||
return value;
|
|
||||||
case 'object':
|
|
||||||
return getRandomInt(value.min, value.max);
|
|
||||||
default:
|
|
||||||
throw Error(`Do not know how to convert the type '${typeof value}' to a number`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const metadata of serverMetadata) {
|
|
||||||
const serverParams = {
|
|
||||||
hostname: metadata.hostname,
|
|
||||||
ip: createRandomIp(),
|
|
||||||
numOpenPortsRequired: metadata.numOpenPortsRequired,
|
|
||||||
organizationName: metadata.organizationName
|
|
||||||
};
|
|
||||||
|
|
||||||
if (metadata.maxRamExponent !== undefined) {
|
|
||||||
serverParams.maxRam = Math.pow(2, toNumber(metadata.maxRamExponent));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const prop of propertiesToPatternMatch) {
|
|
||||||
if (metadata[prop] !== undefined) {
|
|
||||||
serverParams[prop] = toNumber(metadata[prop]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const server = new Server(serverParams);
|
|
||||||
for (const filename of (metadata.literature || [])) {
|
|
||||||
server.messages.push(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata.specialName !== undefined) {
|
|
||||||
SpecialServerIps.addIp(metadata.specialName, server.ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddToAllServers(server);
|
|
||||||
if (metadata.networkLayer !== undefined) {
|
|
||||||
networkLayers[toNumber(metadata.networkLayer) - 1].push(server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a randomized network for all the foreign servers */
|
|
||||||
const linkComputers = (server1, server2) => {
|
|
||||||
server1.serversOnNetwork.push(server2.ip);
|
|
||||||
server2.serversOnNetwork.push(server1.ip);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRandomArrayItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
||||||
|
|
||||||
const linkNetworkLayers = (network1, selectServer) => {
|
|
||||||
for (const server of network1) {
|
|
||||||
linkComputers(server, selectServer());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Connect the first tier of servers to the player's home computer
|
|
||||||
linkNetworkLayers(networkLayers[0], () => Player.getHomeComputer());
|
|
||||||
for (let i = 1; i < networkLayers.length; i++) {
|
|
||||||
linkNetworkLayers(networkLayers[i], () => getRandomArrayItem(networkLayers[i - 1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the number of cycles needed to grow the specified server by the
|
|
||||||
// specified amount. 'growth' parameter is in decimal form, not percentage
|
|
||||||
export function numCycleForGrowth(server, growth) {
|
|
||||||
let ajdGrowthRate = 1 + (CONSTANTS.ServerBaseGrowthRate - 1) / server.hackDifficulty;
|
|
||||||
if(ajdGrowthRate > CONSTANTS.ServerMaxGrowthRate) {
|
|
||||||
ajdGrowthRate = CONSTANTS.ServerMaxGrowthRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
|
||||||
|
|
||||||
const cycles = Math.log(growth)/(Math.log(ajdGrowthRate)*Player.hacking_grow_mult*serverGrowthPercentage);
|
|
||||||
return cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Applied server growth for a single server. Returns the percentage growth
|
|
||||||
export function processSingleServerGrowth(server, numCycles) {
|
|
||||||
//Server growth processed once every 450 game cycles
|
|
||||||
const numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0);
|
|
||||||
|
|
||||||
//Get adjusted growth rate, which accounts for server security
|
|
||||||
const growthRate = CONSTANTS.ServerBaseGrowthRate;
|
|
||||||
var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
|
|
||||||
if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;}
|
|
||||||
|
|
||||||
//Calculate adjusted server growth rate based on parameters
|
|
||||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
|
||||||
const numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
|
|
||||||
|
|
||||||
//Apply serverGrowth for the calculated number of growth cycles
|
|
||||||
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult);
|
|
||||||
if (serverGrowth < 1) {
|
|
||||||
console.log("WARN: serverGrowth calculated to be less than 1");
|
|
||||||
serverGrowth = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldMoneyAvailable = server.moneyAvailable;
|
|
||||||
server.moneyAvailable *= serverGrowth;
|
|
||||||
|
|
||||||
// in case of data corruption
|
|
||||||
if (server.moneyMax && isNaN(server.moneyAvailable)) {
|
|
||||||
server.moneyAvailable = server.moneyMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cap at max
|
|
||||||
if (server.moneyMax && server.moneyAvailable > server.moneyMax) {
|
|
||||||
server.moneyAvailable = server.moneyMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there was any growth at all, increase security
|
|
||||||
if (oldMoneyAvailable !== server.moneyAvailable) {
|
|
||||||
//Growing increases server security twice as much as hacking
|
|
||||||
let usedCycles = numCycleForGrowth(server, server.moneyAvailable / oldMoneyAvailable);
|
|
||||||
usedCycles = Math.max(0, usedCycles);
|
|
||||||
server.fortify(2 * CONSTANTS.ServerFortifyAmount * Math.ceil(usedCycles));
|
|
||||||
}
|
|
||||||
return server.moneyAvailable / oldMoneyAvailable;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function prestigeHomeComputer(homeComp) {
|
|
||||||
const hasBitflume = homeComp.programs.includes(Programs.BitFlume.name);
|
|
||||||
|
|
||||||
homeComp.programs.length = 0; //Remove programs
|
|
||||||
homeComp.runningScripts = [];
|
|
||||||
homeComp.serversOnNetwork = [];
|
|
||||||
homeComp.isConnectedTo = true;
|
|
||||||
homeComp.ramUsed = 0;
|
|
||||||
homeComp.programs.push(Programs.NukeProgram.name);
|
|
||||||
if (hasBitflume) { homeComp.programs.push(Programs.BitFlume.name); }
|
|
||||||
|
|
||||||
//Update RAM usage on all scripts
|
|
||||||
homeComp.scripts.forEach(function(script) {
|
|
||||||
script.updateRamUsage();
|
|
||||||
});
|
|
||||||
|
|
||||||
homeComp.messages.length = 0; //Remove .lit and .msg files
|
|
||||||
homeComp.messages.push("hackers-starting-handbook.lit");
|
|
||||||
}
|
|
||||||
|
|
||||||
//List of all servers that exist in the game, indexed by their ip
|
|
||||||
let AllServers = {};
|
|
||||||
|
|
||||||
export function prestigeAllServers() {
|
|
||||||
for (var member in AllServers) {
|
|
||||||
delete AllServers[member];
|
|
||||||
}
|
|
||||||
AllServers = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadAllServers(saveString) {
|
|
||||||
AllServers = JSON.parse(saveString, Reviver);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SizeOfAllServers() {
|
|
||||||
var size = 0, key;
|
|
||||||
for (key in AllServers) {
|
|
||||||
if (AllServers.hasOwnProperty(key)) size++;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add a server onto the map of all servers in the game
|
|
||||||
export function AddToAllServers(server) {
|
|
||||||
var serverIp = server.ip;
|
|
||||||
if (ipExists(serverIp)) {
|
|
||||||
console.log("IP of server that's being added: " + serverIp);
|
|
||||||
console.log("Hostname of the server thats being added: " + server.hostname);
|
|
||||||
console.log("The server that already has this IP is: " + AllServers[serverIp].hostname);
|
|
||||||
throw new Error("Error: Trying to add a server with an existing IP");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AllServers[serverIp] = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Returns server object with corresponding hostname
|
|
||||||
// Relatively slow, would rather not use this a lot
|
|
||||||
export function GetServerByHostname(hostname) {
|
|
||||||
for (var ip in AllServers) {
|
|
||||||
if (AllServers.hasOwnProperty(ip)) {
|
|
||||||
if (AllServers[ip].hostname == hostname) {
|
|
||||||
return AllServers[ip];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get server by IP or hostname. Returns null if invalid
|
|
||||||
export function getServer(s) {
|
|
||||||
if (!isValidIPAddress(s)) {
|
|
||||||
return GetServerByHostname(s);
|
|
||||||
}
|
|
||||||
if(AllServers[s] !== undefined) {
|
|
||||||
return AllServers[s];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Debugging tool
|
|
||||||
function PrintAllServers() {
|
|
||||||
for (var ip in AllServers) {
|
|
||||||
if (AllServers.hasOwnProperty(ip)) {
|
|
||||||
console.log("Ip: " + ip + ", hostname: " + AllServers[ip].hostname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Directory object (folders)
|
|
||||||
function Directory(server, parent, name) {
|
|
||||||
this.s = server; //Ref to server
|
|
||||||
this.p = parent; //Ref to parent directory
|
|
||||||
this.c = []; //Subdirs
|
|
||||||
this.n = name;
|
|
||||||
this.d = parent.d + 1; //We'll only have a maximum depth of 3 or something
|
|
||||||
this.scrs = []; //Holds references to the scripts in server.scripts
|
|
||||||
this.pgms = [];
|
|
||||||
this.msgs = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
Directory.prototype.createSubdir = function(name) {
|
|
||||||
var subdir = new Directory(this.s, this, name);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Directory.prototype.getPath = function(name) {
|
|
||||||
var res = [];
|
|
||||||
var i = this;
|
|
||||||
while (i !== null) {
|
|
||||||
res.unshift(i.n, "/");
|
|
||||||
i = i.parent;
|
|
||||||
}
|
|
||||||
res.unshift("/");
|
|
||||||
return res.join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
export {Server, AllServers};
|
|
111
src/Server/AllServers.ts
Normal file
111
src/Server/AllServers.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { ipExists } from "../../utils/IPAddress";
|
||||||
|
|
||||||
|
// Map of all Servers that exist in the game
|
||||||
|
// Key (string) = IP
|
||||||
|
// Value = Server object
|
||||||
|
let AllServers = {};
|
||||||
|
|
||||||
|
// Saftely add a Server to the AllServers map
|
||||||
|
export function AddToAllServers(server) {
|
||||||
|
var serverIp = server.ip;
|
||||||
|
if (ipExists(serverIp)) {
|
||||||
|
console.log("IP of server that's being added: " + serverIp);
|
||||||
|
console.log("Hostname of the server thats being added: " + server.hostname);
|
||||||
|
console.log("The server that already has this IP is: " + AllServers[serverIp].hostname);
|
||||||
|
throw new Error("Error: Trying to add a server with an existing IP");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AllServers[serverIp] = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initForeignServers() {
|
||||||
|
/* Create a randomized network for all the foreign servers */
|
||||||
|
//Groupings for creating a randomized network
|
||||||
|
const networkLayers = [];
|
||||||
|
for (let i = 0; i < 15; i++) {
|
||||||
|
networkLayers.push([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Essentially any property that is of type 'number | IMinMaxRange'
|
||||||
|
const propertiesToPatternMatch = [
|
||||||
|
"hackDifficulty",
|
||||||
|
"moneyAvailable",
|
||||||
|
"requiredHackingSkill",
|
||||||
|
"serverGrowth"
|
||||||
|
];
|
||||||
|
|
||||||
|
const toNumber = (value) => {
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'number':
|
||||||
|
return value;
|
||||||
|
case 'object':
|
||||||
|
return getRandomInt(value.min, value.max);
|
||||||
|
default:
|
||||||
|
throw Error(`Do not know how to convert the type '${typeof value}' to a number`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const metadata of serverMetadata) {
|
||||||
|
const serverParams = {
|
||||||
|
hostname: metadata.hostname,
|
||||||
|
ip: createRandomIp(),
|
||||||
|
numOpenPortsRequired: metadata.numOpenPortsRequired,
|
||||||
|
organizationName: metadata.organizationName
|
||||||
|
};
|
||||||
|
|
||||||
|
if (metadata.maxRamExponent !== undefined) {
|
||||||
|
serverParams.maxRam = Math.pow(2, toNumber(metadata.maxRamExponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const prop of propertiesToPatternMatch) {
|
||||||
|
if (metadata[prop] !== undefined) {
|
||||||
|
serverParams[prop] = toNumber(metadata[prop]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const server = new Server(serverParams);
|
||||||
|
for (const filename of (metadata.literature || [])) {
|
||||||
|
server.messages.push(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.specialName !== undefined) {
|
||||||
|
SpecialServerIps.addIp(metadata.specialName, server.ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddToAllServers(server);
|
||||||
|
if (metadata.networkLayer !== undefined) {
|
||||||
|
networkLayers[toNumber(metadata.networkLayer) - 1].push(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a randomized network for all the foreign servers */
|
||||||
|
const linkComputers = (server1, server2) => {
|
||||||
|
server1.serversOnNetwork.push(server2.ip);
|
||||||
|
server2.serversOnNetwork.push(server1.ip);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRandomArrayItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
||||||
|
|
||||||
|
const linkNetworkLayers = (network1, selectServer) => {
|
||||||
|
for (const server of network1) {
|
||||||
|
linkComputers(server, selectServer());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connect the first tier of servers to the player's home computer
|
||||||
|
linkNetworkLayers(networkLayers[0], () => Player.getHomeComputer());
|
||||||
|
for (let i = 1; i < networkLayers.length; i++) {
|
||||||
|
linkNetworkLayers(networkLayers[i], () => getRandomArrayItem(networkLayers[i - 1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function prestigeAllServers() {
|
||||||
|
for (var member in AllServers) {
|
||||||
|
delete AllServers[member];
|
||||||
|
}
|
||||||
|
AllServers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadAllServers(saveString) {
|
||||||
|
AllServers = JSON.parse(saveString, Reviver);
|
||||||
|
}
|
303
src/Server/Server.ts
Normal file
303
src/Server/Server.ts
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
// Class representing a single generic Server
|
||||||
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
|
import { CodingContract } from "../CodingContracts";
|
||||||
|
import { Message } from "../Message/Message";
|
||||||
|
import { RunningScript } from "../Script/RunningScript";
|
||||||
|
import { Script } from "../Script/Script";
|
||||||
|
import { TextFile } from "../TextFile";
|
||||||
|
|
||||||
|
import { createRandomIp } from "../../utils/IPAddress";
|
||||||
|
import { Generic_fromJSON,
|
||||||
|
Generic_toJSON,
|
||||||
|
Reviver } from "../../utils/JSONReviver";
|
||||||
|
|
||||||
|
interface IConstructorParams {
|
||||||
|
adminRights?: boolean;
|
||||||
|
hackDifficulty?: number;
|
||||||
|
hostname: string;
|
||||||
|
ip?: string;
|
||||||
|
isConnectedTo?: boolean;
|
||||||
|
maxRam?: number;
|
||||||
|
moneyAvailable?: number;
|
||||||
|
numOpenPortsRequired?: number;
|
||||||
|
organizationName?: string;
|
||||||
|
purchasedByPlayer?: boolean;
|
||||||
|
requiredHackingSkill?: number;
|
||||||
|
serverGrowth?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Server {
|
||||||
|
// Initial server security level
|
||||||
|
// (i.e. security level when the server was created)
|
||||||
|
baseDifficulty: number = 1;
|
||||||
|
|
||||||
|
// Coding Contract files on this server
|
||||||
|
contracts: CodingContract[] = [];
|
||||||
|
|
||||||
|
// How many CPU cores this server has. Maximum of 8.
|
||||||
|
// Currently, this only affects hacking missions
|
||||||
|
cpuCores: number = 1;
|
||||||
|
|
||||||
|
// Flag indicating whether the FTP port is open
|
||||||
|
ftpPortOpen: boolean = false;
|
||||||
|
|
||||||
|
// Server Security Level
|
||||||
|
hackDifficulty: number = 1;
|
||||||
|
|
||||||
|
// Flag indicating whether player has admin/root access to this server
|
||||||
|
hasAdminRights: boolean = false;
|
||||||
|
|
||||||
|
// Hostname. Must be unique
|
||||||
|
hostname: string = "";
|
||||||
|
|
||||||
|
// Flag indicating whether HTTP Port is open
|
||||||
|
httpPortOpen: boolean = false;
|
||||||
|
|
||||||
|
// IP Address. Must be unique
|
||||||
|
ip: string = "";
|
||||||
|
|
||||||
|
// Flag indicating whether player is curently connected to this server
|
||||||
|
isConnectedTo: boolean = false;
|
||||||
|
|
||||||
|
// Flag indicating whether this server has been manually hacked (ie.
|
||||||
|
// hacked through Terminal) by the player
|
||||||
|
manuallyHacked: boolean = false;
|
||||||
|
|
||||||
|
// RAM (GB) available on this server
|
||||||
|
maxRam: number = 0;
|
||||||
|
|
||||||
|
// Message files AND Literature files on this Server
|
||||||
|
// For Literature files, this array contains only the filename (string)
|
||||||
|
// For Messages, it contains the actual Message object
|
||||||
|
// TODO Separate literature files into its own property
|
||||||
|
messages: (Message | string)[] = [];
|
||||||
|
|
||||||
|
// Minimum server security level that this server can be weakened to
|
||||||
|
minDifficulty: number = 1;
|
||||||
|
|
||||||
|
// How much money currently resides on the server and can be hacked
|
||||||
|
moneyAvailable: number = 0;
|
||||||
|
|
||||||
|
// Maximum amount of money that this server can hold
|
||||||
|
moneyMax: number = 0;
|
||||||
|
|
||||||
|
// Number of open ports required in order to gain admin/root access
|
||||||
|
numOpenPortsRequired: number = 5;
|
||||||
|
|
||||||
|
// How many ports are currently opened on the server
|
||||||
|
openPortCount: number = 0;
|
||||||
|
|
||||||
|
// Name of company/faction/etc. that this server belongs to.
|
||||||
|
// Optional, not applicable to all Servers
|
||||||
|
organizationName: string = "";
|
||||||
|
|
||||||
|
// Programs on this servers. Contains only the names of the programs
|
||||||
|
programs: string[] = [];
|
||||||
|
|
||||||
|
// Flag indicating wehther this is a purchased server
|
||||||
|
purchasedByPlayer: boolean = false;
|
||||||
|
|
||||||
|
// RAM (GB) used. i.e. unavailable RAM
|
||||||
|
ramUsed: number = 0;
|
||||||
|
|
||||||
|
// Hacking level required to hack this server
|
||||||
|
requiredHackingSkill: number = 1;
|
||||||
|
|
||||||
|
// RunningScript files on this server
|
||||||
|
runningScripts: RunningScript[] = [];
|
||||||
|
|
||||||
|
// Script files on this Server
|
||||||
|
scripts: Script[] = [];
|
||||||
|
|
||||||
|
// Parameter that affects how effectively this server's money can
|
||||||
|
// be increased using the grow() Netscript function
|
||||||
|
serverGrowth: number = 1;
|
||||||
|
|
||||||
|
// Contains the IP Addresses of all servers that are immediately
|
||||||
|
// reachable from this one
|
||||||
|
serversOnNetwork: string[] = [];
|
||||||
|
|
||||||
|
// Flag indicating whether SMTP Port is open
|
||||||
|
smtpPortOpen: boolean = false;
|
||||||
|
|
||||||
|
// Flag indicating whether SQL Port is open
|
||||||
|
sqlPortOpen: boolean = false;
|
||||||
|
|
||||||
|
// Flag indicating whether the SSH Port is open
|
||||||
|
sshPortOpen: boolean = false;
|
||||||
|
|
||||||
|
// Text files on this server
|
||||||
|
textFiles: TextFile[] = [];
|
||||||
|
|
||||||
|
constructor(params: IConstructorParams={hostname: "", ip: createRandomIp() }) {
|
||||||
|
/* Properties */
|
||||||
|
//Connection information
|
||||||
|
this.ip = params.ip ? params.ip : createRandomIp();
|
||||||
|
|
||||||
|
var hostname = params.hostname;
|
||||||
|
var i = 0;
|
||||||
|
var suffix = "";
|
||||||
|
while (GetServerByHostname(hostname+suffix) != null) {
|
||||||
|
//Server already exists
|
||||||
|
suffix = "-" + i;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
this.hostname = hostname + suffix;
|
||||||
|
this.organizationName = params.organizationName != null ? params.organizationName : "";
|
||||||
|
this.isConnectedTo = params.isConnectedTo != null ? params.isConnectedTo : false;
|
||||||
|
|
||||||
|
//Access information
|
||||||
|
this.hasAdminRights = params.adminRights != null ? params.adminRights : false;
|
||||||
|
this.purchasedByPlayer = params.purchasedByPlayer != null ? params.purchasedByPlayer : false;
|
||||||
|
|
||||||
|
//RAM, CPU speed and Scripts
|
||||||
|
this.maxRam = params.maxRam != null ? params.maxRam : 0; //GB
|
||||||
|
|
||||||
|
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
|
||||||
|
this.requiredHackingSkill = params.requiredHackingSkill != null ? params.requiredHackingSkill : 1;
|
||||||
|
this.moneyAvailable = params.moneyAvailable != null ? params.moneyAvailable * BitNodeMultipliers.ServerStartingMoney : 0;
|
||||||
|
this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney;
|
||||||
|
|
||||||
|
//Hack Difficulty is synonymous with server security. Base Difficulty = Starting difficulty
|
||||||
|
this.hackDifficulty = params.hackDifficulty != null ? params.hackDifficulty * BitNodeMultipliers.ServerStartingSecurity : 1;
|
||||||
|
this.baseDifficulty = this.hackDifficulty;
|
||||||
|
this.minDifficulty = Math.max(1, Math.round(this.hackDifficulty / 3));
|
||||||
|
this.serverGrowth = params.serverGrowth != null ? params.serverGrowth : 1; //Integer from 0 to 100. Affects money increase from grow()
|
||||||
|
|
||||||
|
//Port information, required for porthacking servers to get admin rights
|
||||||
|
this.numOpenPortsRequired = params.numOpenPortsRequired != null ? params.numOpenPortsRequired : 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
setMaxRam(ram: number): void {
|
||||||
|
this.maxRam = ram;
|
||||||
|
}
|
||||||
|
|
||||||
|
//The serverOnNetwork array holds the IP of all the servers. This function
|
||||||
|
//returns the actual Server objects
|
||||||
|
Server.prototype.getServerOnNetwork = function(i) {
|
||||||
|
if (i > this.serversOnNetwork.length) {
|
||||||
|
console.log("Tried to get server on network that was out of range");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return AllServers[this.serversOnNetwork[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Given the name of the script, returns the corresponding
|
||||||
|
//script object on the server (if it exists)
|
||||||
|
Server.prototype.getScript = function(scriptName) {
|
||||||
|
for (var i = 0; i < this.scripts.length; i++) {
|
||||||
|
if (this.scripts[i].filename == scriptName) {
|
||||||
|
return this.scripts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server.prototype.capDifficulty = function() {
|
||||||
|
if (this.hackDifficulty < this.minDifficulty) {this.hackDifficulty = this.minDifficulty;}
|
||||||
|
if (this.hackDifficulty < 1) {this.hackDifficulty = 1;}
|
||||||
|
//Place some arbitrarily limit that realistically should never happen unless someone is
|
||||||
|
//screwing around with the game
|
||||||
|
if (this.hackDifficulty > 1000000) {this.hackDifficulty = 1000000;}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Strengthens a server's security level (difficulty) by the specified amount
|
||||||
|
Server.prototype.fortify = function(amt) {
|
||||||
|
this.hackDifficulty += amt;
|
||||||
|
this.capDifficulty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Server.prototype.weaken = function(amt) {
|
||||||
|
this.hackDifficulty -= (amt * BitNodeMultipliers.ServerWeakenRate);
|
||||||
|
this.capDifficulty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write to a script file
|
||||||
|
// Overwrites existing files. Creates new files if the script does not eixst
|
||||||
|
Server.prototype.writeToScriptFile = function(fn, code) {
|
||||||
|
var ret = {success: false, overwritten: false};
|
||||||
|
if (!isScriptFilename(fn)) { return ret; }
|
||||||
|
|
||||||
|
//Check if the script already exists, and overwrite it if it does
|
||||||
|
for (let i = 0; i < this.scripts.length; ++i) {
|
||||||
|
if (fn === this.scripts[i].filename) {
|
||||||
|
let script = this.scripts[i];
|
||||||
|
script.code = code;
|
||||||
|
script.updateRamUsage();
|
||||||
|
script.module = "";
|
||||||
|
ret.overwritten = true;
|
||||||
|
ret.success = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Otherwise, create a new script
|
||||||
|
var newScript = new Script();
|
||||||
|
newScript.filename = fn;
|
||||||
|
newScript.code = code;
|
||||||
|
newScript.updateRamUsage();
|
||||||
|
newScript.server = this.ip;
|
||||||
|
this.scripts.push(newScript);
|
||||||
|
ret.success = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write to a text file
|
||||||
|
// Overwrites existing files. Creates new files if the text file does not exist
|
||||||
|
Server.prototype.writeToTextFile = function(fn, txt) {
|
||||||
|
var ret = {success: false, overwritten: false};
|
||||||
|
if (!fn.endsWith("txt")) { return ret; }
|
||||||
|
|
||||||
|
//Check if the text file already exists, and overwrite if it does
|
||||||
|
for (let i = 0; i < this.textFiles.length; ++i) {
|
||||||
|
if (this.textFiles[i].fn === fn) {
|
||||||
|
ret.overwritten = true;
|
||||||
|
this.textFiles[i].text = txt;
|
||||||
|
ret.success = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Otherwise create a new text file
|
||||||
|
var newFile = new TextFile(fn, txt);
|
||||||
|
this.textFiles.push(newFile);
|
||||||
|
ret.success = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server.prototype.addContract = function(contract) {
|
||||||
|
this.contracts.push(contract);
|
||||||
|
}
|
||||||
|
|
||||||
|
Server.prototype.removeContract = function(contract) {
|
||||||
|
if (contract instanceof CodingContract) {
|
||||||
|
this.contracts = this.contracts.filter((c) => {
|
||||||
|
return c.fn !== contract.fn;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.contracts = this.contracts.filter((c) => {
|
||||||
|
return c.fn !== contract;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Server.prototype.getContract = function(contractName) {
|
||||||
|
for (const contract of this.contracts) {
|
||||||
|
if (contract.fn === contractName) {
|
||||||
|
return contract;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Functions for loading and saving a Server
|
||||||
|
Server.prototype.toJSON = function() {
|
||||||
|
return Generic_toJSON("Server", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Server.fromJSON = function(value) {
|
||||||
|
return Generic_fromJSON(Server, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.Server = Server;
|
126
src/Server/ServerHelpers.js
Normal file
126
src/Server/ServerHelpers.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
|
import { CodingContract,
|
||||||
|
ContractTypes } from "./CodingContracts";
|
||||||
|
import { CONSTANTS } from "./Constants";
|
||||||
|
import { Script,
|
||||||
|
isScriptFilename } from "./Script";
|
||||||
|
import { Player } from "./Player";
|
||||||
|
import { Programs } from "./Programs/Programs";
|
||||||
|
import { SpecialServerIps } from "./SpecialServerIps";
|
||||||
|
import { TextFile } from "./TextFile";
|
||||||
|
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||||
|
import { serverMetadata } from "./data/servers";
|
||||||
|
import { Reviver,
|
||||||
|
Generic_toJSON,
|
||||||
|
Generic_fromJSON} from "../utils/JSONReviver";
|
||||||
|
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
||||||
|
|
||||||
|
// Returns the number of cycles needed to grow the specified server by the
|
||||||
|
// specified amount. 'growth' parameter is in decimal form, not percentage
|
||||||
|
export function numCycleForGrowth(server, growth) {
|
||||||
|
let ajdGrowthRate = 1 + (CONSTANTS.ServerBaseGrowthRate - 1) / server.hackDifficulty;
|
||||||
|
if(ajdGrowthRate > CONSTANTS.ServerMaxGrowthRate) {
|
||||||
|
ajdGrowthRate = CONSTANTS.ServerMaxGrowthRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||||
|
|
||||||
|
const cycles = Math.log(growth)/(Math.log(ajdGrowthRate)*Player.hacking_grow_mult*serverGrowthPercentage);
|
||||||
|
return cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Applied server growth for a single server. Returns the percentage growth
|
||||||
|
export function processSingleServerGrowth(server, numCycles) {
|
||||||
|
//Server growth processed once every 450 game cycles
|
||||||
|
const numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0);
|
||||||
|
|
||||||
|
//Get adjusted growth rate, which accounts for server security
|
||||||
|
const growthRate = CONSTANTS.ServerBaseGrowthRate;
|
||||||
|
var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
|
||||||
|
if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;}
|
||||||
|
|
||||||
|
//Calculate adjusted server growth rate based on parameters
|
||||||
|
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||||
|
const numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
|
||||||
|
|
||||||
|
//Apply serverGrowth for the calculated number of growth cycles
|
||||||
|
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult);
|
||||||
|
if (serverGrowth < 1) {
|
||||||
|
console.log("WARN: serverGrowth calculated to be less than 1");
|
||||||
|
serverGrowth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldMoneyAvailable = server.moneyAvailable;
|
||||||
|
server.moneyAvailable *= serverGrowth;
|
||||||
|
|
||||||
|
// in case of data corruption
|
||||||
|
if (server.moneyMax && isNaN(server.moneyAvailable)) {
|
||||||
|
server.moneyAvailable = server.moneyMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cap at max
|
||||||
|
if (server.moneyMax && server.moneyAvailable > server.moneyMax) {
|
||||||
|
server.moneyAvailable = server.moneyMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was any growth at all, increase security
|
||||||
|
if (oldMoneyAvailable !== server.moneyAvailable) {
|
||||||
|
//Growing increases server security twice as much as hacking
|
||||||
|
let usedCycles = numCycleForGrowth(server, server.moneyAvailable / oldMoneyAvailable);
|
||||||
|
usedCycles = Math.max(0, usedCycles);
|
||||||
|
server.fortify(2 * CONSTANTS.ServerFortifyAmount * Math.ceil(usedCycles));
|
||||||
|
}
|
||||||
|
return server.moneyAvailable / oldMoneyAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function prestigeHomeComputer(homeComp) {
|
||||||
|
const hasBitflume = homeComp.programs.includes(Programs.BitFlume.name);
|
||||||
|
|
||||||
|
homeComp.programs.length = 0; //Remove programs
|
||||||
|
homeComp.runningScripts = [];
|
||||||
|
homeComp.serversOnNetwork = [];
|
||||||
|
homeComp.isConnectedTo = true;
|
||||||
|
homeComp.ramUsed = 0;
|
||||||
|
homeComp.programs.push(Programs.NukeProgram.name);
|
||||||
|
if (hasBitflume) { homeComp.programs.push(Programs.BitFlume.name); }
|
||||||
|
|
||||||
|
//Update RAM usage on all scripts
|
||||||
|
homeComp.scripts.forEach(function(script) {
|
||||||
|
script.updateRamUsage();
|
||||||
|
});
|
||||||
|
|
||||||
|
homeComp.messages.length = 0; //Remove .lit and .msg files
|
||||||
|
homeComp.messages.push("hackers-starting-handbook.lit");
|
||||||
|
}
|
||||||
|
|
||||||
|
function SizeOfAllServers() {
|
||||||
|
var size = 0, key;
|
||||||
|
for (key in AllServers) {
|
||||||
|
if (AllServers.hasOwnProperty(key)) size++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns server object with corresponding hostname
|
||||||
|
// Relatively slow, would rather not use this a lot
|
||||||
|
export function GetServerByHostname(hostname) {
|
||||||
|
for (var ip in AllServers) {
|
||||||
|
if (AllServers.hasOwnProperty(ip)) {
|
||||||
|
if (AllServers[ip].hostname == hostname) {
|
||||||
|
return AllServers[ip];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get server by IP or hostname. Returns null if invalid
|
||||||
|
export function getServer(s) {
|
||||||
|
if (!isValidIPAddress(s)) {
|
||||||
|
return GetServerByHostname(s);
|
||||||
|
}
|
||||||
|
if(AllServers[s] !== undefined) {
|
||||||
|
return AllServers[s];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
@ -1,33 +0,0 @@
|
|||||||
import {AllServers} from "../src/Server";
|
|
||||||
import {getRandomByte} from "./helpers/getRandomByte";
|
|
||||||
|
|
||||||
/* Functions to deal with manipulating IP addresses*/
|
|
||||||
|
|
||||||
//Generate a random IP address
|
|
||||||
//Will not return an IP address that already exists in the AllServers array
|
|
||||||
function createRandomIp() {
|
|
||||||
var ip = getRandomByte(99) + '.' +
|
|
||||||
getRandomByte(9) + '.' +
|
|
||||||
getRandomByte(9) + '.' +
|
|
||||||
getRandomByte(9);
|
|
||||||
|
|
||||||
//If the Ip already exists, recurse to create a new one
|
|
||||||
if (ipExists(ip)) {
|
|
||||||
return createRandomIp();
|
|
||||||
}
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Returns true if the IP already exists in one of the game's servers
|
|
||||||
function ipExists(ip) {
|
|
||||||
for (var property in AllServers) {
|
|
||||||
if (AllServers.hasOwnProperty(property)) {
|
|
||||||
if (property == ip) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {createRandomIp, ipExists};
|
|
25
utils/IPAddress.ts
Normal file
25
utils/IPAddress.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {AllServers} from "../src/Server";
|
||||||
|
import {getRandomByte} from "./helpers/getRandomByte";
|
||||||
|
|
||||||
|
/* Functions to deal with manipulating IP addresses*/
|
||||||
|
|
||||||
|
//Generate a random IP address
|
||||||
|
//Will not return an IP address that already exists in the AllServers array
|
||||||
|
export function createRandomIp(): string {
|
||||||
|
const ip: string = getRandomByte(99) + '.' +
|
||||||
|
getRandomByte(9) + '.' +
|
||||||
|
getRandomByte(9) + '.' +
|
||||||
|
getRandomByte(9);
|
||||||
|
|
||||||
|
// If the Ip already exists, recurse to create a new one
|
||||||
|
if (ipExists(ip)) {
|
||||||
|
return createRandomIp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the IP already exists in one of the game's servers
|
||||||
|
export function ipExists(ip: string) {
|
||||||
|
return (AllServers[ip] != null);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user