executeCommand has been removed in favor of connect and manualHack, which is what people have been asking for.

This commit is contained in:
Olivier Gagnon 2021-03-23 21:30:15 -04:00
parent 1eddddd14f
commit 28584c8461
9 changed files with 191 additions and 106 deletions

@ -24,6 +24,8 @@ level 3, then you will be able to access all of the Singularity Functions.
travelToCity() <singularityfunctions/travelToCity>
purchaseTor() <singularityfunctions/purchaseTor>
purchaseProgram() <singularityfunctions/purchaseProgram>
connect() <singularityfunctions/connect>
manualHack() <singularityfunctions/manualHack>
getStats() <singularityfunctions/getStats>
getCharacterInformation() <singularityfunctions/getCharacterInformation>
isBusy() <singularityfunctions/isBusy>

@ -0,0 +1,20 @@
connect() Netscript Function
============================
.. js:function:: connect(hostname)
:RAM cost: 2 GB
:param string hostname: hostname of the server to connect.
:returns: ``true`` if the connection was a success.
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
This function will connect you to the specified server if it's directly connected to the current server.
You can also pass in 'home' to return to your home server from anywhere.
Examples:
.. code-block:: javascript
connect("joesguns");
connect("CSEC");

@ -1,21 +0,0 @@
executeCommand() Netscript Function
========================================
.. js:function:: executeCommand(command)
:RAM cost: 4 GB
:param string commands: The full string of the command.
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
This function writes the command to the terminal and executes it. This
can be used to perform manual hacks. Only one command can be sent at a time.
Examples:
.. code-block:: javascript
await ns.executeCommand('connect CSEC');
await ns.executeCommand('hack');
await ns.executeCommand('home');
// a manual hack will be performed and CSEC will invite you.

@ -0,0 +1,24 @@
manualHack() Netscript Function
===============================
.. js:function:: manualHack()
:RAM cost: 2 GB
:returns: The amount of money stolen if the hack is successful, and zero otherwise
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
This function will perform a manual hack on the server you are currently connected to.
This is typically required to join factions.
Examples:
.. code-block:: javascript
connect("CSEC");
manualHack();
.. warning::
For NS2 users:
This function is async.

