mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
Finished BETA version of Missions. All other changes for v0.29.1
This commit is contained in:
parent
c84417607f
commit
22a5d3b3cc
@ -34,7 +34,6 @@
|
||||
background-color:blue;
|
||||
}
|
||||
|
||||
.hack-mission-player-node:hover,
|
||||
.hack-mission-player-node-active {
|
||||
border: 2px solid white;
|
||||
color: #6666ff;
|
||||
|
3466
dist/bundle.js
vendored
3466
dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -6,6 +6,7 @@ import {getServer} from "./Server.js";
|
||||
import {dialogBoxCreate} from "../utils/DialogBox.js";
|
||||
import {printArray} from "../utils/HelperFunctions.js";
|
||||
import {logBoxCreate} from "../utils/LogBox.js";
|
||||
import numeral from "../utils/numeral.min.js";
|
||||
import {formatNumber} from "../utils/StringHelperFunctions.js";
|
||||
|
||||
|
||||
@ -183,10 +184,10 @@ function updateActiveScriptsItems() {
|
||||
total += updateActiveScriptsItemContent(workerScripts[i]);
|
||||
}
|
||||
document.getElementById("active-scripts-total-prod").innerHTML =
|
||||
"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)";
|
||||
"Total online production of Active Scripts: " + numeral(total).format('$0.000a') + " / sec<br>" +
|
||||
"Total online production since last Aug installation: " +
|
||||
numeral(Player.scriptProdSinceLastAug).format('$0.000a') + " (" +
|
||||
numeral(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000)).format('$0.000a') + " / sec)";
|
||||
return total;
|
||||
}
|
||||
|
||||
|
@ -124,31 +124,30 @@ let CONSTANTS = {
|
||||
|
||||
//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
|
||||
HackingMissionRepToRewardConversion: 12, //Faction rep divided byt his to get mission rep reward
|
||||
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" +
|
||||
"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 " +
|
||||
"Attack - Targets an enemy Node and lowers its HP. The effectiveness is determined by the owner'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 " +
|
||||
"Scan - Targets an enemy Node and lowers its Defense. The effectiveness is determined by the owner's Attack, 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 " +
|
||||
"Weaken - Targets an enemy Node and lowers its Attack. The effectiveness is determined by the owner's Attack, 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>" +
|
||||
"Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.<br>" +
|
||||
"Overflow - Raises the Node's Attack but lowers its Defense. The effectiveness is determined by your hacking level.<br><br>" +
|
||||
"Note that when determining the effectiveness of the above actions, the TOTAL Attack or Defense of the team is used, not just the " +
|
||||
"Attack/Defense of the individual Node that is performing the action.<br><br." +
|
||||
"To capture a Node, you must lower its HP down to 0.<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>" +
|
||||
"CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action<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>" +
|
||||
@ -157,10 +156,16 @@ let CONSTANTS = {
|
||||
"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>" +
|
||||
"To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Only " +
|
||||
"one Node can be selected at a time, and it will be denoted with a white highlight. After selecting the Node, " +
|
||||
"select its action using the Action Buttons near the top of the screen. Every action also has a corresponding keyboard " +
|
||||
"shortcut that can be used as well.<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",
|
||||
"can target, since they are the only ones that can perform actions. To remove a target, you can simply click on the line that represents " +
|
||||
"the connection between one of your Nodes and its target. Alternatively, you can select the 'source' Node and click the 'Drop Connection' button, " +
|
||||
"or press 'd',",
|
||||
|
||||
|
||||
//Gang constants
|
||||
@ -418,6 +423,9 @@ let CONSTANTS = {
|
||||
"args.length<br><br>" +
|
||||
"Note that none of the other functions that typically work with arrays, such as remove(), insert(), clear(), etc., will work on the " +
|
||||
"args array.<br><br>" +
|
||||
"<u><h1>Javascript Modules</h1></u><br>" +
|
||||
"Netscript supports the following Javascript Modules:<br><br>" +
|
||||
"Math<br>Date (static functions only)<br><br>" +
|
||||
"<u><h1> Functions </h1></u><br>" +
|
||||
"You can NOT define you own functions in Netscript (yet), but there are several built in functions that " +
|
||||
"you may use: <br><br> " +
|
||||
@ -649,8 +657,9 @@ let CONSTANTS = {
|
||||
"on the server specified by the hostname/ip. The argument must be a string with the hostname/ip of the target server.<br><br>" +
|
||||
"<i>getScriptIncome([scriptname], [hostname/ip], [args...])</i><br>" +
|
||||
"Returns the amount of income the specified script generates while online (when the game is open, does not apply for " +
|
||||
"offline income). This function can also return the total income of all of your active scripts by running the function " +
|
||||
"with no arguments.<br><br>" +
|
||||
"offline income). This function can also be called with no arguments. If called with no arguments, then this function " +
|
||||
"will return an array of two values. The first value is the total income ($/sec) of all of your active scripts (currently running). " +
|
||||
"The second value is the total income ($/sec) from scripts since you last installed Augmentations (or destroyed a BitNode).<br><br>" +
|
||||
"Remember that a script is uniquely identified by both its name and its arguments. So for example if you ran a script " +
|
||||
"with the arguments 'foodnstuff' and '5' then in order to use this function to get that script's income you must " +
|
||||
"specify those arguments in this function call.<br><br>" +
|
||||
@ -669,6 +678,8 @@ let CONSTANTS = {
|
||||
"The second argument must be a string with the hostname/IP of the target server. If the first argument is specified " +
|
||||
"then the second argument must be specified as well. Any additional arguments passed to the function will specify " +
|
||||
"the arguments passed into the target script.<br><br>" +
|
||||
"<i>getTimeSinceLastAug()</i><br>" +
|
||||
"Returns the amount of time in milliseconds that have passed since you last installed Augmentations (or destroyed a BitNode).<br><br>" +
|
||||
"<u><h1>Hacknet Nodes API</h1></u><br>" +
|
||||
"Netscript provides the following API for accessing and upgrading your Hacknet Nodes through scripts. This API does NOT work offline.<br><br>" +
|
||||
"<i>hacknetnodes</i><br> A special variable. This is an array that maps to the Player's Hacknet Nodes. The Hacknet Nodes are accessed through " +
|
||||
@ -998,28 +1009,24 @@ let CONSTANTS = {
|
||||
|
||||
LatestUpdate:
|
||||
"v0.29.1<br>" +
|
||||
"-New gameplay feature that is currently in BETA: Hacking Missions. Hacking Missions is an active gameplay mechanic (its a minigame) " +
|
||||
"that is meant to be used to earn faction reputation. However, since this is currently in beta, hacking missions will NOT grant reputation " +
|
||||
"for the time being, since the feature likely has many bugs, balance problems, and other issues. If you have any feedback " +
|
||||
"regarding the new feature, feel free to let me know<br>" +
|
||||
"-CHANGED THE RETURN VALUE OF getScriptIncome() WHEN RAN WITH NO ARGUMENTS. It will now return an array of " +
|
||||
"two values rather than a single value. This may break your scripts, so make sure to update them!<br>" +
|
||||
"-Added continue statement for for/while loops<br>" +
|
||||
"-Added getServerMinSecurityLevel() Netscript function<br>" +
|
||||
"-Added getServerMinSecurityLevel(), getPurchasedServers(), and getTimeSinceLastAug() Netscript functions<br>" +
|
||||
"-Netscript scp() function can now take an array as the first argument, and will try to copy " +
|
||||
"every file specified in the array (it will just call scp() normally for every element in the array). " +
|
||||
"If an array is passed in, then the scp() function returns true if at least one element from the array is successfully copied<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>" +
|
||||
"-Added getIp(), getIntelligence(), getHackingMultipliers(), and getBitNodeMultipliers() Netscript functions (requires Source-File 5)<br>" +
|
||||
"-Updated scan() Netscript function so that you can choose to have it print IPs rather than hostnames<br>" +
|
||||
"-Refactored scp() Netscript function so that it takes an optional 'source server' argument<br>" +
|
||||
"-For Infiltration, decreased the percentage by which the security level increases by " +
|
||||
"about 10% for every location<br>" +
|
||||
"-Using :w in the script editor's Vim keybinding mode should now save and quit to Terminal<br>" +
|
||||
"-Some minor optimizations that should reduce the size of the save file<br>" +
|
||||
"-scan-analyze Terminal command will no longer show your purchased servers, unless you pass a '-a' flag into the command<br>" +
|
||||
"-After installing the Red Pill augmentation from Daedalus, the message telling you to find 'The-Cave' " +
|
||||
"will now repeatedly pop up regardless of whether or not you have messages suppressed<br>" +
|
||||
"-Various bugfixes",
|
||||
|
||||
"-The forced repeated 'Find The-Cave' message after installing The Red Pill Augmentation now only happens " +
|
||||
"if you've never destroyed a BitNode before, and will only popup every 15 minutes. If you have already destroyed a BitNode, " +
|
||||
"the message will not pop up if you have messages suppressed (if you don't have messages suppressed it WILL still repeatedly popup)<br>" +
|
||||
"-fileExists() function now works on literature files<br><br>",
|
||||
}
|
||||
|
||||
export {CONSTANTS};
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {Augmentations, Augmentation,
|
||||
AugmentationNames} from "./Augmentations.js";
|
||||
import {Programs} from "./CreateProgram.js";
|
||||
import {inMission} from "./Missions.js";
|
||||
import {Player} from "./Player.js";
|
||||
import {redPillFlag} from "./RedPill.js";
|
||||
import {GetServerByHostname} from "./Server.js";
|
||||
import {Settings} from "./Settings.js";
|
||||
import {dialogBoxCreate, dialogBoxOpened} from "../utils/DialogBox.js";
|
||||
@ -75,10 +77,15 @@ function checkForMessagesToSend() {
|
||||
redpillOwned = true;
|
||||
}
|
||||
|
||||
if (redpill && redpillOwned && Player.sourceFiles.length === 0) {
|
||||
if (redpill && redpillOwned && Player.sourceFiles.length === 0 && !redPillFlag && !inMission) {
|
||||
if (!dialogBoxOpened) {
|
||||
sendMessage(redpill, true);
|
||||
}
|
||||
} else if (redpill && redpillOwned) {
|
||||
//If player has already destroyed a BitNode, message is not forced
|
||||
if (!redPillFlag && !inMission && !dialogBoxOpened) {
|
||||
sendMessage(redpill);
|
||||
}
|
||||
} else if (jumper0 && !jumper0.recvd && Player.hacking_skill >= 25) {
|
||||
sendMessage(jumper0);
|
||||
Player.getHomeComputer().programs.push(Programs.Flight);
|
||||
@ -96,8 +103,6 @@ function checkForMessagesToSend() {
|
||||
sendMessage(jumper4);
|
||||
} else if (bitrunnersTest && !bitrunnersTest.recvd && Player.hacking_skill >= 500) {
|
||||
sendMessage(bitrunnersTest);
|
||||
} else if (redpill && redpillOwned) {
|
||||
sendMessage(redpill);
|
||||
}
|
||||
}
|
||||
|
||||
|
197
src/Missions.js
197
src/Missions.js
@ -156,15 +156,17 @@ function HackingMission(rep, fac) {
|
||||
this.faction = fac;
|
||||
|
||||
this.started = false;
|
||||
this.time = 120000; //2 minutes, milliseconds
|
||||
this.time = 180000; //2 minutes, milliseconds
|
||||
|
||||
this.playerCores = [];
|
||||
this.playerNodes = []; //Non-core nodes
|
||||
this.playerAtk = 0;
|
||||
this.playerDef = 0;
|
||||
|
||||
this.enemyCores = [];
|
||||
this.enemyDatabases = [];
|
||||
this.enemyNodes = []; //Non-core nodes
|
||||
this.enemyAtk = 0;
|
||||
this.enemyDef = 0;
|
||||
|
||||
this.miscNodes = [];
|
||||
@ -190,7 +192,7 @@ function HackingMission(rep, fac) {
|
||||
//difficulty capped at 16
|
||||
this.difficulty = Math.min(16, Math.round(rep / CONSTANTS.HackingMissionRepToDiffConversion) + 1);
|
||||
console.log("difficulty: " + this.difficulty);
|
||||
this.reward = 200 + (rep / CONSTANTS.HackingMissionRepToRewardConversion);
|
||||
this.reward = 250 + (rep / CONSTANTS.HackingMissionRepToRewardConversion);
|
||||
}
|
||||
|
||||
HackingMission.prototype.init = function() {
|
||||
@ -213,7 +215,7 @@ HackingMission.prototype.init = function() {
|
||||
|
||||
//Randomly generate enemy nodes (CPU and Firewall) based on difficulty
|
||||
var numNodes = getRandomInt(this.difficulty, this.difficulty + 1);
|
||||
var numFirewalls = getRandomInt(this.difficulty, this.difficulty + 2);
|
||||
var numFirewalls = getRandomInt(this.difficulty, this.difficulty + 1);
|
||||
var numDatabases = getRandomInt(this.difficulty, this.difficulty + 1);
|
||||
var totalNodes = numNodes + numFirewalls + numDatabases;
|
||||
var xlimit = 7 - Math.floor(totalNodes / 8);
|
||||
@ -254,6 +256,7 @@ HackingMission.prototype.init = function() {
|
||||
this.enemyDatabases.push(node);
|
||||
}
|
||||
this.calculateDefenses();
|
||||
this.calculateAttacks();
|
||||
this.createMap();
|
||||
}
|
||||
|
||||
@ -297,11 +300,23 @@ HackingMission.prototype.createPageDom = function() {
|
||||
startBtn.style.display = "inline-block";
|
||||
startBtn.addEventListener("click", ()=>{
|
||||
this.start();
|
||||
return false;
|
||||
});
|
||||
|
||||
var forfeitMission = document.createElement("a");
|
||||
forfeitMission.innerHTML = "Forfeit Mission (Exit)";
|
||||
forfeitMission.classList.add("a-link-button");
|
||||
forfeitMission.classList.add("hack-mission-header-element");
|
||||
forfeitMission.style.display = "inline-block";
|
||||
forfeitMission.addEventListener("click", ()=> {
|
||||
this.finishMission(false);
|
||||
return false;
|
||||
});
|
||||
|
||||
var timer = document.createElement("p");
|
||||
timer.setAttribute("id", "hacking-mission-timer");
|
||||
timer.style.display = "inline-block";
|
||||
timer.style.margin = "6px";
|
||||
|
||||
//Create Action Buttons (Attack/Scan/Weaken/ etc...)
|
||||
var actionsContainer = document.createElement("span");
|
||||
@ -353,18 +368,18 @@ HackingMission.prototype.createPageDom = function() {
|
||||
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);
|
||||
var playerStats = document.createElement("p");
|
||||
var enemyStats = document.createElement("p");
|
||||
playerStats.style.display = "inline-block";
|
||||
enemyStats.style.display = "inline-block";
|
||||
playerStats.style.color = "#00ccff";
|
||||
enemyStats.style.color = "red";
|
||||
playerStats.style.margin = "4px";
|
||||
enemyStats.style.margin = "4px";
|
||||
playerStats.setAttribute("id", "hacking-mission-player-stats");
|
||||
enemyStats.setAttribute("id", "hacking-mission-enemy-stats");
|
||||
actionsContainer.appendChild(playerStats);
|
||||
actionsContainer.appendChild(enemyStats);
|
||||
|
||||
//Set Action Button event listeners
|
||||
this.actionButtons[0].addEventListener("click", ()=>{
|
||||
@ -434,6 +449,7 @@ HackingMission.prototype.createPageDom = function() {
|
||||
container.appendChild(inGameGuideBtn);
|
||||
container.appendChild(wikiGuideBtn);
|
||||
container.appendChild(startBtn);
|
||||
container.appendChild(forfeitMission);
|
||||
container.appendChild(timer);
|
||||
container.appendChild(actionsContainer);
|
||||
container.appendChild(timeDisplay);
|
||||
@ -485,7 +501,34 @@ HackingMission.prototype.setActionButton = function(i, active=true) {
|
||||
|
||||
}
|
||||
|
||||
//Should only be used at the start
|
||||
HackingMission.prototype.calculateAttacks = function() {
|
||||
var total = 0;
|
||||
for (var i = 0; i < this.playerCores.length; ++i) {
|
||||
total += this.playerCores[i].atk;
|
||||
}
|
||||
for (var i = 0; i < this.playerNodes.length; ++i) {
|
||||
total += this.playerNodes[i].atk;
|
||||
}
|
||||
this.playerAtk = total;
|
||||
document.getElementById("hacking-mission-player-stats").innerHTML =
|
||||
"Player Attack: " + formatNumber(this.playerAtk, 1) + "<br>" +
|
||||
"Player Defense: " + formatNumber(this.playerDef, 1);
|
||||
total = 0;
|
||||
for (var i = 0; i < this.enemyCores.length; ++i) {
|
||||
total += this.enemyCores[i].atk;
|
||||
}
|
||||
for (var i = 0; i < this.enemyDatabases.length; ++i) {
|
||||
total += this.enemyDatabases[i].atk;
|
||||
}
|
||||
for (var i = 0; i < this.enemyNodes.length; ++i) {
|
||||
total += this.enemyNodes[i].atk;
|
||||
}
|
||||
this.enemyAtk = total;
|
||||
document.getElementById("hacking-mission-enemy-stats").innerHTML =
|
||||
"Enemy Attack: " + formatNumber(this.enemyAtk, 1) + "<br>" +
|
||||
"Enemy Defense: " + formatNumber(this.enemyDef, 1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.calculateDefenses = function() {
|
||||
var total = 0;
|
||||
for (var i = 0; i < this.playerCores.length; ++i) {
|
||||
@ -495,7 +538,8 @@ HackingMission.prototype.calculateDefenses = function() {
|
||||
total += this.playerNodes[i].def;
|
||||
}
|
||||
this.playerDef = total;
|
||||
document.getElementById("hacking-mission-player-def").innerText =
|
||||
document.getElementById("hacking-mission-player-stats").innerHTML =
|
||||
"Player Attack: " + formatNumber(this.playerAtk, 1) + "<br>" +
|
||||
"Player Defense: " + formatNumber(this.playerDef, 1);
|
||||
total = 0;
|
||||
for (var i = 0; i < this.enemyCores.length; ++i) {
|
||||
@ -508,7 +552,8 @@ HackingMission.prototype.calculateDefenses = function() {
|
||||
total += this.enemyNodes[i].def;
|
||||
}
|
||||
this.enemyDef = total;
|
||||
document.getElementById("hacking-mission-enemy-def").innerText =
|
||||
document.getElementById("hacking-mission-enemy-stats").innerHTML =
|
||||
"Enemy Attack: " + formatNumber(this.enemyAtk, 1) + "<br>" +
|
||||
"Enemy Defense: " + formatNumber(this.enemyDef, 1);
|
||||
}
|
||||
|
||||
@ -563,16 +608,16 @@ HackingMission.prototype.createMap = function() {
|
||||
case 0: //Spam
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: randMult * getRandomInt(30, 40),
|
||||
hp: randMult * getRandomInt(70, 90)
|
||||
def: randMult * getRandomInt(35, 55),
|
||||
hp: randMult * getRandomInt(125, 150)
|
||||
}
|
||||
node = new Node(NodeTypes.Spam, stats);
|
||||
break;
|
||||
case 1: //Transfer
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: randMult * getRandomInt(50, 70),
|
||||
hp: randMult * getRandomInt(80, 95)
|
||||
def: randMult * getRandomInt(45, 65),
|
||||
hp: randMult * getRandomInt(150, 175)
|
||||
}
|
||||
node = new Node(NodeTypes.Transfer, stats);
|
||||
break;
|
||||
@ -580,8 +625,8 @@ HackingMission.prototype.createMap = function() {
|
||||
default:
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: randMult * getRandomInt(90, 105),
|
||||
hp: randMult * getRandomInt(130, 150)
|
||||
def: randMult * getRandomInt(60, 80),
|
||||
hp: randMult * getRandomInt(200, 250)
|
||||
}
|
||||
node = new Node(NodeTypes.Shield, stats);
|
||||
break;
|
||||
@ -779,11 +824,8 @@ 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;
|
||||
});
|
||||
startBtn.classList.remove("a-link-button");
|
||||
startBtn.classList.add("a-link-button-inactive");
|
||||
}
|
||||
|
||||
HackingMission.prototype.initJsPlumb = function() {
|
||||
@ -806,8 +848,8 @@ HackingMission.prototype.initJsPlumb = function() {
|
||||
instance.makeSource(this.playerCores[i].el, {
|
||||
deleteEndpointsOnEmpty:true,
|
||||
maxConnections:1,
|
||||
anchor:"Center",
|
||||
connector:"Straight"
|
||||
anchor:"Continuous",
|
||||
connector:"Flowchart"
|
||||
});
|
||||
}
|
||||
|
||||
@ -815,29 +857,29 @@ HackingMission.prototype.initJsPlumb = function() {
|
||||
for (var i = 0; i < this.enemyCores.length; ++i) {
|
||||
instance.makeTarget(this.enemyCores[i].el, {
|
||||
maxConnections:-1,
|
||||
anchor:"Center",
|
||||
connector:"Straight"
|
||||
anchor:"Continuous",
|
||||
connector:"Flowchart"
|
||||
});
|
||||
}
|
||||
for (var i = 0; i < this.enemyDatabases.length; ++i) {
|
||||
instance.makeTarget(this.enemyDatabases[i].el, {
|
||||
maxConnections:-1,
|
||||
anchor:"Center",
|
||||
connector:["Straight"]
|
||||
anchor:"Continuous",
|
||||
connector:["Flowchart"]
|
||||
});
|
||||
}
|
||||
for (var i = 0; i < this.enemyNodes.length; ++i) {
|
||||
instance.makeTarget(this.enemyNodes[i].el, {
|
||||
maxConnections:-1,
|
||||
anchor:"Center",
|
||||
connector:"Straight"
|
||||
anchor:"Continuous",
|
||||
connector:"Flowchart"
|
||||
});
|
||||
}
|
||||
for (var i = 0; i < this.miscNodes.length; ++i) {
|
||||
instance.makeTarget(this.miscNodes[i].el, {
|
||||
maxConnections:-1,
|
||||
anchor:"Center",
|
||||
connector:"Straight"
|
||||
anchor:"Continuous",
|
||||
connector:"Flowchart"
|
||||
});
|
||||
}
|
||||
|
||||
@ -888,45 +930,60 @@ HackingMission.prototype.dropAllConnectionsToNode = function(node) {
|
||||
}
|
||||
}
|
||||
|
||||
var storedCycles = 0;
|
||||
HackingMission.prototype.process = function(numCycles=1) {
|
||||
if (!this.started) {return;}
|
||||
storedCycles += numCycles;
|
||||
if (storedCycles < 3) {return;} //Only process every 2 cycles minimum
|
||||
|
||||
var res = false;
|
||||
//Process actions of all player nodes
|
||||
this.playerCores.forEach((node)=>{
|
||||
res |= this.processNode(node, numCycles);
|
||||
res |= this.processNode(node, storedCycles);
|
||||
});
|
||||
|
||||
this.playerNodes.forEach((node)=>{
|
||||
if (node.type === NodeTypes.Transfer) {
|
||||
res |= this.processNode(node, numCycles);
|
||||
res |= this.processNode(node, storedCycles);
|
||||
}
|
||||
});
|
||||
|
||||
//Process actions of all enemy nodes
|
||||
this.enemyCores.forEach((node)=>{
|
||||
res |= this.processNode(node, numCycles);
|
||||
res |= this.processNode(node, storedCycles);
|
||||
});
|
||||
|
||||
this.enemyNodes.forEach((node)=>{
|
||||
if (node.type === NodeTypes.Transfer) {
|
||||
res |= this.processNode(node, numCycles);
|
||||
res |= this.processNode(node, storedCycles);
|
||||
}
|
||||
});
|
||||
|
||||
if (res) {this.calculateDefenses();}
|
||||
if (res) {
|
||||
this.calculateAttacks();
|
||||
this.calculateDefenses();
|
||||
}
|
||||
|
||||
if (this.enemyDatabases.length === 0) {
|
||||
this.finishMission(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//Defense of every misc Node increase by 1 per second
|
||||
this.miscNodes.forEach((node)=>{
|
||||
node.def += (0.1 * storedCycles);
|
||||
this.updateNodeDomElement(node);
|
||||
});
|
||||
|
||||
//Update timer and check if player lost
|
||||
this.time -= (numCycles * Engine._idleSpeed);
|
||||
this.time -= (storedCycles * Engine._idleSpeed);
|
||||
if (this.time <= 0) {
|
||||
this.finishMission(false);
|
||||
return;
|
||||
}
|
||||
this.updateTimer();
|
||||
|
||||
storedCycles = 0;
|
||||
}
|
||||
|
||||
//Returns a bool representing whether defenses need to be re-calculated
|
||||
@ -935,48 +992,52 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var targetNode = null, def;
|
||||
var targetNode = null, def, atk;
|
||||
if (nodeObj.conn) {
|
||||
targetNode = this.getNodeFromElement(nodeObj.conn.target);
|
||||
if (targetNode.plyrCtrl) {
|
||||
def = this.playerDef;
|
||||
atk = this.enemyAtk;
|
||||
} else if (targetNode.enmyCtrl) {
|
||||
def = this.enemyDef;
|
||||
atk = this.playerAtk;
|
||||
} else { //Misc Node
|
||||
def = targetNode.def;
|
||||
nodeObj.plyrCtrl ? atk = this.playerAtk : atk = this.enemyAtk;
|
||||
}
|
||||
}
|
||||
|
||||
//Calculations are per second, so divide everything by 5
|
||||
var calcDefenses = false;
|
||||
var calcStats = false;
|
||||
switch(nodeObj.action) {
|
||||
case NodeActions.Attack:
|
||||
if (nodeObj.conn === null) {break;}
|
||||
var dmg = this.calculateAttackDamage(nodeObj.atk, def, Player.hacking_skill);
|
||||
var dmg = this.calculateAttackDamage(atk, def, Player.hacking_skill);
|
||||
targetNode.hp -= (dmg/5 * numCycles);
|
||||
break;
|
||||
case NodeActions.Scan:
|
||||
if (nodeObj.conn === null) {break;}
|
||||
var eff = this.calculateScanEffect(nodeObj.atk, def, Player.hacking_skill);
|
||||
var eff = this.calculateScanEffect(atk, def, Player.hacking_skill);
|
||||
targetNode.def -= (eff/5 * numCycles);
|
||||
calcDefenses = true;
|
||||
calcStats = true;
|
||||
break;
|
||||
case NodeActions.Weaken:
|
||||
if (nodeObj.conn === null) {break;}
|
||||
var eff = this.calculateWeakenEffect(nodeObj.atk, def, Player.hacking_skill);
|
||||
var eff = this.calculateWeakenEffect(atk, def, Player.hacking_skill);
|
||||
targetNode.atk -= (eff/5 * numCycles);
|
||||
calcStats = true;
|
||||
break;
|
||||
case NodeActions.Fortify:
|
||||
var eff = this.calculateFortifyEffect(Player.hacking_skill);
|
||||
nodeObj.def += (eff/5 * numCycles);
|
||||
calcDefenses = true;
|
||||
calcStats = true;
|
||||
break;
|
||||
case NodeActions.Overflow:
|
||||
var eff = this.calculateOverflowEffect(Player.hacking_skill);
|
||||
if (nodeObj.def < eff) {break;}
|
||||
nodeObj.def -= (eff/5 * numCycles);
|
||||
nodeObj.atk += (eff/5 * numCycles);
|
||||
calcDefenses = true;
|
||||
calcStats = true;
|
||||
break;
|
||||
default:
|
||||
console.log("ERR: Invalid Node Action: " + nodeObj.action);
|
||||
@ -1014,20 +1075,20 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
this.jsplumbinstance.makeSource(targetNode.el, {
|
||||
deleteEndpointsOnEmpty:true,
|
||||
maxConnections:1,
|
||||
anchor:"Center",
|
||||
connector:"Straight"
|
||||
anchor:"Continuous",
|
||||
connector:"Flowchart"
|
||||
});
|
||||
} else {
|
||||
targetNode.setControlledByEnemy();
|
||||
this.jsplumbinstance.unmakeSource(targetNode.el);
|
||||
this.jsplumbinstance.makeTarget(targetNode.el, {
|
||||
maxConnections:-1,
|
||||
anchor:"Center",
|
||||
connector:["Straight"]
|
||||
anchor:"Continuous",
|
||||
connector:["Flowchart"]
|
||||
});
|
||||
}
|
||||
|
||||
calcDefenses = true;
|
||||
calcStats = true;
|
||||
|
||||
//Helper function to swap nodes between the respective enemyNodes/playerNodes arrays
|
||||
function swapNodes(orig, dest, targetNode) {
|
||||
@ -1105,24 +1166,24 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
}
|
||||
this.updateNodeDomElement(nodeObj);
|
||||
if (targetNode) {this.updateNodeDomElement(targetNode);}
|
||||
return calcDefenses;
|
||||
return calcStats;
|
||||
}
|
||||
|
||||
var hackEffWeightSelf = 100; //Weight for Node actions on self
|
||||
var hackEffWeightTarget = 15; //Weight for Node Actions against Target
|
||||
var hackEffWeightAttack = 100; //Weight for Attack action
|
||||
var hackEffWeightSelf = 150; //Weight for Node actions on self
|
||||
var hackEffWeightTarget = 25; //Weight for Node Actions against Target
|
||||
var hackEffWeightAttack = 110; //Weight for Attack action
|
||||
|
||||
//Returns damage per cycle based on stats
|
||||
HackingMission.prototype.calculateAttackDamage = function(atk, def, hacking = 0) {
|
||||
return Math.max(atk + (hacking / hackEffWeightAttack) - def, 0.1);
|
||||
return Math.max(atk + (hacking / hackEffWeightAttack) - def, 1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.calculateScanEffect = function(atk, def, hacking=0) {
|
||||
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 0.1);
|
||||
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.calculateWeakenEffect = function(atk, def, hacking=0) {
|
||||
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 0.1);
|
||||
return Math.max((atk/2) + hacking / hackEffWeightTarget - def, 1);
|
||||
}
|
||||
|
||||
HackingMission.prototype.calculateFortifyEffect = function(hacking=0) {
|
||||
@ -1151,9 +1212,11 @@ HackingMission.prototype.finishMission = function(win) {
|
||||
currMission = null;
|
||||
|
||||
if (win) {
|
||||
dialogBoxCreate("Mission won!");
|
||||
dialogBoxCreate("Mission won! This feature is currently in " +
|
||||
"beta so you did not earn anything, but normally you would have won " +
|
||||
this.reward + " reputation with " + this.faction.name);
|
||||
} else {
|
||||
dialogBoxCreate("Mission lost!");
|
||||
dialogBoxCreate("Mission lost/forfeited!");
|
||||
}
|
||||
|
||||
//Clear mission container
|
||||
|
@ -469,6 +469,16 @@ function NetscriptFunctions(workerScript) {
|
||||
if (arguments.length !== 2 && arguments.length !== 3) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Error: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
|
||||
}
|
||||
if (scriptname && scriptname.constructor === Array) {
|
||||
//Recursively call scp on all elements of array
|
||||
var res = false;
|
||||
scriptname.forEach(function(script) {
|
||||
if (NetscriptFunctions(workerScript).scp(script, ip1, ip2)) {
|
||||
res = true;
|
||||
};
|
||||
});
|
||||
return res;
|
||||
}
|
||||
if (!scriptname.endsWith(".lit") && !scriptname.endsWith(".script")) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Error: scp() only works for .script and .lit files");
|
||||
}
|
||||
@ -1124,7 +1134,10 @@ function NetscriptFunctions(workerScript) {
|
||||
getScriptIncome : function(scriptname, ip) {
|
||||
if (arguments.length === 0) {
|
||||
//Get total script income
|
||||
return updateActiveScriptsItems();
|
||||
var res = [];
|
||||
res.push(updateActiveScriptsItems());
|
||||
res.push(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000));
|
||||
return res;
|
||||
} else {
|
||||
//Get income for a particular script
|
||||
var server = getServer(ip);
|
||||
@ -1170,6 +1183,9 @@ function NetscriptFunctions(workerScript) {
|
||||
return runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime;
|
||||
}
|
||||
},
|
||||
getTimeSinceLastAug : function() {
|
||||
return Player.playtimeSinceLastAug;
|
||||
},
|
||||
|
||||
/* Singularity Functions */
|
||||
universityCourse(universityName, className) {
|
||||
|
@ -275,6 +275,7 @@ PlayerObject.prototype.prestigeAugmentation = function() {
|
||||
this.lastUpdate = new Date().getTime();
|
||||
|
||||
this.playtimeSinceLastAug = 0;
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
|
||||
this.hacknetNodes.length = 0;
|
||||
this.totalHacknetNodeProduction = 0;
|
||||
@ -365,6 +366,7 @@ PlayerObject.prototype.prestigeSourceFile = function() {
|
||||
this.hasTixApiAccess = false;
|
||||
|
||||
this.playtimeSinceLastAug = 0;
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
}
|
||||
|
||||
PlayerObject.prototype.getCurrentServer = function() {
|
||||
|
@ -840,6 +840,7 @@ let Engine = {
|
||||
Player.gang.process(numCycles);
|
||||
}
|
||||
|
||||
//Mission
|
||||
if (inMission && currMission) {
|
||||
currMission.process(numCycles);
|
||||
}
|
||||
@ -967,7 +968,7 @@ let Engine = {
|
||||
if (Engine.Counters.messages <= 0) {
|
||||
checkForMessagesToSend();
|
||||
if (Augmentations[AugmentationNames.TheRedPill].owned) {
|
||||
Engine.Counters.messages = 600; //2 minutes for Red pill message
|
||||
Engine.Counters.messages = 4500; //15 minutes for Red pill message
|
||||
} else {
|
||||
Engine.Counters.messages = 150;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user