This commit is contained in:
Olivier Gagnon 2021-08-19 16:37:59 -04:00
parent ee3530d9b9
commit df457a0c6e
18 changed files with 194 additions and 105 deletions

File diff suppressed because one or more lines are too long

26
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -3,6 +3,32 @@
Changelog
=========
v0.52.5 - 2021-07-19 CPU cores are useful!? (hydroflame)
-------------------------------------------
** Terminal **
* When executing 'run SCRIPT' any script can now add '--tail' to
automatically bring up the logs.
** Netscript **
* The 'flags' function now works with single letter flags but they only take
one dash.
* Fix several broken bladeburner netscript functions.
* Fix gang.getMemberInformation returning inconsistent data after the gang
rework.
** CPU Cores **
* CPU Cores on the home computer now provide a bonus to grow() money gain
and makes weaken lower more security. Only for scripts running on 'home'
** Misc. **
* Fix weird scrolling in the new Bladeburner React console.
* nerf noodle bar
v0.52.4 - 2021-07-19 Bladeburner in React (hydroflame)
-------------------------------------------

@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
# The short X.Y version.
version = '0.52'
# The full version, including alpha/beta/rc tags.
release = '0.52.4'
release = '0.52.5'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

@ -1,12 +1,13 @@
growPercent() Netscript Function
=================================
.. js:function:: growPercent(server, threads, player)
.. js:function:: growPercent(server, threads, player, cores)
:RAM cost: 0 GB
:param server server: The server that receives the growth.
:param number threads: The number of thread that would be used.
:param player player: The player.
:param number cores: The amount of cores on the host computer.
:returns: The amount the server's money would be multiplied by with these
parameters.

@ -13,30 +13,42 @@ getMemberInformation() Netscript Function
name: Name of this member.
task: Name of currently assigned task.
earnedRespect: Total amount of respect earned by this member.
hack: Hacking stat
str: Strength stat
def: Defense stat
dex: Dexterity stat
agi: Agility stat
cha: Charisma stat
hack_exp: Hacking experience
str_exp: Strength experience
def_exp: Defense experience
dex_exp: Dexterity experience
agi_exp: Agility experience
cha_exp: Charisma experience
hack_mult: Hacking multiplier from equipment. Decimal form
str_mult: Strength multiplier from equipment. Decimal form
def_mult: Defense multiplier from equipment. Decimal form
dex_mult: Dexterity multiplier from equipment. Decimal form
agi_mult: Agility multiplier from equipment. Decimal form
cha_mult: Charisma multiplier from equipment. Decimal form
hack_asc_mult: Hacking multiplier from ascension. Decimal form
str_asc_mult: Strength multiplier from ascension. Decimal form
def_asc_mult: Defense multiplier from ascension. Decimal form
dex_asc_mult: Dexterity multiplier from ascension. Decimal form
agi_asc_mult: Agility multiplier from ascension. Decimal form
cha_asc_mult: Charisma multiplier from ascension. Decimal form
hack_asc_points: Hacking ascension points.
str_asc_points: Strength ascension points.
def_asc_points: Defense ascension points.
dex_asc_points: Dexterity ascension points.
agi_asc_points: Agility ascension points.
cha_asc_points: Charisma ascension points.
upgrades: Array of names of all owned Non-Augmentation Equipment
augmentations: Array of names of all owned Augmentations
}

@ -126,5 +126,5 @@
"watch": "webpack --watch --mode production",
"watch:dev": "webpack --watch --mode development"
},
"version": "0.52.4"
"version": "0.52.5"
}

