merge base

This commit is contained in:
phyzical
2022-04-15 14:25:13 +08:00
19 changed files with 232 additions and 98 deletions
+9 -1
View File
@@ -1,5 +1,14 @@
# DELETE THIS AFTER READING # DELETE THIS AFTER READING
# PR title
Formatted as such:
SECTION: FIX #xzyw PLAYER DESCRIPTION
SECTION is something like "API", "UI", "MISC", "STANEK", "CORPORATION"
FIX #xyzw is the issue number, if any
PLAYER DESCRIPTION is what you'd tell a non-contributor to convey what is changed.
# Documentation # Documentation
- DO NOT CHANGE any markdown/\*.md, these files are autogenerated from NetscriptDefinitions.d.ts and will be overwritten - DO NOT CHANGE any markdown/\*.md, these files are autogenerated from NetscriptDefinitions.d.ts and will be overwritten
@@ -10,5 +19,4 @@
- Include how it was tested - Include how it was tested
- Include screenshot / gif (if possible) - Include screenshot / gif (if possible)
Make sure you run `npm run format` and `npm run lint` before pushing. Make sure you run `npm run format` and `npm run lint` before pushing.
+2
View File
@@ -1,5 +1,7 @@
# Bitburner # Bitburner
[![Join Discord](https://img.shields.io/discord/415207508303544321)](https://discord.gg/TFc3hKD)
[![Build Status](https://github.com/danielyxie/bitburner/actions/workflows/ci.yml/badge.svg?branch=dev)](https://github.com/danielyxie/bitburner/actions/workflows/ci.yml) [![Build Status](https://github.com/danielyxie/bitburner/actions/workflows/ci.yml/badge.svg?branch=dev)](https://github.com/danielyxie/bitburner/actions/workflows/ci.yml)
Bitburner is a programming-based [incremental game](https://en.wikipedia.org/wiki/Incremental_game) Bitburner is a programming-based [incremental game](https://en.wikipedia.org/wiki/Incremental_game)
+11
View File
@@ -0,0 +1,11 @@
BitNodes are advanced simulations used to contain humanity by the Enders. It is
unknown how or why they operate, but what is clear is that the World Daemon is
extremely important to the operation of a BitNode. It is possible for the daemon
to be hacked, which results in the entire simulation going offline and the
failure of automatic attempts to reboot the node. The Daemon has a physical
presence, as indicated by the Bladeburners' ability to destroy it via force.
Also, hydroflame (irl) has stated that the glitch in Ishima is the physical
location of the World Daemon in a node. When the player destroys a BitNode, it is
currently unknown what becomes of it, or the people trapped within. However, based
on the way jump3r and Deadalus help the player to destroy it, doing so is somehow
aligned with their goals.
+5
View File
@@ -0,0 +1,5 @@
The "Enders", as dubbed by the humans who know of them, are a humanoid alien race
with extremely advanced technology. "Many decades ago", they invaded Earth, leading
to war between the humans and enders, but the enders were far too powerful for the
humans to win against. When the enders had won, they, for reasons unknown, kept some
number of humans alive, and in some way contained the humans within BitNodes.
+12 -12
View File
@@ -5046,9 +5046,9 @@
} }
}, },
"node_modules/async": { "node_modules/async": {
"version": "2.6.3", "version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"lodash": "^4.17.14" "lodash": "^4.17.14"
@@ -10199,9 +10199,9 @@
} }
}, },
"node_modules/getos/node_modules/async": { "node_modules/getos/node_modules/async": {
"version": "3.2.1", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
"integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==", "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==",
"dev": true "dev": true
}, },
"node_modules/getpass": { "node_modules/getpass": {
@@ -26245,9 +26245,9 @@
"dev": true "dev": true
}, },
"async": { "async": {
"version": "2.6.3", "version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true, "dev": true,
"requires": { "requires": {
"lodash": "^4.17.14" "lodash": "^4.17.14"
@@ -30405,9 +30405,9 @@
}, },
"dependencies": { "dependencies": {
"async": { "async": {
"version": "3.2.1", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
"integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==", "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==",
"dev": true "dev": true
} }
} }
+2 -1
View File
@@ -134,6 +134,7 @@
"allbuild": "npm run build && npm run electron && git add --all && git commit -m \"allbuild commit $(git rev-parse --short HEAD)\" && git push -f -u origin dev", "allbuild": "npm run build && npm run electron && git add --all && git commit -m \"allbuild commit $(git rev-parse --short HEAD)\" && git push -f -u origin dev",
"preversion": "npm install && npm run test", "preversion": "npm install && npm run test",
"version": "sh ./tools/build-release.sh && git add --all", "version": "sh ./tools/build-release.sh && git add --all",
"postversion": "git push -u origin dev && git push --tags" "postversion": "git push -u origin dev && git push --tags",
"changelog": "node tools/fetch-changelog/index.js --from=$(cat last_changelog_hash) > changelog.md"
} }
} }
+29 -27
View File
@@ -6,6 +6,7 @@ import { WHRNG } from "../../Casino/RNG";
import React from "react"; import React from "react";
import { FactionNames } from "../../Faction/data/FactionNames"; import { FactionNames } from "../../Faction/data/FactionNames";
import { CityName } from "../../Locations/data/CityNames"; import { CityName } from "../../Locations/data/CityNames";
import { CONSTANTS } from "../../Constants";
function getRandomBonus(): any { function getRandomBonus(): any {
const bonuses = [ const bonuses = [
@@ -2049,6 +2050,7 @@ export const initChurchOfTheMachineGodAugmentations = (): Augmentation[] => [
]; ];
export function initNeuroFluxGovernor(): Augmentation { export function initNeuroFluxGovernor(): Augmentation {
const donationBonus = CONSTANTS.Donations / 1e6 / 100; // 1 millionth of a percent per donation
return new Augmentation({ return new Augmentation({
name: AugmentationNames.NeuroFluxGovernor, name: AugmentationNames.NeuroFluxGovernor,
repCost: 500, repCost: 500,
@@ -2061,35 +2063,35 @@ export function initNeuroFluxGovernor(): Augmentation {
stats: ( stats: (
<> <>
This special augmentation can be leveled up infinitely. Each level of this augmentation increases MOST This special augmentation can be leveled up infinitely. Each level of this augmentation increases MOST
multipliers by 1%, stacking multiplicatively. multipliers by 1% (+{donationBonus * 100}% boosted by real life blood donations), stacking multiplicatively.
</> </>
), ),
hacking_chance_mult: 1.01, hacking_chance_mult: 1.01 + donationBonus,
hacking_speed_mult: 1.01, hacking_speed_mult: 1.01 + donationBonus,
hacking_money_mult: 1.01, hacking_money_mult: 1.01 + donationBonus,
hacking_grow_mult: 1.01, hacking_grow_mult: 1.01 + donationBonus,
hacking_mult: 1.01, hacking_mult: 1.01 + donationBonus,
strength_mult: 1.01, strength_mult: 1.01 + donationBonus,
defense_mult: 1.01, defense_mult: 1.01 + donationBonus,
dexterity_mult: 1.01, dexterity_mult: 1.01 + donationBonus,
agility_mult: 1.01, agility_mult: 1.01 + donationBonus,
charisma_mult: 1.01, charisma_mult: 1.01 + donationBonus,
hacking_exp_mult: 1.01, hacking_exp_mult: 1.01 + donationBonus,
strength_exp_mult: 1.01, strength_exp_mult: 1.01 + donationBonus,
defense_exp_mult: 1.01, defense_exp_mult: 1.01 + donationBonus,
dexterity_exp_mult: 1.01, dexterity_exp_mult: 1.01 + donationBonus,
agility_exp_mult: 1.01, agility_exp_mult: 1.01 + donationBonus,
charisma_exp_mult: 1.01, charisma_exp_mult: 1.01 + donationBonus,
company_rep_mult: 1.01, company_rep_mult: 1.01 + donationBonus,
faction_rep_mult: 1.01, faction_rep_mult: 1.01 + donationBonus,
crime_money_mult: 1.01, crime_money_mult: 1.01 + donationBonus,
crime_success_mult: 1.01, crime_success_mult: 1.01 + donationBonus,
hacknet_node_money_mult: 1.01, hacknet_node_money_mult: 1.01 + donationBonus,
hacknet_node_purchase_cost_mult: 0.99, hacknet_node_purchase_cost_mult: 1 / (1.01 + donationBonus),
hacknet_node_ram_cost_mult: 0.99, hacknet_node_ram_cost_mult: 1 / (1.01 + donationBonus),
hacknet_node_core_cost_mult: 0.99, hacknet_node_core_cost_mult: 1 / (1.01 + donationBonus),
hacknet_node_level_cost_mult: 0.99, hacknet_node_level_cost_mult: 1 / (1.01 + donationBonus),
work_money_mult: 1.01, work_money_mult: 1.01 + donationBonus,
factions: Object.values(FactionNames).filter( factions: Object.values(FactionNames).filter(
(factionName) => (factionName) =>
![FactionNames.Infiltrators, FactionNames.Bladeburners, FactionNames.ChurchOfTheMachineGod].includes( ![FactionNames.Infiltrators, FactionNames.Bladeburners, FactionNames.ChurchOfTheMachineGod].includes(
+3
View File
@@ -114,6 +114,7 @@ export const CONSTANTS: {
AugmentationGraftingTimeBase: number; AugmentationGraftingTimeBase: number;
EntropyEffect: number; EntropyEffect: number;
TotalNumBitNodes: number; TotalNumBitNodes: number;
Donations: number; // number of blood/plasma/palette donation the dev have verified., boosts NFG
LatestUpdate: string; LatestUpdate: string;
} = { } = {
VersionString: "1.6.4", VersionString: "1.6.4",
@@ -286,6 +287,8 @@ export const CONSTANTS: {
// BitNode/Source-File related stuff // BitNode/Source-File related stuff
TotalNumBitNodes: 24, TotalNumBitNodes: 24,
Donations: 2,
LatestUpdate: ` LatestUpdate: `
v1.6.3 - 2022-04-01 Few stanek fixes v1.6.3 - 2022-04-01 Few stanek fixes
---------------------------- ----------------------------
+3 -2
View File
@@ -40,8 +40,9 @@ export class ActiveFragment {
// These 2 variables converts 'this' local coordinates to world to other local. // These 2 variables converts 'this' local coordinates to world to other local.
const dx: number = other.x - this.x; const dx: number = other.x - this.x;
const dy: number = other.y - this.y; const dy: number = other.y - this.y;
for (let j = 0; j < thisFragment.shape.length; j++) { const fragSize = Math.max(thisFragment.shape.length, thisFragment.shape[0].length);
for (let i = 0; i < thisFragment.shape[j].length; i++) { for (let j = 0; j < fragSize; j++) {
for (let i = 0; i < fragSize; i++) {
if (thisFragment.fullAt(i, j, this.rotation) && otherFragment.fullAt(i - dx, j - dy, other.rotation)) if (thisFragment.fullAt(i, j, this.rotation) && otherFragment.fullAt(i - dx, j - dy, other.rotation))
return true; return true;
} }
+1 -1
View File
@@ -183,7 +183,7 @@ const Messages: Record<MessageFilenames, Message> = {
"like us. Because they can't hide from us. Because they can't fight shadows " + "like us. Because they can't hide from us. Because they can't fight shadows " +
"and ideas with bullets. <br><br>" + "and ideas with bullets. <br><br>" +
"Join us, and people will fear you, too. <br><br>" + "Join us, and people will fear you, too. <br><br>" +
"Find and install the backdoor on our server. Then, we will contact you again." + "Find and install the backdoor on our server, avmnite-02h. Then, we will contact you again." +
`<br><br>-${FactionNames.NiteSec}`, `<br><br>-${FactionNames.NiteSec}`,
), ),
+7 -4
View File
@@ -59,17 +59,20 @@ export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, help
player.giveExploit(Exploit.RealityAlteration); player.giveExploit(Exploit.RealityAlteration);
} }
}, },
rainbow: function (guess: unknown): void { rainbow: function (guess: unknown): boolean {
async function tryGuess(): Promise<void> { function tryGuess(): boolean {
const verified = await bcrypt.compare( // eslint-disable-next-line no-sync
const verified = bcrypt.compareSync(
helper.string("rainbow", "guess", guess), helper.string("rainbow", "guess", guess),
"$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO", "$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO",
); );
if (verified) { if (verified) {
player.giveExploit(Exploit.INeedARainbow); player.giveExploit(Exploit.INeedARainbow);
return true;
} }
return false;
} }
tryGuess(); return tryGuess();
}, },
}; };
} }
+6
View File
@@ -38,6 +38,7 @@ import {
calculateAscensionPointsGain, calculateAscensionPointsGain,
} from "../Gang/formulas/formulas"; } from "../Gang/formulas/formulas";
import { favorToRep as calculateFavorToRep, repToFavor as calculateRepToFavor } from "../Faction/formulas/favor"; import { favorToRep as calculateFavorToRep, repToFavor as calculateRepToFavor } from "../Faction/formulas/favor";
import { repFromDonation } from "../Faction/formulas/donation";
export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IFormulas { export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IFormulas {
const checkFormulasAccess = function (func: string): void { const checkFormulasAccess = function (func: string): void {
@@ -57,6 +58,11 @@ export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, h
checkFormulasAccess("reputation.calculateRepToFavor"); checkFormulasAccess("reputation.calculateRepToFavor");
return calculateRepToFavor(rep); return calculateRepToFavor(rep);
}, },
repFromDonation: function (_amount: unknown, player: any): number {
const amount = helper.number("repFromDonation", "amount", _amount);
checkFormulasAccess("reputation.repFromDonation");
return repFromDonation(amount, player);
},
}, },
skills: { skills: {
calculateSkill: function (_exp: unknown, _mult: unknown = 1): number { calculateSkill: function (_exp: unknown, _mult: unknown = 1): number {
+32 -19
View File
@@ -23,7 +23,6 @@ import { findCrime } from "../Crime/CrimeHelpers";
import { CompanyPosition } from "../Company/CompanyPosition"; import { CompanyPosition } from "../Company/CompanyPosition";
import { CompanyPositions } from "../Company/CompanyPositions"; import { CompanyPositions } from "../Company/CompanyPositions";
import { DarkWebItems } from "../DarkWeb/DarkWebItems"; import { DarkWebItems } from "../DarkWeb/DarkWebItems";
import { AllGangs } from "../Gang/AllGangs";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
import { LocationName } from "../Locations/data/LocationNames"; import { LocationName } from "../Locations/data/LocationNames";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
@@ -49,6 +48,7 @@ import { FactionInfos } from "../Faction/FactionInfo";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames"; import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
import { enterBitNode } from "../RedPill"; import { enterBitNode } from "../RedPill";
import { FactionNames } from "../Faction/data/FactionNames";
export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI<ISingularity> { export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI<ISingularity> {
const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation { const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation {
@@ -1047,11 +1047,14 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const facName = _ctx.helper.string("facName", _facName); const facName = _ctx.helper.string("facName", _facName);
const type = _ctx.helper.string("type", _type); const type = _ctx.helper.string("type", _type);
const focus = _ctx.helper.boolean(_focus); const focus = _ctx.helper.boolean(_focus);
getFaction(_ctx, facName); const faction = getFaction(_ctx, facName);
// if the player is in a gang and the target faction is any of the gang faction, fail // if the player is in a gang and the target faction is any of the gang faction, fail
if (player.inGang() && AllGangs[facName] !== undefined) { if (player.inGang() && faction.name === player.getGangFaction().name) {
workerScript.log("workForFaction", () => `Faction '${facName}' does not offer work at the moment.`); workerScript.log(
"workForFaction",
() => `You can't work for '${facName}' because youre managing a gang for it`,
);
return false; return false;
} }
@@ -1066,21 +1069,18 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
workerScript.log("workForFaction", () => txt); workerScript.log("workForFaction", () => txt);
} }
const fac = Factions[facName];
// Arrays listing factions that allow each time of work
switch (type.toLowerCase()) { switch (type.toLowerCase()) {
case "hacking": case "hacking":
case "hacking contracts": case "hacking contracts":
case "hackingcontracts": case "hackingcontracts":
if (!FactionInfos[fac.name].offerHackingWork) { if (!FactionInfos[faction.name].offerHackingWork) {
workerScript.log( workerScript.log(
"workForFaction", "workForFaction",
() => `Faction '${fac.name}' do not need help with hacking contracts.`, () => `Faction '${faction.name}' do not need help with hacking contracts.`,
); );
return false; return false;
} }
player.startFactionHackWork(fac); player.startFactionHackWork(faction);
if (focus) { if (focus) {
player.startFocusing(); player.startFocusing();
Router.toWork(); Router.toWork();
@@ -1088,16 +1088,19 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.stopFocusing(); player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
workerScript.log("workForFaction", () => `Started carrying out hacking contracts for '${fac.name}'`); workerScript.log("workForFaction", () => `Started carrying out hacking contracts for '${faction.name}'`);
return true; return true;
case "field": case "field":
case "fieldwork": case "fieldwork":
case "field work": case "field work":
if (!FactionInfos[fac.name].offerFieldWork) { if (!FactionInfos[faction.name].offerFieldWork) {
workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with field missions.`); workerScript.log(
"workForFaction",
() => `Faction '${faction.name}' do not need help with field missions.`,
);
return false; return false;
} }
player.startFactionFieldWork(fac); player.startFactionFieldWork(faction);
if (focus) { if (focus) {
player.startFocusing(); player.startFocusing();
Router.toWork(); Router.toWork();
@@ -1105,16 +1108,19 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.stopFocusing(); player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
workerScript.log("workForFaction", () => `Started carrying out field missions for '${fac.name}'`); workerScript.log("workForFaction", () => `Started carrying out field missions for '${faction.name}'`);
return true; return true;
case "security": case "security":
case "securitywork": case "securitywork":
case "security work": case "security work":
if (!FactionInfos[fac.name].offerSecurityWork) { if (!FactionInfos[faction.name].offerSecurityWork) {
workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with security work.`); workerScript.log(
"workForFaction",
() => `Faction '${faction.name}' do not need help with security work.`,
);
return false; return false;
} }
player.startFactionSecurityWork(fac); player.startFactionSecurityWork(faction);
if (focus) { if (focus) {
player.startFocusing(); player.startFocusing();
Router.toWork(); Router.toWork();
@@ -1122,7 +1128,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.stopFocusing(); player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
workerScript.log("workForFaction", () => `Started carrying out security work for '${fac.name}'`); workerScript.log("workForFaction", () => `Started carrying out security work for '${faction.name}'`);
return true; return true;
default: default:
workerScript.log("workForFaction", () => `Invalid work type: '${type}`); workerScript.log("workForFaction", () => `Invalid work type: '${type}`);
@@ -1168,6 +1174,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
); );
return false; return false;
} }
if (faction.name === FactionNames.ChurchOfTheMachineGod || faction.name === FactionNames.Bladeburners) {
workerScript.log(
"donateToFaction",
() => `You can't donate to '${facName}' because they do not accept donations`,
);
return false;
}
if (typeof amt !== "number" || amt <= 0 || isNaN(amt)) { if (typeof amt !== "number" || amt <= 0 || isNaN(amt)) {
workerScript.log("donateToFaction", () => `Invalid donation amount: '${amt}'.`); workerScript.log("donateToFaction", () => `Invalid donation amount: '${amt}'.`);
return false; return false;
+6 -1
View File
@@ -16,6 +16,7 @@ import {
SleeveSkills, SleeveSkills,
SleeveTask, SleeveTask,
} from "../ScriptEditor/NetscriptDefinitions"; } from "../ScriptEditor/NetscriptDefinitions";
import { checkEnum } from "../utils/helpers/checkEnum";
export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): ISleeve { export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): ISleeve {
const checkSleeveAPIAccess = function (func: string): void { const checkSleeveAPIAccess = function (func: string): void {
@@ -99,7 +100,11 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
const cityName = helper.string("travel", "cityName", _cityName); const cityName = helper.string("travel", "cityName", _cityName);
checkSleeveAPIAccess("travel"); checkSleeveAPIAccess("travel");
checkSleeveNumber("travel", sleeveNumber); checkSleeveNumber("travel", sleeveNumber);
return player.sleeves[sleeveNumber].travel(player, cityName as CityName); if (checkEnum(CityName, cityName)) {
return player.sleeves[sleeveNumber].travel(player, cityName);
} else {
throw helper.makeRuntimeErrorMsg("sleeve.setToCompanyWork", `Invalid city name: '${cityName}'.`);
}
}, },
setToCompanyWork: function (_sleeveNumber: unknown, acompanyName: unknown): boolean { setToCompanyWork: function (_sleeveNumber: unknown, acompanyName: unknown): boolean {
updateRam("setToCompanyWork"); updateRam("setToCompanyWork");
+2 -1
View File
@@ -37,6 +37,7 @@ import { ISkillProgress } from "../formulas/skill";
import { PlayerAchievement } from "../../Achievements/Achievements"; import { PlayerAchievement } from "../../Achievements/Achievements";
import { cyrb53 } from "../../utils/StringHelperFunctions"; import { cyrb53 } from "../../utils/StringHelperFunctions";
import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { CONSTANTS } from "../../Constants";
export class PlayerObject implements IPlayer { export class PlayerObject implements IPlayer {
// Class members // Class members
@@ -361,7 +362,7 @@ export class PlayerObject implements IPlayer {
this.faction_rep_mult = 1; this.faction_rep_mult = 1;
//Money //Money
this.money = 1000; this.money = 1000 + CONSTANTS.Donations;
//Location information //Location information
this.city = CityName.Sector12; this.city = CityName.Sector12;
@@ -105,7 +105,7 @@ export function prestigeAugmentation(this: PlayerObject): void {
this.agility_exp = 0; this.agility_exp = 0;
this.charisma_exp = 0; this.charisma_exp = 0;
this.money = 1000; this.money = 1000 + CONSTANTS.Donations;
this.city = CityName.Sector12; this.city = CityName.Sector12;
this.location = LocationName.TravelAgency; this.location = LocationName.TravelAgency;
+7
View File
@@ -3873,6 +3873,13 @@ interface ReputationFormulas {
* @returns The calculated faction favor. * @returns The calculated faction favor.
*/ */
calculateRepToFavor(rep: number): number; calculateRepToFavor(rep: number): number;
/**
* Calculate how much rep would be gained.
* @param amount - Amount of money donated
* @param player - Player info from {@link NS.getPlayer | getPlayer}
*/
repFromDonation(amount: number, player: Player): number;
} }
/** /**
+94 -21
View File
@@ -9,6 +9,8 @@ import { evaluateDirectoryPath, getFirstParentDirectory, isValidDirectoryPath }
import { IRouter } from "../../ui/Router"; import { IRouter } from "../../ui/Router";
import { ITerminal } from "../ITerminal"; import { ITerminal } from "../ITerminal";
import * as libarg from "arg"; import * as libarg from "arg";
import { showLiterature } from "../../Literature/LiteratureHelpers";
import { MessageFilenames, showMessage } from "../../Message/MessageHelpers";
export function ls( export function ls(
terminal: ITerminal, terminal: ITerminal,
@@ -121,13 +123,13 @@ export function ls(
allMessages.sort(); allMessages.sort();
folders.sort(); folders.sort();
interface ClickableScriptRowProps { interface ClickableRowProps {
row: string; row: string;
prefix: string; prefix: string;
hostname: string; hostname: string;
} }
function ClickableScriptRow({ row, prefix, hostname }: ClickableScriptRowProps): React.ReactElement { function ClickableScriptRow({ row, prefix, hostname }: ClickableRowProps): React.ReactElement {
const classes = makeStyles((theme: Theme) => const classes = makeStyles((theme: Theme) =>
createStyles({ createStyles({
scriptLinksWrap: { scriptLinksWrap: {
@@ -160,18 +162,82 @@ export function ls(
return ( return (
<span className={classes.scriptLinksWrap}> <span className={classes.scriptLinksWrap}>
{rowSplitArray.map((rowItem) => ( {rowSplitArray.map((rowItem) => (
<span> <span key={"script_" + rowItem[0]}>
<span key={rowItem[0]} className={classes.scriptLink} onClick={() => onScriptLinkClick(rowItem[0])}> <span className={classes.scriptLink} onClick={() => onScriptLinkClick(rowItem[0])}>
{rowItem[0]} {rowItem[0]}
</span> </span>
<span key={"s" + rowItem[0]}>{rowItem[1]}</span> <span>{rowItem[1]}</span>
</span> </span>
))} ))}
</span> </span>
); );
} }
function postSegments(segments: string[], flags: any, style?: any, linked?: boolean): void { function ClickableMessageRow({ row, prefix, hostname }: ClickableRowProps): React.ReactElement {
const classes = makeStyles((theme: Theme) =>
createStyles({
linksWrap: {
display: "inline-flex",
color: theme.palette.primary.main,
},
link: {
cursor: "pointer",
textDecorationLine: "underline",
paddingRight: "1.15em",
"&:last-child": { padding: 0 },
},
}),
)();
const rowSplit = row.split("~");
let rowSplitArray = rowSplit.map((x) => [x.trim(), x.replace(x.trim(), "")]);
rowSplitArray = rowSplitArray.filter((x) => !!x[0]);
function onMessageLinkClick(filename: string): void {
if (player.getCurrentServer().hostname !== hostname) {
return terminal.error(`File is not on this server, connect to ${hostname} and try again`);
}
if (filename.startsWith("/")) filename = filename.slice(1);
const filepath = terminal.getFilepath(`${prefix}${filename}`);
if (filepath.endsWith(".lit")) {
showLiterature(filepath);
} else if (filepath.endsWith(".msg")) {
showMessage(filepath as MessageFilenames);
}
}
return (
<span className={classes.linksWrap}>
{rowSplitArray.map((rowItem) => (
<span key={"text_" + rowItem[0]}>
<span className={classes.link} onClick={() => onMessageLinkClick(rowItem[0])}>
{rowItem[0]}
</span>
<span>{rowItem[1]}</span>
</span>
))}
</span>
);
}
enum FileType {
Folder,
Message,
TextFile,
Program,
Contract,
Script,
}
interface FileGroup {
type: FileType;
segments: string[];
}
function postSegments(group: FileGroup, flags: any): void {
const segments = group.segments;
const linked = group.type === FileType.Script || group.type === FileType.Message;
const maxLength = Math.max(...segments.map((s) => s.length)) + 1; const maxLength = Math.max(...segments.map((s) => s.length)) + 1;
const filesPerRow = flags["-l"] === true ? 1 : Math.ceil(80 / maxLength); const filesPerRow = flags["-l"] === true ? 1 : Math.ceil(80 / maxLength);
for (let i = 0; i < segments.length; i++) { for (let i = 0; i < segments.length; i++) {
@@ -186,25 +252,32 @@ export function ls(
i++; i++;
} }
i--; i--;
if (!style) {
terminal.print(row); switch (group.type) {
} else if (linked) { case FileType.Folder:
terminal.printRaw(<ClickableScriptRow row={row} prefix={prefix} hostname={server.hostname} />); terminal.printRaw(<span style={{ color: "cyan" }}>{row}</span>);
} else { break;
terminal.printRaw(<span style={style}>{row}</span>); case FileType.Script:
terminal.printRaw(<ClickableScriptRow row={row} prefix={prefix} hostname={server.hostname} />);
break;
case FileType.Message:
terminal.printRaw(<ClickableMessageRow row={row} prefix={prefix} hostname={server.hostname} />);
break;
default:
terminal.print(row);
} }
} }
} }
const groups = [ const groups: FileGroup[] = [
{ segments: folders, style: { color: "cyan" } }, { type: FileType.Folder, segments: folders },
{ segments: allMessages }, { type: FileType.Message, segments: allMessages },
{ segments: allTextFiles }, { type: FileType.TextFile, segments: allTextFiles },
{ segments: allPrograms }, { type: FileType.Program, segments: allPrograms },
{ segments: allContracts }, { type: FileType.Contract, segments: allContracts },
{ segments: allScripts, style: { color: "yellow", fontStyle: "bold" }, linked: true }, { type: FileType.Script, segments: allScripts },
].filter((g) => g.segments.length > 0); ].filter((g) => g.segments.length > 0);
for (let i = 0; i < groups.length; i++) { for (const group of groups) {
postSegments(groups[i].segments, flags, groups[i].style, groups[i].linked); postSegments(group, flags);
} }
} }
@@ -6,7 +6,6 @@ import { getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGene
import { Environment } from "../../../src/Netscript/Environment"; import { Environment } from "../../../src/Netscript/Environment";
import { RunningScript } from "../../../src/Script/RunningScript"; import { RunningScript } from "../../../src/Script/RunningScript";
import { Script } from "../../../src/Script/Script"; import { Script } from "../../../src/Script/Script";
import { SourceFileFlags } from "../../../src/SourceFile/SourceFileFlags";
jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", { jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", {
virtual: true, virtual: true,
@@ -169,12 +168,6 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
testEquality(workerScript.dynamicRamUsage, runningScript.ramUsage); testEquality(workerScript.dynamicRamUsage, runningScript.ramUsage);
} }
beforeEach(function () {
for (let i = 0; i < SourceFileFlags.length; ++i) {
SourceFileFlags[i] = 3;
}
});
describe("Basic Functions", function () { describe("Basic Functions", function () {
it("hack()", async function () { it("hack()", async function () {
const f = ["hack"]; const f = ["hack"];