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> travelToCity() <singularityfunctions/travelToCity>
purchaseTor() <singularityfunctions/purchaseTor> purchaseTor() <singularityfunctions/purchaseTor>
purchaseProgram() <singularityfunctions/purchaseProgram> purchaseProgram() <singularityfunctions/purchaseProgram>
connect() <singularityfunctions/connect>
manualHack() <singularityfunctions/manualHack>
getStats() <singularityfunctions/getStats> getStats() <singularityfunctions/getStats>
getCharacterInformation() <singularityfunctions/getCharacterInformation> getCharacterInformation() <singularityfunctions/getCharacterInformation>
isBusy() <singularityfunctions/isBusy> 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) 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. Misc.
* New shortcut, Alt + b, brings you to bladeburner * New shortcut, Alt + b, brings you to bladeburner
* New shortcut, Alt + g, brings you to gang * New shortcut, Alt + g, brings you to gang

@ -176,7 +176,8 @@ export const RamCosts: IMap<any> = {
travelToCity: () => RamCostConstants.ScriptSingularityFn1RamCost, travelToCity: () => RamCostConstants.ScriptSingularityFn1RamCost,
purchaseTor: () => RamCostConstants.ScriptSingularityFn1RamCost, purchaseTor: () => RamCostConstants.ScriptSingularityFn1RamCost,
purchaseProgram: () => RamCostConstants.ScriptSingularityFn1RamCost, purchaseProgram: () => RamCostConstants.ScriptSingularityFn1RamCost,
executeCommand: () => RamCostConstants.ScriptSingularityFn1RamCost * 2, connect: () => RamCostConstants.ScriptSingularityFn1RamCost,
manualHack: () => RamCostConstants.ScriptSingularityFn1RamCost,
getStats: () => RamCostConstants.ScriptSingularityFn1RamCost / 4, getStats: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
getCharacterInformation: () => RamCostConstants.ScriptSingularityFn1RamCost / 4, getCharacterInformation: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
isBusy: () => 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 { return {
hacknet : { hacknet : {
numNodes : function() { numNodes : function() {
@ -671,74 +745,7 @@ function NetscriptFunctions(workerScript) {
}, },
hack : function(ip, { threads: requestedThreads, stock } = {}){ hack : function(ip, { threads: requestedThreads, stock } = {}){
updateDynamicRam("hack", getRamCost("hack")); updateDynamicRam("hack", getRamCost("hack"));
if (ip === undefined) { return hack(ip, false, {threads: requestedThreads, stock: stock});
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);
}
});
}, },
hackAnalyzeThreads : function(ip, hackAmount) { hackAnalyzeThreads : function(ip, hackAmount) {
updateDynamicRam("hackAnalyzeThreads", getRamCost("hackAnalyzeThreads")); 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.`); workerScript.log("purchaseProgram", `You have purchased the '${item.program}' program. The new program can be found on your home computer.`);
return true; return true;
}, },
executeCommand: function(command) { connect: function(hostname) {
updateDynamicRam("executeCommand", getRamCost("executeCommand")); if (!hostname) {
checkSingularityAccess("executeCommand", 1); throw makeRuntimeErrorMsg("connect", `Invalid hostname: '${hostname}'`);
Terminal.executeCommand(command); }
return new Promise(function (resolve, reject) {
(function wait(){ let target = getServer(hostname);
if (!Terminal.hackFlag && !Terminal.analyzeFlag) return resolve(); if (target == null) {
setTimeout(wait, 30); 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() { getStats: function() {
updateDynamicRam("getStats", getRamCost("getStats")); updateDynamicRam("getStats", getRamCost("getStats"));

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

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