mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
More work on Hacking mission
This commit is contained in:
parent
5e7d72d901
commit
2523222565
@ -144,6 +144,12 @@ a:link, a:visited {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.a-link-button:active {
|
||||
-webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
-moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* Make anchor tags ("a" elements) inactive (not clickable) */
|
||||
.a-link-button-inactive {
|
||||
text-decoration: none;
|
||||
|
1245
dist/bundle.js
vendored
1245
dist/bundle.js
vendored
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
import {workerScripts,
|
||||
addWorkerScript,
|
||||
killWorkerScript} from "./NetscriptWorker.js";
|
||||
import {Player} from "./Player.js";
|
||||
import {getServer} from "./Server.js";
|
||||
import {dialogBoxCreate} from "../utils/DialogBox.js";
|
||||
import {printArray} from "../utils/HelperFunctions.js";
|
||||
@ -182,7 +183,10 @@ function updateActiveScriptsItems() {
|
||||
total += updateActiveScriptsItemContent(workerScripts[i]);
|
||||
}
|
||||
document.getElementById("active-scripts-total-prod").innerHTML =
|
||||
"Total online production rate: $" + formatNumber(total, 2) + " / second";
|
||||
"Total online production of Active Scripts: $" + formatNumber(total, 2) + " / second<br>" +
|
||||
"Total online production since last Augmentation installation: $" +
|
||||
formatNumber(Player.scriptProdSinceLastAug, 2) + " ($" +
|
||||
formatNumber(Player.scriptProdSinceLastAug / Player.playtimeSinceLastAug, 2) + " / second)";
|
||||
return total;
|
||||
}
|
||||
|
||||
|
@ -120,11 +120,48 @@ let CONSTANTS = {
|
||||
IntelligenceProgramBaseExpGain: 1000, //Program required hack level divided by this to determine int exp gain
|
||||
IntelligenceTerminalHackBaseExpGain: 200, //Hacking exp divided by this to determine int exp gain
|
||||
IntelligenceSingFnBaseExpGain: 0.0005,
|
||||
IntelligenceClassBaseExpGain: 0.0000001,
|
||||
|
||||
//Hacking Missions
|
||||
HackingMissionRepToDiffConversion: 5000, //Faction rep is divided by this to get mission difficulty
|
||||
HackingMissionRepToRewardConversion: 20, //Faction rep divided byt his to get mission rep reward
|
||||
HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with factin reputation",
|
||||
HackingMissionSpamTimeIncrease: 20000, //How much time limit increase is gained when conquering a Spam Node (ms)
|
||||
HackingMissionTransferAttackIncrease: 1.05, //Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node
|
||||
HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with faction reputation.<br><br>" +
|
||||
"In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " +
|
||||
"are colored blue, while the enemy's are red. There are also other nodes on the map colored gray" +
|
||||
"that initially belong to neither you nor the enemy. The goal of the game is " +
|
||||
"to capture all of the enemy's database nodes, which are the parallelogram-shaped ones, within the time limit. " +
|
||||
"If you cannot capture all of the enemy's database nodes in the time limit, you will lose.<br><br>" +
|
||||
"Each Node has three stats: Attack, Defense, and HP. There are five different actions that " +
|
||||
"a Node can take:<br><br> " +
|
||||
"Attack - Targets an enemy Node and lowers its HP. The effectiveness is determined by the Node's Attack, the Player's " +
|
||||
"hacking level, and the enemy's defense.<br>" +
|
||||
"Scan - Targets an enemy Node and lowers its Defense. The effectiveness is determined by the Player's hacking level and the " +
|
||||
"enemy's defense.<br>" +
|
||||
"Weaken - Targets an enemy Node and lowers its Attack. The effectiveness is determined by the Player's hacking level and the enemy's " +
|
||||
"defense.<br>" +
|
||||
"Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.<br><br>" +
|
||||
"To capture a Node, you must lower its HP down to 0. " +
|
||||
"A Node's 'Attack' stats affects its effectiveness when attacking other Nodes. A Node's 'Defense' helps protect " +
|
||||
"against the actions of enemy Nodes. One important thing to note is that, when defending, your total 'Defense' " +
|
||||
"(sum of the Defense of all of your Nodes) is what's taken into account when determining the effect of offensive actions. " +
|
||||
"However, when attacking, only the 'Attack' of the Node being used to attack is taken into account.<br><br>" +
|
||||
"There are six different types of Nodes:<br><br>" +
|
||||
"CPU Core - These are your main Nodes that are used to perform actions<br>" +
|
||||
"Firewall - Nodes with high defense. These Nodes cannot perform any actions<br>" +
|
||||
"Database - A special type of Node. The player's objective is to conquer all of the enemy's Database Nodes within " +
|
||||
"the time limit. These Nodes cannot perform any actions<br>" +
|
||||
"Spam - Conquering one of these Nodes will slow the enemy's trace, giving the player additional time to complete " +
|
||||
"the mission. These Nodes cannot perform any actions<br>" +
|
||||
"Transfer - Conquering one of these nodes will increase the Attack of all of your CPU Cores by a small fixed percentage. " +
|
||||
"These Nodes are capable of performing every action except the 'Attack' action<br>" +
|
||||
"Shield - Nodes with high defense. These Nodes cannot perform any actions<br><br>" +
|
||||
"For certain actions such as attacking, scanning, and weakening, the Node performing the action must have a target. To target " +
|
||||
"another node, simply click-and-drag from the 'source' Node to a target. A Node can only have one target, and you can only target " +
|
||||
"Nodes that are adjacent to one of your Nodes (immediately above, below, or to the side. NOT diagonal). Furthermore, only CPU Cores and Transfer Nodes " +
|
||||
"can target, since they are the only ones that can perform actions",
|
||||
|
||||
|
||||
//Gang constants
|
||||
GangRespectToReputationRatio: 2, //Respect is divided by this to get rep gain
|
||||
@ -419,18 +456,18 @@ let CONSTANTS = {
|
||||
"the hostnames or IPs of the scanned servers should be output. If it is true then hostnames will be returned, and if false then IP addresses will. " +
|
||||
"This second argument is optional and, if ommitted, the function will output " +
|
||||
"the hostnames of the scanned servers. The hostnames/IPs in the returned array are strings.<br><br>" +
|
||||
"<i>nuke(hostname/ip)</i><br>Run NUKE.exe on the target server. NUKE.exe must exist on your home computer. Does NOT work while offline <br> Example: nuke('foodnstuff'); <br><br>" +
|
||||
"<i>brutessh(hostname/ip)</i><br>Run BruteSSH.exe on the target server. BruteSSH.exe must exist on your home computer. Does NOT work while offline <br> Example: brutessh('foodnstuff');<br><br>" +
|
||||
"<i>ftpcrack(hostname/ip)</i><br>Run FTPCrack.exe on the target server. FTPCrack.exe must exist on your home computer. Does NOT work while offline <br> Example: ftpcrack('foodnstuff');<br><br>" +
|
||||
"<i>relaysmtp(hostname/ip)</i><br>Run relaySMTP.exe on the target server. relaySMTP.exe must exist on your home computer. Does NOT work while offline <br> Example: relaysmtp('foodnstuff');<br><br>" +
|
||||
"<i>httpworm(hostname/ip)</i><br>Run HTTPWorm.exe on the target server. HTTPWorm.exe must exist on your home computer. Does NOT work while offline <br> Example: httpworm('foodnstuff');<br><br>" +
|
||||
"<i>sqlinject(hostname/ip)</i><br>Run SQLInject.exe on the target server. SQLInject.exe must exist on your home computer. Does NOT work while offline <br> Example: sqlinject('foodnstuff');<br><br>" +
|
||||
"<i>nuke(hostname/ip)</i><br>Run NUKE.exe on the target server. NUKE.exe must exist on your home computer.<br> Example: nuke('foodnstuff'); <br><br>" +
|
||||
"<i>brutessh(hostname/ip)</i><br>Run BruteSSH.exe on the target server. BruteSSH.exe must exist on your home computer.<br> Example: brutessh('foodnstuff');<br><br>" +
|
||||
"<i>ftpcrack(hostname/ip)</i><br>Run FTPCrack.exe on the target server. FTPCrack.exe must exist on your home computer.<br> Example: ftpcrack('foodnstuff');<br><br>" +
|
||||
"<i>relaysmtp(hostname/ip)</i><br>Run relaySMTP.exe on the target server. relaySMTP.exe must exist on your home computer.<br> Example: relaysmtp('foodnstuff');<br><br>" +
|
||||
"<i>httpworm(hostname/ip)</i><br>Run HTTPWorm.exe on the target server. HTTPWorm.exe must exist on your home computer.<br> Example: httpworm('foodnstuff');<br><br>" +
|
||||
"<i>sqlinject(hostname/ip)</i><br>Run SQLInject.exe on the target server. SQLInject.exe must exist on your home computer.<br> Example: sqlinject('foodnstuff');<br><br>" +
|
||||
"<i>run(script, [numThreads], [args...])</i> <br> Run a script as a separate process. The first argument that is passed in is the name of the script as a string. This function can only " +
|
||||
"be used to run scripts located on the current server (the server running the script that calls this function). The second argument " +
|
||||
"is optional, and it specifies how many threads to run the script with. This argument must be a number greater than 0. If it is omitted, then the script will be run single-threaded. Any additional arguments will specify " +
|
||||
"arguments to pass into the new script that is being run. If arguments are specified for the new script, then the second argument numThreads argument must be filled in with a value.<br><br>" +
|
||||
"Returns true if the script is successfully started, and false otherwise. Requires a significant amount " +
|
||||
"of RAM to run this command. Does NOT work while offline <br><br>" +
|
||||
"of RAM to run this command.<br><br>" +
|
||||
"The simplest way to use the run command is to call it with just the script name. The following example will run 'foo.script' single-threaded with no arguments:<br><br>" +
|
||||
"run('foo.script');<br><br>" +
|
||||
"The following example will run 'foo.script' but with 5 threads instead of single-threaded:<br><br>" +
|
||||
@ -442,7 +479,7 @@ let CONSTANTS = {
|
||||
"The third argument is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " +
|
||||
"This argument must be a number that is greater than 0. Any additional arguments will specify arguments to pass into the new script that is being run. If " +
|
||||
"arguments are specified for the new script, then the third argument numThreads must be filled in with a value.<br><br>Returns " +
|
||||
"true if the script is successfully started, and false otherwise. Does NOT work while offline<br><br> " +
|
||||
"true if the script is successfully started, and false otherwise.<br><br> " +
|
||||
"The simplest way to use the exec command is to call it with just the script name and the target server. The following example will try to run 'generic-hack.script' " +
|
||||
"on the 'foodnstuff' server:<br><br>" +
|
||||
"exec('generic-hack.script', 'foodnstuff');<br><br>" +
|
||||
@ -480,11 +517,11 @@ let CONSTANTS = {
|
||||
"<i>ls(hostname/ip)</i><br>Returns an array containing the names of all files on the specified server. The argument must be a " +
|
||||
"string with the hostname or IP of the target server.<br><br>" +
|
||||
"<i>hasRootAccess(hostname/ip)</i><br> Returns a boolean (true or false) indicating whether or not the Player has root access to a server. " +
|
||||
"The argument passed in must be a string with either the hostname or IP of the target server. Does NOT work while offline.<br> " +
|
||||
"The argument passed in must be a string with either the hostname or IP of the target server.<br> " +
|
||||
"Example:<br>if (hasRootAccess('foodnstuff') == false) {<br> nuke('foodnstuff');<br>}<br><br>" +
|
||||
"<i>getIp()</i><br>Returns a string with the IP Address of the server that the script is running on <br><br>" +
|
||||
"<i>getHostname()</i><br>Returns a string with the hostname of the server that the script is running on<br><br>" +
|
||||
"<i>getHackingLevel()</i><br>Returns the Player's current hacking level. Does NOT work while offline<br><br> " +
|
||||
"<i>getHackingLevel()</i><br>Returns the Player's current hacking level.<br><br> " +
|
||||
"<i>getIntelligence()</i><br>Returns the Player's current intelligence level. Requires Source-File 5 to run<br><br>" +
|
||||
"<i>getHackingMultipliers()</i><br>Returns an object containing the Player's hacking related multipliers. " +
|
||||
"These multipliers are returned in integer forms, not percentages (e.g. 1.5 instead of 150%). " +
|
||||
@ -529,24 +566,26 @@ let CONSTANTS = {
|
||||
"print(mults.ServerMaxMoney);<br>" +
|
||||
"print(mults.HackExpGain);<br><br>" +
|
||||
"<i>getServerMoneyAvailable(hostname/ip)</i><br> Returns the amount of money available on a server. The argument passed in must be a string with either the " +
|
||||
"hostname or IP of the target server. Does NOT work while offline <br> Example: getServerMoneyAvailable('foodnstuff');<br><br>" +
|
||||
"hostname or IP of the target server.<br> Example: getServerMoneyAvailable('foodnstuff');<br><br>" +
|
||||
"<i>getServerMaxMoney(hostname/ip)</i><br>Returns the maximum amount of money that can be available on a server. The argument passed in must be a string with " +
|
||||
"the hostname or IP of the target server. Does NOT work while offline<br>Example: getServerMaxMoney('foodnstuff');<br><br>" +
|
||||
"the hostname or IP of the target server.<br>Example: getServerMaxMoney('foodnstuff');<br><br>" +
|
||||
"<i>getServerGrowth(hostname/ip)</i><br>Returns the server's intrinsic 'growth parameter'. This growth parameter is a number " +
|
||||
"between 1 and 100 that represents how quickly the server's money grows. This parameter affects the percentage by which this server's " +
|
||||
"money is increased when using the grow() function. A higher growth parameter will result in a higher percentage from grow().<br><br>" +
|
||||
"The argument passed in must be a string with the hostname or IP of the target server.<br><br>" +
|
||||
"<i>getServerSecurityLevel(hostname/ip)</i><br>Returns the security level of a server. The argument passed in must be a string with either the " +
|
||||
"hostname or IP of the target server. A server's security is denoted by a number between 1 and 100. Does NOT work while offline.<br><br>" +
|
||||
"<i>getServerBaseSecurityLevel(hostname/ip)</i><br> Returns the base security level of a server. This is the security level that the server starts out with. " +
|
||||
"hostname or IP of the target server. A server's security is denoted by a number, typically between 1 and 100.<br><br>" +
|
||||
"<i>getServerBaseSecurityLevel(hostname/ip)</i><br>Returns the base security level of a server. This is the security level that the server starts out with. " +
|
||||
"This is different than getServerSecurityLevel() because getServerSecurityLevel() returns the current security level of a server, which can constantly change " +
|
||||
"due to hack(), grow(), and weaken() calls on that server. The base security level will stay the same until you reset by installing an Augmentation. <br><br>" +
|
||||
"The argument passed in must be a string with either the hostname or IP of the target server. A server's base security is denoted by a number between 1 and 100. " +
|
||||
"Does NOT work while offline.<br><br>" +
|
||||
"The argument passed in must be a string with either the hostname or IP of the target server. A server's base security is denoted by a number, typically between 1 and 100. " +
|
||||
"<br><br>" +
|
||||
"<i>getServerMinSecurityLevel(hostname/ip)</i>Returns the minimum security level of a server. The argument passed in must be a string with " +
|
||||
"either the hostname or IP of the target server.<br><br>" +
|
||||
"<i>getServerRequiredHackingLevel(hostname/ip)</i><br>Returns the required hacking level of a server. The argument passed in must be a string with either the " +
|
||||
"hostname or IP or the target server. Does NOT work while offline <br><br>" +
|
||||
"hostname or IP or the target server.<br><br>" +
|
||||
"<i>getServerNumPortsRequired(hostname/ip)</i><br>Returns the number of open ports required to successfully run NUKE.exe on a server. The argument " +
|
||||
"passed in must be a string with either the hostname or IP of the target server. Does NOT work while offline<br><br>" +
|
||||
"passed in must be a string with either the hostname or IP of the target server.<br><br>" +
|
||||
"<i>getServerRam(hostname/ip)</i><br>Returns an array with two elements that gives information about the target server's RAM. The first " +
|
||||
"element in the array is the amount of RAM that the server has (in GB). The second element in the array is the amount of RAM that " +
|
||||
"is currently being used on the server.<br><br>" +
|
||||
@ -960,6 +999,12 @@ let CONSTANTS = {
|
||||
LatestUpdate:
|
||||
"v0.29.1<br>" +
|
||||
"-Added continue statement for for/while loops<br>" +
|
||||
"-Added getServerMinSecurityLevel() Netscript function<br>" +
|
||||
"-Added Javascript's Date module to Netscript. Since 'new' is not supported in Netscript yet, only the Date module's " +
|
||||
"static methods will work (now(), UTC(), parse(), etc.).<br>" +
|
||||
"-Failing a crime now gives half the experience it did before<br>" +
|
||||
"-The repeated 'Find The-Cave' message after installing The Red Pill Augmentation now only happens " +
|
||||
"if you've never destroyed a BitNode before<br>" +
|
||||
"-fileExists() function now works on literature files<br><br>" +
|
||||
"v0.29.0<br>" +
|
||||
"-Added BitNode-5: Artificial Intelligence<br>" +
|
||||
|
307
src/Missions.js
307
src/Missions.js
@ -1,9 +1,11 @@
|
||||
import {CONSTANTS} from "./Constants.js";
|
||||
import {Engine} from "./engine.js";
|
||||
import {displayFactionContent} from "./Faction.js";
|
||||
import {Player} from "./Player.js";
|
||||
import {dialogBoxCreate} from "../utils/DialogBox.js";
|
||||
import {addOffset, getRandomInt,
|
||||
clearEventListenersEl} from "../utils/HelperFunctions.js";
|
||||
clearEventListenersEl,
|
||||
clearEventListeners} from "../utils/HelperFunctions.js";
|
||||
import {formatNumber, isString} from "../utils/StringHelperFunctions.js";
|
||||
import jsplumb from 'jsplumb'
|
||||
|
||||
@ -17,47 +19,48 @@ function setInMission(bool, mission) {
|
||||
currMission = null;
|
||||
}
|
||||
}
|
||||
/* Hacking Missions */
|
||||
|
||||
/*You start with N CPU nodes dependent on home computer cores
|
||||
//Keyboard shortcuts
|
||||
$(document).keydown(function(e) {
|
||||
if (inMission && currMission && currMission.selectedNode != null) {
|
||||
switch (e.keyCode) {
|
||||
case 65: //a for Attack
|
||||
currMission.actionButtons[0].click();
|
||||
break;
|
||||
case 83: //s for Scan
|
||||
currMission.actionButtons[1].click();
|
||||
break;
|
||||
case 87: //w for Weaken
|
||||
currMission.actionButtons[2].click();
|
||||
break;
|
||||
case 70: //f for Fortify
|
||||
currMission.actionButtons[3].click();
|
||||
break;
|
||||
case 82: //r for Overflow
|
||||
currMission.actionButtons[4].click();
|
||||
break;
|
||||
case 68: //d for Detach connection
|
||||
currMission.actionButtons[5].click();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Three main stats:
|
||||
Attack - Specific to a node. Affected by hacking skill, RAM (for home comp)
|
||||
Defense - Universal defense - summed from all nodes
|
||||
HP - Specific to a node. Affected by hacking skill, RAM (for home comp)
|
||||
|
||||
Enemy has the following nodes:
|
||||
Firewall Nodes - Essentially shields. Weak attack but large def
|
||||
CPU Nodes - Defeating and capturing these will give you new nodes to use
|
||||
Database Node - Main Target
|
||||
|
||||
Misc Nodes (initially not owned by player or enemy):
|
||||
Spam nodes - Increases time limit
|
||||
Transfer Nodes - Slightly increases attack for all of your CPUs
|
||||
Shield Node - Increases your defense
|
||||
|
||||
Shapes for nodes:
|
||||
Firewall - Rectangle
|
||||
CPU - Circle
|
||||
Database - Parralelogram
|
||||
Spam - Diamond
|
||||
Transfer - Cone
|
||||
Shield - Shield shape
|
||||
|
||||
*/
|
||||
let NodeTypes = {
|
||||
Core: "CPU Core Node", //All actions available
|
||||
Firewall: "Firewall Node", //No actions available
|
||||
Database: "Database Node", //No actions available
|
||||
Spam: "Spam Node", //No actions Available
|
||||
Transfer: "Transfer Node", //Can Weaken, Scan, and Overflow
|
||||
Transfer: "Transfer Node", //Can Weaken, Scan, Fortify and Overflow
|
||||
Shield: "Shield Node" //Can Fortify
|
||||
}
|
||||
|
||||
let NodeActions = {
|
||||
Attack: "Attacking", //Damaged based on attack stat + hacking level + opp def
|
||||
Scan: "Scanning", //-Def for target, affected by hacking level
|
||||
Weaken: "Weakening", //-Attack for target, affected by hacking level
|
||||
Scan: "Scanning", //-Def for target, affected by attack and hacking level
|
||||
Weaken: "Weakening", //-Attack for target, affected by attack and hacking level
|
||||
Fortify: "Fortifying", //+Defense for Node, affected by hacking level
|
||||
Overflow: "Overflowing", //+Attack but -Defense for Node, affected by hacking level
|
||||
}
|
||||
@ -126,8 +129,12 @@ Node.prototype.select = function(actionButtons) {
|
||||
actionButtons[1].classList.add("a-link-button");
|
||||
actionButtons[2].classList.remove("a-link-button-inactive");
|
||||
actionButtons[2].classList.add("a-link-button");
|
||||
actionButtons[3].classList.remove("a-link-button-inactive");
|
||||
actionButtons[3].classList.add("a-link-button");
|
||||
actionButtons[4].classList.remove("a-link-button-inactive");
|
||||
actionButtons[4].classList.add("a-link-button");
|
||||
actionButtons[5].classList.remove("a-link-button-inactive");
|
||||
actionButtons[5].classList.add("a-link-button");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -135,7 +142,7 @@ Node.prototype.select = function(actionButtons) {
|
||||
}
|
||||
|
||||
Node.prototype.deselect = function(actionButtons) {
|
||||
this.el.classList.remove("active");
|
||||
this.el.classList.remove("hack-mission-player-node-active");
|
||||
for (var i = 0; i < actionButtons.length; ++i) {
|
||||
actionButtons[i].classList.remove("a-link-button");
|
||||
actionButtons[i].classList.add("a-link-button-inactive");
|
||||
@ -148,6 +155,7 @@ Node.prototype.deselect = function(actionButtons) {
|
||||
function HackingMission(rep, fac) {
|
||||
this.faction = fac;
|
||||
|
||||
this.started = false;
|
||||
this.time = 120000; //2 minutes, milliseconds
|
||||
|
||||
this.playerCores = [];
|
||||
@ -204,8 +212,8 @@ HackingMission.prototype.init = function() {
|
||||
}
|
||||
|
||||
//Randomly generate enemy nodes (CPU and Firewall) based on difficulty
|
||||
var numNodes = getRandomInt(this.difficulty, this.difficulty + 2);
|
||||
var numFirewalls = getRandomInt(this.difficulty, this.difficulty + 5);
|
||||
var numNodes = getRandomInt(this.difficulty, this.difficulty + 1);
|
||||
var numFirewalls = getRandomInt(this.difficulty, this.difficulty + 2);
|
||||
var numDatabases = getRandomInt(this.difficulty, this.difficulty + 1);
|
||||
var totalNodes = numNodes + numFirewalls + numDatabases;
|
||||
var xlimit = 7 - Math.floor(totalNodes / 8);
|
||||
@ -216,8 +224,8 @@ HackingMission.prototype.init = function() {
|
||||
var randMult = addOffset(this.difficulty, 20);
|
||||
for (var i = 0; i < numNodes; ++i) {
|
||||
var stats = {
|
||||
atk: randMult * getRandomInt(150, 200),
|
||||
def: randMult * getRandomInt(40, 75),
|
||||
atk: randMult * getRandomInt(125, 175),
|
||||
def: randMult * getRandomInt(30, 50),
|
||||
hp: randMult * getRandomInt(225, 275)
|
||||
}
|
||||
this.enemyCores.push(new Node(NodeTypes.Core, stats));
|
||||
@ -283,15 +291,23 @@ HackingMission.prototype.createPageDom = function() {
|
||||
//Start button will get replaced with forfeit when game is started
|
||||
var startBtn = document.createElement("a");
|
||||
startBtn.innerHTML = "Start";
|
||||
startBtn.setAttribute("id", "hack-mission-start-btn");
|
||||
startBtn.classList.add("a-link-button");
|
||||
startBtn.classList.add("hack-mission-header-element");
|
||||
startBtn.style.display = "inline-block";
|
||||
startBtn.addEventListener("click", ()=>{
|
||||
this.start();
|
||||
});
|
||||
|
||||
var timer = document.createElement("p");
|
||||
timer.setAttribute("id", "hacking-mission-timer");
|
||||
timer.style.display = "inline-block";
|
||||
|
||||
//Create Action Buttons (Attack/Scan/Weaken/ etc...)
|
||||
var actionsContainer = document.createElement("span");
|
||||
actionsContainer.style.display = "block";
|
||||
actionsContainer.classList.add("hack-mission-action-buttons-container");
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
for (var i = 0; i < 6; ++i) {
|
||||
this.actionButtons.push(document.createElement("a"));
|
||||
this.actionButtons[i].style.display = "inline-block";
|
||||
this.actionButtons[i].classList.add("a-link-button-inactive"); //Disabled at start
|
||||
@ -303,19 +319,19 @@ HackingMission.prototype.createPageDom = function() {
|
||||
var atkTooltip = document.createElement("span");
|
||||
atkTooltip.classList.add("tooltiptext");
|
||||
atkTooltip.innerText = "Lowers the targeted node's HP. The effectiveness of this depends on " +
|
||||
"this node's Attack level, your hacking level, and the opponents defense level.";
|
||||
"this node's Attack level, your hacking level, and the opponent's defense level.";
|
||||
this.actionButtons[0].appendChild(atkTooltip);
|
||||
this.actionButtons[1].innerText = "Scan(s)";
|
||||
var scanTooltip = document.createElement("span");
|
||||
scanTooltip.classList.add("tooltiptext");
|
||||
scanTooltip.innerText = "Lowers the targeted node's defense. The effectiveness of this depends on " +
|
||||
"this node's Attack level and your hacking level";
|
||||
"this node's Attack level, your hacking level, and the opponent's defense level.";
|
||||
this.actionButtons[1].appendChild(scanTooltip);
|
||||
this.actionButtons[2].innerText = "Weaken(w)";
|
||||
var WeakenTooltip = document.createElement("span");
|
||||
WeakenTooltip.classList.add("tooltiptext");
|
||||
WeakenTooltip.innerText = "Lowers the targeted node's attack. The effectiveness of this depends on " +
|
||||
"this node's Attack level and your hacking level";
|
||||
"this node's Attack level, your hacking level, and the opponent's defense level.";
|
||||
this.actionButtons[2].appendChild(WeakenTooltip);
|
||||
this.actionButtons[3].innerText = "Fortify(f)";
|
||||
var fortifyTooltip = document.createElement("span");
|
||||
@ -329,6 +345,26 @@ HackingMission.prototype.createPageDom = function() {
|
||||
overflowTooltip.innerText = "Raises this node's Attack level but lowers its Defense level. The effectiveness " +
|
||||
"of this depends on your hacking level.";
|
||||
this.actionButtons[4].appendChild(overflowTooltip);
|
||||
this.actionButtons[5].innerText = "Drop Connection(d)";
|
||||
var dropconnTooltip = document.createElement("span");
|
||||
dropconnTooltip.classList.add("tooltiptext");
|
||||
dropconnTooltip.innerText = "Removes this Node's current connection to some target Node, if it has one. This can " +
|
||||
"also be done by simply clicking the white connection line.";
|
||||
this.actionButtons[5].appendChild(dropconnTooltip);
|
||||
|
||||
//Player/enemy defense displays will be in action container
|
||||
var playerDefense = document.createElement("p");
|
||||
var enemyDefense = document.createElement("p");
|
||||
playerDefense.style.display = "inline-block";
|
||||
enemyDefense.style.display = "inline-block";
|
||||
playerDefense.style.color = "blue";
|
||||
enemyDefense.style.color = "red";
|
||||
playerDefense.style.margin = "4px";
|
||||
enemyDefense.style.margin = "4px";
|
||||
playerDefense.setAttribute("id", "hacking-mission-player-def");
|
||||
enemyDefense.setAttribute("id", "hacking-mission-enemy-def");
|
||||
actionsContainer.appendChild(playerDefense);
|
||||
actionsContainer.appendChild(enemyDefense);
|
||||
|
||||
//Set Action Button event listeners
|
||||
this.actionButtons[0].addEventListener("click", ()=>{
|
||||
@ -381,12 +417,24 @@ HackingMission.prototype.createPageDom = function() {
|
||||
this.selectedNode.action = NodeActions.Overflow;
|
||||
});
|
||||
|
||||
this.actionButtons[5].addEventListener("click", ()=>{
|
||||
if (!(this.selectedNode instanceof Node)) {
|
||||
console.log("ERR: Pressing Action button without selected node");
|
||||
return;
|
||||
}
|
||||
if (this.selectedNode.conn) {
|
||||
var endpoints = this.selectedNode.conn.endpoints;
|
||||
endpoints[0].detachFrom(endpoints[1]);
|
||||
}
|
||||
})
|
||||
|
||||
var timeDisplay = document.createElement("p");
|
||||
|
||||
container.appendChild(headerText);
|
||||
container.appendChild(inGameGuideBtn);
|
||||
container.appendChild(wikiGuideBtn);
|
||||
container.appendChild(startBtn);
|
||||
container.appendChild(timer);
|
||||
container.appendChild(actionsContainer);
|
||||
container.appendChild(timeDisplay);
|
||||
}
|
||||
@ -446,8 +494,9 @@ HackingMission.prototype.calculateDefenses = function() {
|
||||
for (var i = 0; i < this.playerNodes.length; ++i) {
|
||||
total += this.playerNodes[i].def;
|
||||
}
|
||||
console.log("player defenses calculated to be: " + total);
|
||||
this.playerDef = total;
|
||||
document.getElementById("hacking-mission-player-def").innerText =
|
||||
"Player Defense: " + formatNumber(this.playerDef, 1);
|
||||
total = 0;
|
||||
for (var i = 0; i < this.enemyCores.length; ++i) {
|
||||
total += this.enemyCores[i].def;
|
||||
@ -458,8 +507,9 @@ HackingMission.prototype.calculateDefenses = function() {
|
||||
for (var i = 0; i < this.enemyNodes.length; ++i) {
|
||||
total += this.enemyNodes[i].def;
|
||||
}
|
||||
console.log("enemy defenses calculated to be: " + total);
|
||||
this.enemyDef = total;
|
||||
document.getElementById("hacking-mission-enemy-def").innerText =
|
||||
"Enemy Defense: " + formatNumber(this.enemyDef, 1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.removeAvailablePosition = function(x, y) {
|
||||
@ -513,16 +563,16 @@ HackingMission.prototype.createMap = function() {
|
||||
case 0: //Spam
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: randMult * getRandomInt(10, 20),
|
||||
hp: randMult * getRandomInt(60, 90)
|
||||
def: randMult * getRandomInt(30, 40),
|
||||
hp: randMult * getRandomInt(70, 90)
|
||||
}
|
||||
node = new Node(NodeTypes.Spam, stats);
|
||||
break;
|
||||
case 1: //Transfer
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: randMult * getRandomInt(35, 45),
|
||||
hp: randMult * getRandomInt(75, 90)
|
||||
def: randMult * getRandomInt(50, 70),
|
||||
hp: randMult * getRandomInt(80, 95)
|
||||
}
|
||||
node = new Node(NodeTypes.Transfer, stats);
|
||||
break;
|
||||
@ -530,8 +580,8 @@ HackingMission.prototype.createMap = function() {
|
||||
default:
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: randMult * getRandomInt(80, 100),
|
||||
hp: randMult * getRandomInt(100, 125)
|
||||
def: randMult * getRandomInt(90, 105),
|
||||
hp: randMult * getRandomInt(130, 150)
|
||||
}
|
||||
node = new Node(NodeTypes.Shield, stats);
|
||||
break;
|
||||
@ -555,8 +605,6 @@ HackingMission.prototype.createMap = function() {
|
||||
console.log("Configuring Player Node: " + this.playerCores[i].el.id);
|
||||
this.configurePlayerNodeElement(this.playerCores[i].el);
|
||||
}
|
||||
|
||||
this.initJsPlumb();
|
||||
}
|
||||
|
||||
HackingMission.prototype.createNodeDomElement = function(nodeObj) {
|
||||
@ -712,6 +760,8 @@ HackingMission.prototype.configureEnemyNodeElement = function(el) {
|
||||
if (this.selectedNode == nodeObj) {
|
||||
nodeObj.deselect(this.actionButtons);
|
||||
}
|
||||
|
||||
//TODO Need to remove event listeners
|
||||
}
|
||||
|
||||
//Returns bool indicating whether a node is reachable by player
|
||||
@ -725,6 +775,17 @@ HackingMission.prototype.nodeReachable = function(node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HackingMission.prototype.start = function() {
|
||||
this.started = true;
|
||||
this.initJsPlumb();
|
||||
var startBtn = clearEventListeners("hack-mission-start-btn");
|
||||
startBtn.innerHTML = "Forfeit Mission";
|
||||
startBtn.addEventListener("click", ()=>{
|
||||
this.finishMission(false);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
HackingMission.prototype.initJsPlumb = function() {
|
||||
var instance = jsPlumb.getInstance({
|
||||
DragOptions:{cursor:"pointer", zIndex:2000},
|
||||
@ -828,31 +889,51 @@ HackingMission.prototype.dropAllConnectionsToNode = function(node) {
|
||||
}
|
||||
|
||||
HackingMission.prototype.process = function(numCycles=1) {
|
||||
var res = true;
|
||||
if (!this.started) {return;}
|
||||
var res = false;
|
||||
//Process actions of all player nodes
|
||||
for (var i = 0; i < this.playerCores.length; ++i) {
|
||||
res &= this.processNode(this.playerCores[i], numCycles);
|
||||
}
|
||||
this.playerCores.forEach((node)=>{
|
||||
res |= this.processNode(node, numCycles);
|
||||
});
|
||||
|
||||
this.playerNodes.forEach((node)=>{
|
||||
if (node.type === NodeTypes.Transfer) {
|
||||
res |= this.processNode(node, numCycles);
|
||||
}
|
||||
});
|
||||
|
||||
//Process actions of all enemy nodes
|
||||
for (var i = 0; i < this.enemyCores.length; ++i) {
|
||||
res &= this.processNode(this.enemyCores[i], numCycles);
|
||||
}
|
||||
this.enemyCores.forEach((node)=>{
|
||||
res |= this.processNode(node, numCycles);
|
||||
});
|
||||
|
||||
this.enemyNodes.forEach((node)=>{
|
||||
if (node.type === NodeTypes.Transfer) {
|
||||
res |= this.processNode(node, numCycles);
|
||||
}
|
||||
});
|
||||
|
||||
if (res) {this.calculateDefenses();}
|
||||
|
||||
//TODO Check if win/lose
|
||||
if (this.enemyDatabases.length === 0) {
|
||||
this.finishMission(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//Update timer and check if player lost
|
||||
this.time -= (numCycles * Engine._idleSpeed);
|
||||
if (this.time <= 0) {
|
||||
this.finishMission(false);
|
||||
return;
|
||||
}
|
||||
this.updateTimer();
|
||||
}
|
||||
|
||||
//Returns a bool representing whether defenses need to be re-calculated
|
||||
HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
if (nodeObj.action === null) {return;}
|
||||
if (nodeObj.action === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var targetNode = null, def;
|
||||
if (nodeObj.conn) {
|
||||
@ -876,13 +957,13 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
break;
|
||||
case NodeActions.Scan:
|
||||
if (nodeObj.conn === null) {break;}
|
||||
var eff = this.calculateScanEffect(def, Player.hacking_skill);
|
||||
var eff = this.calculateScanEffect(nodeObj.atk, def, Player.hacking_skill);
|
||||
targetNode.def -= (eff/5 * numCycles);
|
||||
calcDefenses = true;
|
||||
break;
|
||||
case NodeActions.Weaken:
|
||||
if (nodeObj.conn === null) {break;}
|
||||
var eff = this.calculateWeakenEffect(def, Player.hacking_skill);
|
||||
var eff = this.calculateWeakenEffect(nodeObj.atk, def, Player.hacking_skill);
|
||||
targetNode.atk -= (eff/5 * numCycles);
|
||||
break;
|
||||
case NodeActions.Fortify:
|
||||
@ -917,31 +998,60 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
if (this.selectedNode == targetNode) {
|
||||
targetNode.deselect();
|
||||
}
|
||||
|
||||
//Flag for whether the target node was a misc node
|
||||
var isMiscNode = !targetNode.plyrCtrl && !targetNode.enmyCtrl;
|
||||
console.log("isMiscNode: " + isMiscNode);
|
||||
|
||||
//Remove all connections from Node
|
||||
this.dropAllConnectionsToNode(targetNode);
|
||||
this.dropAllConnectionsFromNode(targetNode);
|
||||
|
||||
//Changes the css class and turn the node into a JsPlumb Source/Target
|
||||
if (conqueredByPlayer) {
|
||||
targetNode.setControlledByPlayer()
|
||||
} else { //Conquered by enemy
|
||||
targetNode.setControlledByPlayer();
|
||||
this.jsplumbinstance.unmakeTarget(targetNode.el);
|
||||
this.jsplumbinstance.makeSource(targetNode.el, {
|
||||
deleteEndpointsOnEmpty:true,
|
||||
maxConnections:1,
|
||||
anchor:"Center",
|
||||
connector:"Straight"
|
||||
});
|
||||
} else {
|
||||
targetNode.setControlledByEnemy();
|
||||
this.jsplumbinstance.unmakeSource(targetNode.el);
|
||||
this.jsplumbinstance.makeTarget(targetNode.el, {
|
||||
maxConnections:-1,
|
||||
anchor:"Center",
|
||||
connector:["Straight"]
|
||||
});
|
||||
}
|
||||
|
||||
calcDefenses = true;
|
||||
|
||||
//Helper function to swap nodes between the respective enemyNodes/playerNodes arrays
|
||||
function swapNodes(orig, dest, targetNode) {
|
||||
console.log("swapNodes called");
|
||||
for (var i = 0; i < orig.length; ++i) {
|
||||
if (orig[i] == targetNode) {
|
||||
console.log("Swapping nodes");
|
||||
var node = orig.splice(i, 1);
|
||||
node = node[0];
|
||||
dest.push(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Whether conquered node was a misc node
|
||||
switch(targetNode.type) {
|
||||
case NodeTypes.Core:
|
||||
if (conqueredByPlayer) {
|
||||
swapNodes(this.enemyCores, this.playerCores, targetNode);
|
||||
this.configurePlayerNodeElement(targetNode.el);
|
||||
} else {
|
||||
swapNodes(this.playerCores, this.enemyCores, targetNode);
|
||||
this.configureEnemyNodeElement(targetNode.el);
|
||||
}
|
||||
break;
|
||||
case NodeTypes.Firewall:
|
||||
@ -952,12 +1062,44 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
}
|
||||
break;
|
||||
case NodeTypes.Database:
|
||||
if (conqueredByPlayer) {
|
||||
swapNodes(this.enemyDatabases, this.playerNodes, targetNode);
|
||||
} else {
|
||||
swapNodes(this.playerNodes, this.enemyDatabases, targetNode);
|
||||
}
|
||||
break;
|
||||
case NodeTypes.Spam:
|
||||
if (conqueredByPlayer) {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
|
||||
} else {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
|
||||
}
|
||||
|
||||
//Conquering spam node increases time limit
|
||||
this.time += CONSTANTS.HackingMissionSpamTimeIncrease;
|
||||
break;
|
||||
case NodeTypes.Transfer:
|
||||
//Conquering a Transfer node increases the attack of all cores by some percentages
|
||||
if (conqueredByPlayer) {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
|
||||
this.playerCores.forEach(function(node) {
|
||||
node.atk *= CONSTANTS.HackingMissionTransferAttackIncrease;
|
||||
});
|
||||
this.configurePlayerNodeElement(targetNode.el);
|
||||
} else {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
|
||||
this.enemyCores.forEach(function(node) {
|
||||
node.atk *= CONSTANTS.HackingMissionTransferAttackIncrease;
|
||||
});
|
||||
this.configureEnemyNodeElement(targetNode.el);
|
||||
}
|
||||
break;
|
||||
case NodeTypes.Shield:
|
||||
if (conqueredByPlayer) {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
|
||||
} else {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -967,7 +1109,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
}
|
||||
|
||||
var hackEffWeightSelf = 100; //Weight for Node actions on self
|
||||
var hackEffWeightTarget = 10; //Weight for Node Actions against Target
|
||||
var hackEffWeightTarget = 15; //Weight for Node Actions against Target
|
||||
var hackEffWeightAttack = 100; //Weight for Attack action
|
||||
|
||||
//Returns damage per cycle based on stats
|
||||
@ -975,12 +1117,12 @@ HackingMission.prototype.calculateAttackDamage = function(atk, def, hacking = 0)
|
||||
return Math.max(atk + (hacking / hackEffWeightAttack) - def, 0.1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.calculateScanEffect = function(def, hacking=0) {
|
||||
return Math.max(hacking / hackEffWeightTarget - def, 0.1);
|
||||
HackingMission.prototype.calculateScanEffect = function(atk, def, hacking=0) {
|
||||
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 0.1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.calculateWeakenEffect = function(def, hacking=0) {
|
||||
return Math.max(hacking / hackEffWeightTarget - def, 0.1);
|
||||
HackingMission.prototype.calculateWeakenEffect = function(atk, def, hacking=0) {
|
||||
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 0.1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.calculateFortifyEffect = function(hacking=0) {
|
||||
@ -991,9 +1133,40 @@ HackingMission.prototype.calculateOverflowEffect = function(hacking=0) {
|
||||
return hacking / hackEffWeightSelf;
|
||||
}
|
||||
|
||||
//Updates timer display
|
||||
HackingMission.prototype.updateTimer = function() {
|
||||
var timer = document.getElementById("hacking-mission-timer");
|
||||
|
||||
//Convert time remaining to a string of the form m:ss
|
||||
var seconds = Math.round(this.time / 1000);
|
||||
var minutes = Math.trunc(seconds / 60);
|
||||
seconds %= 60;
|
||||
var str = ("0" + minutes).slice(-2) + ":" + ("0" + seconds).slice(-2);
|
||||
timer.innerText = "Time left: " + str;
|
||||
}
|
||||
|
||||
//The 'win' argument is a bool for whether or not the player won
|
||||
HackingMission.prototype.finishMission = function(win) {
|
||||
inMission = false;
|
||||
currMission = null;
|
||||
|
||||
if (win) {
|
||||
dialogBoxCreate("Mission won!");
|
||||
} else {
|
||||
dialogBoxCreate("Mission lost!");
|
||||
}
|
||||
|
||||
//Clear mission container
|
||||
var container = document.getElementById("mission-container");
|
||||
while(container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
|
||||
//Return to Faction page
|
||||
document.getElementById("mainmenu-container").style.visibility = "visible";
|
||||
document.getElementById("character-overview-wrapper").style.visibility = "visible";
|
||||
Engine.loadFactionContent();
|
||||
displayFactionContent(this.faction.name);
|
||||
}
|
||||
|
||||
export {HackingMission, inMission, setInMission, currMission};
|
||||
|
@ -64,6 +64,7 @@ function initSingularitySFFlags() {
|
||||
function NetscriptFunctions(workerScript) {
|
||||
return {
|
||||
Math : Math,
|
||||
Date : Date,
|
||||
hacknetnodes : Player.hacknetNodes,
|
||||
scan : function(ip=workerScript.serverIp, hostnames=true){
|
||||
var server = getServer(ip);
|
||||
@ -135,6 +136,7 @@ function NetscriptFunctions(workerScript) {
|
||||
|
||||
Player.gainMoney(moneyGained);
|
||||
workerScript.scriptRef.onlineMoneyMade += moneyGained;
|
||||
Player.scriptProdSinceLastAug += moneyGained;
|
||||
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
|
||||
Player.gainHackingExp(expGainedOnSuccess);
|
||||
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
|
||||
@ -703,6 +705,15 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.scriptRef.log("getServerBaseSecurityLevel() returned " + formatNumber(server.baseDifficulty, 3) + " for " + server.hostname);
|
||||
return server.baseDifficulty;
|
||||
},
|
||||
getServerMinSecurityLevel : function(ip) {
|
||||
var server = getServer(ip);
|
||||
if (server == null) {
|
||||
workerScript.scriptRef.log("getServerMinSecurityLevel() failed. Invalid IP or hostname passed in: " + ip);
|
||||
throw makeRuntimeRejectMsg(workerScript, "getServerMinSecurityLevel() failed. Invalid IP or hostname passed in: " + ip);
|
||||
}
|
||||
workerScript.scriptRef.log("getServerMinSecurityLevel() returned " + formatNumber(server.minDifficulty, 3) + " for " + server.hostname);
|
||||
return server.minDifficulty;
|
||||
},
|
||||
getServerRequiredHackingLevel : function(ip){
|
||||
var server = getServer(ip);
|
||||
if (server == null) {
|
||||
@ -872,6 +883,7 @@ function NetscriptFunctions(workerScript) {
|
||||
var netProfit = ((stock.price - stock.playerAvgPx) * shares) - CONSTANTS.StockMarketCommission;
|
||||
if (isNaN(netProfit)) {netProfit = 0;}
|
||||
workerScript.scriptRef.onlineMoneyMade += netProfit;
|
||||
Player.scriptProdSinceLastAug += netProfit;
|
||||
|
||||
stock.playerShares -= shares;
|
||||
if (stock.playerShares == 0) {
|
||||
@ -984,6 +996,21 @@ function NetscriptFunctions(workerScript) {
|
||||
"as a purchased server. This is likely a bug please contact game dev");
|
||||
return false;
|
||||
},
|
||||
getPurchasedServers : function(hostname=true) {
|
||||
var res = [];
|
||||
Player.purchasedServers.forEach(function(ip) {
|
||||
if (hostname) {
|
||||
var server = getServer(ip);
|
||||
if (server == null) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "ERR: Could not find server in getPurchasedServers(). This is a bug please report to game dev");
|
||||
}
|
||||
res.push(server.hostname);
|
||||
} else {
|
||||
res.push(ip);
|
||||
}
|
||||
});
|
||||
return res;
|
||||
},
|
||||
round : function(n) {
|
||||
if (isNaN(n)) {return 0;}
|
||||
return Math.round(n);
|
||||
|
@ -93,8 +93,7 @@ function PlayerObject() {
|
||||
|
||||
//Servers
|
||||
this.currentServer = ""; //IP address of Server currently being accessed through terminal
|
||||
this.discoveredServers = []; //IP addresses of secret servers not in the network that you have discovered
|
||||
this.purchasedServers = [];
|
||||
this.purchasedServers = []; //IP Addresses of purchased servers
|
||||
this.hacknetNodes = [];
|
||||
this.totalHacknetNodeProduction = 0;
|
||||
|
||||
@ -187,6 +186,9 @@ function PlayerObject() {
|
||||
this.lastUpdate = 0;
|
||||
this.totalPlaytime = 0;
|
||||
this.playtimeSinceLastAug = 0;
|
||||
|
||||
//Script production since last Aug installation
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
};
|
||||
|
||||
PlayerObject.prototype.init = function() {
|
||||
@ -232,7 +234,6 @@ PlayerObject.prototype.prestigeAugmentation = function() {
|
||||
this.companyName = "";
|
||||
this.companyPosition = "";
|
||||
|
||||
this.discoveredServers = [];
|
||||
this.purchasedServers = [];
|
||||
|
||||
this.factions = [];
|
||||
@ -311,7 +312,6 @@ PlayerObject.prototype.prestigeSourceFile = function() {
|
||||
this.companyName = "";
|
||||
this.companyPosition = "";
|
||||
|
||||
this.discoveredServers = [];
|
||||
this.purchasedServers = [];
|
||||
|
||||
this.factions = [];
|
||||
@ -1363,6 +1363,7 @@ PlayerObject.prototype.takeClass = function(numCycles) {
|
||||
//through a Singularity Netscript function
|
||||
PlayerObject.prototype.finishClass = function(sing=false) {
|
||||
this.gainWorkExp();
|
||||
this.gainIntelligenceExp(CONSTANTS.IntelligenceClassBaseExpGain * Math.round(this.timeWorked / 1000));
|
||||
|
||||
if (this.workMoneyGained > 0) {
|
||||
throw new Error("ERR: Somehow gained money while taking class");
|
||||
@ -1513,6 +1514,14 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
|
||||
formatNumber(this.workAgiExpGained, 4) + " agility experience<br>" +
|
||||
formatNumber(this.workChaExpGained, 4) + " charisma experience");
|
||||
} else {
|
||||
//Exp halved on failure
|
||||
this.workHackExpGained /= 2;
|
||||
this.workStrExpGained /= 2;
|
||||
this.workDefExpGained /= 2;
|
||||
this.workDexExpGained /= 2;
|
||||
this.workAgiExpGained /= 2;
|
||||
this.workChaExpGained /= 2;
|
||||
|
||||
dialogBoxCreate("Crime failed! <br><br>" +
|
||||
"You gained:<br>"+
|
||||
formatNumber(this.workHackExpGained, 4) + " hacking experience <br>" +
|
||||
@ -1526,8 +1535,6 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
|
||||
this.gainWorkExp();
|
||||
}
|
||||
|
||||
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.isWorking = false;
|
||||
|
@ -248,6 +248,7 @@ let Engine = {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.activeScriptsContent.style.visibility = "visible";
|
||||
setActiveScriptsClickHandlers();
|
||||
updateActiveScriptsItems();
|
||||
Engine.currentPage = Engine.Page.ActiveScripts;
|
||||
document.getElementById("active-scripts-menu-link").classList.add("active");
|
||||
},
|
||||
@ -395,6 +396,7 @@ let Engine = {
|
||||
document.getElementById("mainmenu-container").style.visibility = "hidden";
|
||||
document.getElementById("character-overview-wrapper").style.visibility = "hidden";
|
||||
Engine.Display.missionContent.style.visibility = "visible";
|
||||
Engine.currentPage = Engine.Page.Mission;
|
||||
},
|
||||
|
||||
//Helper function that hides all content
|
||||
@ -477,6 +479,11 @@ let Engine = {
|
||||
if (Player.companyPosition != "") {
|
||||
companyPosition = Player.companyPosition.positionName;
|
||||
}
|
||||
|
||||
var bnText = "";
|
||||
if (Player.sourceFiles.length !== 0) {
|
||||
bnText = "<br>Current BitNode: " + Player.bitNodeN;
|
||||
}
|
||||
Engine.Display.characterInfo.innerHTML =
|
||||
('<b>General</b><br><br>' +
|
||||
'Current City: ' + Player.city + '<br><br>' +
|
||||
@ -528,7 +535,8 @@ let Engine = {
|
||||
'Hacknet Nodes owned: ' + Player.hacknetNodes.length + '<br>' +
|
||||
'Augmentations installed: ' + Player.augmentations.length + '<br>' +
|
||||
'Time played since last Augmentation: ' + convertTimeMsToTimeElapsedString(Player.playtimeSinceLastAug) + '<br>' +
|
||||
'Time played: ' + convertTimeMsToTimeElapsedString(Player.totalPlaytime) + '<br><br><br>').replace( / /g, " " );
|
||||
'Time played: ' + convertTimeMsToTimeElapsedString(Player.totalPlaytime) +
|
||||
bnText + '<br><br><br>').replace( / /g, " " );
|
||||
},
|
||||
|
||||
/* Display locations in the world*/
|
||||
|
Loading…
Reference in New Issue
Block a user