@ -231,6 +231,10 @@ export let CONSTANTS: IMap<any> = {
v0.51.0 - 2021-XX-XX formulas (hydroflame)
-------
Netscript
* 'connect': a new singularity function that connects you to a server. (like the terminal command)
* 'manualHack': a new singularity function that performs a manual hack on the players current server.
Misc.
* New shortcut, Alt + b, brings you to bladeburner
* New shortcut, Alt + g, brings you to gang

@ -176,7 +176,8 @@ export const RamCosts: IMap<any> = {
travelToCity: () => RamCostConstants.ScriptSingularityFn1RamCost,
purchaseTor: () => RamCostConstants.ScriptSingularityFn1RamCost,
purchaseProgram: () => RamCostConstants.ScriptSingularityFn1RamCost,
executeCommand: () => RamCostConstants.ScriptSingularityFn1RamCost * 2,
connect: () => RamCostConstants.ScriptSingularityFn1RamCost,
manualHack: () => RamCostConstants.ScriptSingularityFn1RamCost,
getStats: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
getCharacterInformation: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
isBusy: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,

@ -555,6 +555,80 @@ function NetscriptFunctions(workerScript) {
}
}
const hack = function(ip, manual, { threads: requestedThreads, stock } = {}) {
if (ip === undefined) {
throw makeRuntimeErrorMsg("hack", "Takes 1 argument.");
}
const threads = resolveNetscriptRequestedThreads(workerScript, "hack", requestedThreads);
const server = getServer(ip);
if (server == null) {
throw makeRuntimeErrorMsg("hack", `Invalid IP/hostname: ${ip}.`);
}
// Calculate the hacking time
var hackingTime = calculateHackingTime(server); // This is in seconds
// No root access or skill level too low
const canHack = netscriptCanHack(server, Player);
if (!canHack.res) {
throw makeRuntimeErrorMsg('hack', canHack.msg);
}
workerScript.log("hack", `Executing ${ip} in ${hackingTime.toFixed(3)} seconds (t=${threads})`);
return netscriptDelay(hackingTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
var hackChance = calculateHackingChance(server);
var rand = Math.random();
var expGainedOnSuccess = calculateHackingExpGain(server) * threads;
var expGainedOnFailure = (expGainedOnSuccess / 4);
if (rand < hackChance) { // Success!
const percentHacked = calculatePercentMoneyHacked(server);
let maxThreadNeeded = Math.ceil(1/percentHacked*(server.moneyAvailable/server.moneyMax));
if (isNaN(maxThreadNeeded)) {
// Server has a 'max money' of 0 (probably). We'll set this to an arbitrarily large value
maxThreadNeeded = 1e6;
}
let moneyDrained = Math.floor(server.moneyAvailable * percentHacked) * threads;
// Over-the-top safety checks
if (moneyDrained <= 0) {
moneyDrained = 0;
expGainedOnSuccess = expGainedOnFailure;
}
if (moneyDrained > server.moneyAvailable) {moneyDrained = server.moneyAvailable;}
server.moneyAvailable -= moneyDrained;
if (server.moneyAvailable < 0) {server.moneyAvailable = 0;}
const moneyGained = moneyDrained * BitNodeMultipliers.ScriptHackMoneyGain;
Player.gainMoney(moneyGained);
workerScript.scriptRef.onlineMoneyMade += moneyGained;
Player.scriptProdSinceLastAug += moneyGained;
Player.recordMoneySource(moneyGained, "hacking");
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
Player.gainHackingExp(expGainedOnSuccess);
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
workerScript.log("hack", `Successfully hacked '${server.hostname}' for ${numeralWrapper.format(moneyGained, '$0.000a')} and ${numeralWrapper.format(expGainedOnSuccess, '0.000a')} exp (t=${threads})`);
server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
if (stock) {
influenceStockThroughServerHack(server, moneyGained);
}
if(manual) {
server.manuallyHacked = true;
}
return Promise.resolve(moneyGained);
} else {
// Player only gains 25% exp for failure?
Player.gainHackingExp(expGainedOnFailure);
workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
workerScript.log("hack", `Failed to hack '${server.hostname}'. Gained ${numeralWrapper.format(expGainedOnFailure, '0.000a')} exp (t=${threads})`);
return Promise.resolve(0);
}
});
}
return {
hacknet : {
numNodes : function() {
@ -671,74 +745,7 @@ function NetscriptFunctions(workerScript) {
},
hack : function(ip, { threads: requestedThreads, stock } = {}){
updateDynamicRam("hack", getRamCost("hack"));
if (ip === undefined) {
throw makeRuntimeErrorMsg("hack", "Takes 1 argument.");
}
const threads = resolveNetscriptRequestedThreads(workerScript, "hack", requestedThreads);
const server = getServer(ip);
if (server == null) {
throw makeRuntimeErrorMsg("hack", `Invalid IP/hostname: ${ip}.`);
}
// Calculate the hacking time
var hackingTime = calculateHackingTime(server); // This is in seconds
// No root access or skill level too low
const canHack = netscriptCanHack(server, Player);
if (!canHack.res) {
throw makeRuntimeErrorMsg('hack', canHack.msg);
}
workerScript.log("hack", `Executing ${ip} in ${hackingTime.toFixed(3)} seconds (t=${threads})`);
return netscriptDelay(hackingTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
var hackChance = calculateHackingChance(server);
var rand = Math.random();
var expGainedOnSuccess = calculateHackingExpGain(server) * threads;
var expGainedOnFailure = (expGainedOnSuccess / 4);
if (rand < hackChance) { // Success!
const percentHacked = calculatePercentMoneyHacked(server);
let maxThreadNeeded = Math.ceil(1/percentHacked*(server.moneyAvailable/server.moneyMax));
if (isNaN(maxThreadNeeded)) {
// Server has a 'max money' of 0 (probably). We'll set this to an arbitrarily large value
maxThreadNeeded = 1e6;
}
let moneyDrained = Math.floor(server.moneyAvailable * percentHacked) * threads;
// Over-the-top safety checks
if (moneyDrained <= 0) {
moneyDrained = 0;
expGainedOnSuccess = expGainedOnFailure;
}
if (moneyDrained > server.moneyAvailable) {moneyDrained = server.moneyAvailable;}
server.moneyAvailable -= moneyDrained;
if (server.moneyAvailable < 0) {server.moneyAvailable = 0;}
const moneyGained = moneyDrained * BitNodeMultipliers.ScriptHackMoneyGain;
Player.gainMoney(moneyGained);
workerScript.scriptRef.onlineMoneyMade += moneyGained;
Player.scriptProdSinceLastAug += moneyGained;
Player.recordMoneySource(moneyGained, "hacking");
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
Player.gainHackingExp(expGainedOnSuccess);
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
workerScript.log("hack", `Successfully hacked '${server.hostname}' for ${numeralWrapper.format(moneyGained, '$0.000a')} and ${numeralWrapper.format(expGainedOnSuccess, '0.000a')} exp (t=${threads})`);
server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
if (stock) {
influenceStockThroughServerHack(server, moneyGained);
}
return Promise.resolve(moneyGained);
} else {
// Player only gains 25% exp for failure?
Player.gainHackingExp(expGainedOnFailure);
workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
workerScript.log("hack", `Failed to hack '${server.hostname}'. Gained ${numeralWrapper.format(expGainedOnFailure, '0.000a')} exp (t=${threads})`);
return Promise.resolve(0);
}
});
return hack(ip, false, {threads: requestedThreads, stock: stock});
},
hackAnalyzeThreads : function(ip, hackAmount) {
updateDynamicRam("hackAnalyzeThreads", getRamCost("hackAnalyzeThreads"));
@ -2679,16 +2686,46 @@ function NetscriptFunctions(workerScript) {
workerScript.log("purchaseProgram", `You have purchased the '${item.program}' program. The new program can be found on your home computer.`);
return true;
},
executeCommand: function(command) {
updateDynamicRam("executeCommand", getRamCost("executeCommand"));
checkSingularityAccess("executeCommand", 1);
Terminal.executeCommand(command);
return new Promise(function (resolve, reject) {
(function wait(){
if (!Terminal.hackFlag && !Terminal.analyzeFlag) return resolve();
setTimeout(wait, 30);
})();
});
connect: function(hostname) {
if (!hostname) {
throw makeRuntimeErrorMsg("connect", `Invalid hostname: '${hostname}'`);
}
let target = getServer(hostname);
if (target == null) {
throw makeRuntimeErrorMsg("connect", `Invalid hostname: '${hostname}'`);
return;
}
if(hostname === 'home') {
Player.getCurrentServer().isConnectedTo = false;
Player.currentServer = Player.getHomeComputer().ip;
Player.getCurrentServer().isConnectedTo = true;
Terminal.currDir = "/";
Terminal.resetTerminalInput(true);
return true;
}
const server = Player.getCurrentServer();
for (let i = 0; i < server.serversOnNetwork.length; i++) {
const other = getServerOnNetwork(server, i);
if (other.ip == hostname || other.hostname == hostname) {
Player.getCurrentServer().isConnectedTo = false;
Player.currentServer = target.ip;
Player.getCurrentServer().isConnectedTo = true;
Terminal.currDir = "/";
Terminal.resetTerminalInput(true);
return true;
}
}
return false;
},
manualHack: function() {
updateDynamicRam("manualHack", getRamCost("manualHack"));
checkSingularityAccess("manualHack", 1);
const server = Player.getCurrentServer();
return hack(server.hostname, true);
},
getStats: function() {
updateDynamicRam("getStats", getRamCost("getStats"));

@ -163,7 +163,7 @@ function startNetscript1Script(workerScript) {
if (typeof entry === "function") {
//Async functions need to be wrapped. See JS-Interpreter documentation
if (name === "hack" || name === "grow" || name === "weaken" || name === "sleep" ||
name === "prompt") {
name === "prompt" || name === "manualHack") {
let tempWrapper = function() {
let fnArgs = [];

@ -113,6 +113,10 @@ function isNumber(str) {
return !isNaN(str) && !isNaN(parseFloat(str));
}
function getTerminalInput() {
return document.getElementById("terminal-input-text-box").value;
}
// Defines key commands in terminal
$(document).keydown(function(event) {
// Terminal
@ -122,7 +126,7 @@ $(document).keydown(function(event) {
if (event.keyCode === KEY.ENTER) {
event.preventDefault(); // Prevent newline from being entered in Script Editor
const command = terminalInput.value;
const command = getTerminalInput();
const dir = Terminal.currDir;
post(
"<span class='prompt'>[" +
@ -344,22 +348,36 @@ let Terminal = {
// Excludes the trailing forward slash
currDir: "/",
resetTerminalInput: function() {
resetTerminalInput: function(keepInput=false) {
let input = "";
if(keepInput) {
input = getTerminalInput();
}
const dir = Terminal.currDir;
if (FconfSettings.WRAP_INPUT) {
document.getElementById("terminal-input-td").innerHTML =
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
'<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
`<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\"/>`;
// Auto re-size the line element as it wraps
autosize(document.getElementById("terminal-input-text-box"));
} else {
document.getElementById("terminal-input-td").innerHTML =
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
`<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>`;
`<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\"/>`;
}
var hdr = document.getElementById("terminal-input-header");
const hdr = document.getElementById("terminal-input-header");
hdr.style.display = "inline";
const terminalInput = document.getElementById("terminal-input-text-box");
if (typeof terminalInput.selectionStart == "number") {
terminalInput.selectionStart = terminalInput.selectionEnd = terminalInput.value.length;
} else if (typeof terminalInput.createTextRange != "undefined") {
terminalInput.focus();
var range = el.createTextRange();
range.collapse(false);
range.select();
}
},
modifyInput: function(mod) {