@ -26,8 +26,18 @@ export function Console(props: IProps): React.ReactElement {
// TODO: Figure out how to actually make the scrolling work correctly.
function scrollToBottom(): void {
if(lastRef.current)
function isMaxed(): boolean {
if(!lastRef.current) return false;
const oldTop = lastRef.current.scrollTop;
lastRef.current.scrollTop = lastRef.current.scrollHeight;
const maxed = oldTop === lastRef.current.scrollTop;
lastRef.current.scrollTop = oldTop;
return maxed;
}
if(lastRef.current) {
if(isMaxed())
lastRef.current.scrollTop = lastRef.current.scrollHeight;
}
}
function rerender(): void {

@ -6,7 +6,7 @@
import { IMap } from "./types";
export const CONSTANTS: IMap<any> = {
Version: "0.52.4",
Version: "0.52.5",
// Speed (in ms) at which the main loop is updated
_idleSpeed: 200,
@ -228,26 +228,30 @@ export const CONSTANTS: IMap<any> = {
TotalNumBitNodes: 24,
LatestUpdate: `
v0.52.4 - 2021-07-19 Bladeburner in React (hydroflame)
v0.52.5 - 2021-07-19 CPU cores are useful!? (hydroflame)
-------------------------------------------
** Bladeburner **
** Terminal **
* The entire UI was rebuild in React. It should be more responsive
* When executing 'run SCRIPT' any script can now add '--tail' to
automatically bring up the logs.
** Hacknet **
** Netscript **
* Displays how many time each hash upgrade was bought.
* Displays cummulative effect of the upgrade.
* Removed "Close" button from hash upgrade menu.
* The 'flags' function now works with single letter flags but they only take
one dash.
* Fix several broken bladeburner netscript functions.
* Fix gang.getMemberInformation returning inconsistent data after the gang
rework.
** CPU Cores **
* CPU Cores on the home computer now provide a bonus to grow() money gain
and makes weaken lower more security. Only for scripts running on 'home'
** Misc. **
* More popup/modals have dark background, can be dismissed by clicking
outside, or by pressing escape.
* Small reword in the guide.
* Fix several typos in the bladeburner documentation.
* Linting (no one cares except the dev)
* Fix weird scrolling in the new Bladeburner React console.
* nerf noodle bar
`,
}

@ -44,8 +44,6 @@ export class HashUpgrade {
// The meaning varies between different upgrades
value = 0;
effectText: (level: number) => JSX.Element | null = () => null;
constructor(p: IConstructorParams) {
if (p.cost != null) { this.cost = p.cost; }
if (p.effectText != null) { this.effectText = p.effectText; }
@ -57,6 +55,9 @@ export class HashUpgrade {
this.value = p.value;
}
// Functions that returns the UI element to display the effect of this upgrade.
effectText: (level: number) => JSX.Element | null = () => null;
getCost(levels: number): number {
if (typeof this.cost === "number") { return this.cost; }

@ -11,7 +11,6 @@ import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat";
import { PopupCloseButton } from "../../ui/React/PopupCloseButton";
import { ServerDropdown,
ServerType } from "../../ui/React/ServerDropdown"

@ -204,7 +204,7 @@ export const LocationsMetadata: IConstructorParams[] = [
startingSecurityLevel: 2.5,
},
name: LocationName.NewTokyoNoodleBar,
types: [LocationType.Company],
types: [LocationType.Company, LocationType.Special],
},
{
city: CityName.NewTokyo,

@ -45,6 +45,7 @@ export class SpecialLocation extends React.Component<IProps, IState> {
this.btnStyle = { display: "block" };
this.renderNoodleBar = this.renderNoodleBar.bind(this);
this.createCorporationPopup = this.createCorporationPopup.bind(this);
this.handleBladeburner = this.handleBladeburner.bind(this);
this.handleResleeving = this.handleResleeving.bind(this);
@ -107,6 +108,18 @@ export class SpecialLocation extends React.Component<IProps, IState> {
)
}
renderNoodleBar(): React.ReactNode {
function EatNoodles(): void {
dialogBoxCreate(<>You ate some delicious noodles and feel refreshed.</>)
}
return (<StdButton
onClick={EatNoodles}
style={this.btnStyle}
text={'Eat noodles'}
/>)
}
renderCreateCorporation(): React.ReactNode {
if (!this.props.p.canAccessCorporation()) {
return <>
@ -145,6 +158,9 @@ export class SpecialLocation extends React.Component<IProps, IState> {
case LocationName.Sector12NSA: {
return this.renderBladeburner();
}
case LocationName.NewTokyoNoodleBar: {
return this.renderNoodleBar();
}
default:
console.error(`Location ${this.props.loc.name} doesn't have any special properties`);
break;

@ -853,6 +853,8 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeErrorMsg("grow", `Invalid IP/hostname: ${ip}.`);
}
const host = getServer(workerScript.serverIp);
// No root access or skill level too low
const canHack = netscriptCanGrow(server);
if (!canHack.res) {
@ -865,7 +867,7 @@ function NetscriptFunctions(workerScript) {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable;
server.moneyAvailable += (1 * threads); // It can be grown even if it has no money
processSingleServerGrowth(server, threads, Player);
processSingleServerGrowth(server, threads, Player, host.cpuCores);
const moneyAfter = server.moneyAvailable;
workerScript.scriptRef.recordGrow(server.ip, threads);
var expGain = calculateHackingExpGain(server, Player) * threads;
@ -896,7 +898,7 @@ function NetscriptFunctions(workerScript) {
if (ip === undefined) {
throw makeRuntimeErrorMsg("weaken", "Takes 1 argument.");
}
var server = getServer(ip);
const server = getServer(ip);
if (server == null) {
throw makeRuntimeErrorMsg("weaken", `Invalid IP/hostname: ${ip}`);
}
@ -907,13 +909,15 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeErrorMsg("weaken", canHack.msg);
}
var weakenTime = calculateWeakenTime(server, Player);
const weakenTime = calculateWeakenTime(server, Player);
workerScript.log("weaken", `Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(weakenTime*1000, true)} (t=${numeralWrapper.formatThreads(threads)})`);
return netscriptDelay(weakenTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
server.weaken(CONSTANTS.ServerWeakenAmount * threads);
if (workerScript.env.stopFlag) return Promise.reject(workerScript);
const host = getServer(workerScript.serverIp);
const coreBonus = 1+(host.cpuCores-1)/16;
server.weaken(CONSTANTS.ServerWeakenAmount * threads * coreBonus);
workerScript.scriptRef.recordWeaken(server.ip, threads);
var expGain = calculateHackingExpGain(server, Player) * threads;
const expGain = calculateHackingExpGain(server, Player) * threads;
workerScript.log("weaken", `'${server.hostname}' security level weakened to ${server.hackDifficulty}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)})`);
workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain);
@ -3671,24 +3675,35 @@ function NetscriptFunctions(workerScript) {
dex: member.dex,
agi: member.agi,
cha: member.cha,
hack_exp: member.hack_exp,
str_exp: member.str_exp,
def_exp: member.def_exp,
dex_exp: member.dex_exp,
agi_exp: member.agi_exp,
cha_exp: member.cha_exp,
hack_mult: member.hack_mult,
str_mult: member.str_mult,
def_mult: member.def_mult,
dex_mult: member.dex_mult,
agi_mult: member.agi_mult,
cha_mult: member.cha_mult,
hack_asc_mult: member.hack_asc_mult,
str_asc_mult: member.str_asc_mult,
def_asc_mult: member.def_asc_mult,
dex_asc_mult: member.dex_asc_mult,
agi_asc_mult: member.agi_asc_mult,
cha_asc_mult: member.cha_asc_mult,
hack_asc_mult: member.calculateAscensionMult(member.hack_asc_points),
str_asc_mult: member.calculateAscensionMult(member.str_asc_points),
def_asc_mult: member.calculateAscensionMult(member.def_asc_points),
dex_asc_mult: member.calculateAscensionMult(member.dex_asc_points),
agi_asc_mult: member.calculateAscensionMult(member.agi_asc_points),
cha_asc_mult: member.calculateAscensionMult(member.cha_asc_points),
hack_asc_points: member.hack_asc_points,
str_asc_points: member.str_asc_points,
def_asc_points: member.def_asc_points,
dex_asc_points: member.dex_asc_points,
agi_asc_points: member.agi_asc_points,
cha_asc_points: member.cha_asc_points,
upgrades: member.upgrades.slice(),
augmentations: member.augmentations.slice(),
}
@ -4375,9 +4390,9 @@ function NetscriptFunctions(workerScript) {
checkFormulasAccess("basic.hackPercent", 5);
return calculatePercentMoneyHacked(server, player);
},
growPercent: function(server, threads, player) {
growPercent: function(server, threads, player, cores = 1) {
checkFormulasAccess("basic.growPercent", 5);
return calculateServerGrowth(server, threads, player);
return calculateServerGrowth(server, threads, player, cores);
},
hackTime: function(server, player) {
checkFormulasAccess("basic.hackTime", 5);
@ -4492,17 +4507,19 @@ function NetscriptFunctions(workerScript) {
} else if(Array.isArray(d[1])) {
t = [String];
}
args['--'+d[0]] = t
const numDashes = d[0].length > 1 ? 2 : 1;
args['-'.repeat(numDashes)+d[0]] = t
}
const ret = libarg(args, {argv: workerScript.args});
for(const d of data) {
if(!ret.hasOwnProperty('--'+d[0])) ret[d[0]] = d[1];
if(!ret.hasOwnProperty('--'+d[0]) || !ret.hasOwnProperty('-'+d[0])) ret[d[0]] = d[1];
}
for(const key of Object.keys(ret)) {
if(!key.startsWith('--')) continue;
if(!key.startsWith('-')) continue;
const value = ret[key];
delete ret[key];
ret[key.slice(2)] = value;
const numDashes = key.length === 2 ? 1 : 2;
ret[key.slice(numDashes)] = value;
}
return ret;
},

@ -313,7 +313,8 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
if (serv == null) {continue;}
const timesGrown = Math.round(0.5 * runningScriptObj.dataMap[ip][2] / runningScriptObj.onlineRunningTime * timePassed);
runningScriptObj.log(`Called on ${serv.hostname} ${timesGrown} times while offline`);
const growth = processSingleServerGrowth(serv, timesGrown, Player);
const host = AllServers[runningScriptObj.server];
const growth = processSingleServerGrowth(serv, timesGrown, Player, host.cpuCores);
runningScriptObj.log(`'${serv.hostname}' grown by ${numeralWrapper.format(growth * 100 - 100, '0.000000%')} while offline`);
}
}
@ -333,9 +334,11 @@ export function scriptCalculateOfflineProduction(runningScriptObj) {
if (runningScriptObj.dataMap[ip][3] == 0 || runningScriptObj.dataMap[ip][3] == null) {continue;}
const serv = AllServers[ip];
if (serv == null) {continue;}
const host = AllServers[runningScriptObj.server];
const timesWeakened = Math.round(0.5 * runningScriptObj.dataMap[ip][3] / runningScriptObj.onlineRunningTime * timePassed);
runningScriptObj.log(`Called weaken() on ${serv.hostname} ${timesWeakened} times while offline`);
serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened);
const coreBonus = 1+(host.cpuCores-1)/16;
serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened * coreBonus);
}
}
}

@ -60,8 +60,8 @@ export function numCycleForGrowth(server: Server, growth: number, p: IPlayer): n
}
//Applied server growth for a single server. Returns the percentage growth
export function processSingleServerGrowth(server: Server, threads: number, p: IPlayer): number {
let serverGrowth = calculateServerGrowth(server, threads, p);
export function processSingleServerGrowth(server: Server, threads: number, p: IPlayer, cores: number = 1): number {
let serverGrowth = calculateServerGrowth(server, threads, p, cores);
if (serverGrowth < 1) {
console.warn("serverGrowth calculated to be less than 1");
serverGrowth = 1;

@ -3,7 +3,7 @@ import { Server } from "../Server";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { IPlayer } from "../../PersonObjects/IPlayer";
export function calculateServerGrowth(server: Server, threads: number, p: IPlayer): number {
export function calculateServerGrowth(server: Server, threads: number, p: IPlayer, cores: number = 1): number {
const numServerGrowthCycles = Math.max(Math.floor(threads), 0);
//Get adjusted growth rate, which accounts for server security
@ -16,5 +16,6 @@ export function calculateServerGrowth(server: Server, threads: number, p: IPlaye
const numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
//Apply serverGrowth for the calculated number of growth cycles
return Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * p.hacking_grow_mult);
const coreBonus = 1+(cores-1)/16;
return Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * p.hacking_grow_mult * coreBonus);
}

@ -98,6 +98,7 @@ import { Money } from "./ui/React/Money";
import autosize from "autosize";
import * as JSZip from "jszip";
import * as FileSaver from "file-saver";
import * as libarg from 'arg';
import React from "react";
@ -2378,28 +2379,18 @@ let Terminal = {
}
const server = Player.getCurrentServer();
let numThreads = 1;
const args = [];
const scriptName = Terminal.getFilepath(commandArray[1]);
if (commandArray.length > 2) {
if (commandArray.length >= 4 && commandArray[2] == "-t") {
numThreads = Math.round(parseFloat(commandArray[3]));
if (isNaN(numThreads) || numThreads < 1) {
postError("Invalid number of threads specified. Number of threads must be greater than 0");
return;
}
for (let i = 4; i < commandArray.length; ++i) {
args.push(commandArray[i]);
}
} else {
for (let i = 2; i < commandArray.length; ++i) {
args.push(commandArray[i])
}
}
const runArgs = {'--tail': Boolean, '-t': Number};
const flags = libarg(runArgs, {permissive: true, argv: commandArray.slice(2)});
const threadFlag = Math.round(parseFloat(flags['-t']));
const tailFlag = flags['--tail'] === true;
if(flags['-t'] !== undefined && (threadFlag < 0 || isNaN(threadFlag))) {
postError("Invalid number of threads specified. Number of threads must be greater than 0");
return;
}
const numThreads = !isNaN(threadFlag) && threadFlag > 0 ? threadFlag : 1;
const args = flags['_'];
// Check if this script is already running
if (findRunningScript(scriptName, args, server) != null) {
@ -2408,33 +2399,41 @@ let Terminal = {
}
// Check if the script exists and if it does run it
for (var i = 0; i < server.scripts.length; i++) {
if (server.scripts[i].filename === scriptName) {
// Check for admin rights and that there is enough RAM availble to run
var script = server.scripts[i];
var ramUsage = script.ramUsage * numThreads;
var ramAvailable = server.maxRam - server.ramUsed;
if (server.hasAdminRights == false) {
post("Need root access to run script");
return;
} else if (ramUsage > ramAvailable){
post("This machine does not have enough RAM to run this script with " +
numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
return;
} else {
// Able to run script
var runningScriptObj = new RunningScript(script, args);
runningScriptObj.threads = numThreads;
if (startWorkerScript(runningScriptObj, server)) {
post(`Running script with ${numThreads} thread(s), pid ${runningScriptObj.pid} and args: ${arrayToString(args)}.`);
} else {
postError(`Failed to start script`);
}
return;
}
for (let i = 0; i < server.scripts.length; i++) {
if (server.scripts[i].filename !== scriptName) {
continue
}
// Check for admin rights and that there is enough RAM availble to run
const script = server.scripts[i];
const ramUsage = script.ramUsage * numThreads;
const ramAvailable = server.maxRam - server.ramUsed;
if (!server.hasAdminRights) {
post("Need root access to run script");
return;
}
if (ramUsage > ramAvailable){
post("This machine does not have enough RAM to run this script with " +
numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
return;
}
// Able to run script
const runningScript = new RunningScript(script, args);
runningScript.threads = numThreads;
const success = startWorkerScript(runningScript, server);
if (!success) {
postError(`Failed to start script`);
return
}
post(`Running script with ${numThreads} thread(s), pid ${runningScript.pid} and args: ${arrayToString(args)}.`);
if(tailFlag) {
logBoxCreate(runningScript)
}
return;
}
post("ERROR: No such script");