Merge pull request #3495 from danielyxie/dev

blood
This commit is contained in:
hydroflame
2022-04-18 11:19:55 -04:00
committed by GitHub
29 changed files with 465 additions and 320 deletions

View File

@@ -1,5 +1,19 @@
# 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.
# Linked issues
If your pull request is related to a git issue, please link it in the description using #xyz.
If your PR should close the issue when it is merged in, use `fixes #xyz` or `closes #xyz`. It'll automate the process.
# 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 +24,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.

64
.github/workflows/validate-pr.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: Validate PR
on:
pull_request:
branches: [dev]
types: [opened, edited, synchronize, reopened]
jobs:
checkTitle:
name: Check Title
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Validate Title
id: validate-pr-title
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Creating label (if it does not exist)"
LABEL="validation: invalid title"
gh --repo "${{ github.repository }}" \
label create "$LABEL" --description "Modifications to this pull request are requested" --color D93F0B || true
PR_TITLE=$(\
gh --repo "${{ github.repository }}" \
pr view "${{ github.event.number }}" --json title --jq .title)
echo "::set-output name=title::$PR_TITLE"
echo "PR Title: $PR_TITLE"
TITLE_REGEX="^[0-9A-Z\-]*: .*$"
PR_TITLE_VALID=$(echo "$PR_TITLE" | grep -Eq "$TITLE_REGEX" && echo "true" || echo "false")
if [ "$PR_TITLE_VALID" == "true" ]; then
echo "Title is valid, removing label"
gh --repo "${{ github.repository }}" \
pr edit "${{ github.event.number }}" --remove-label "$LABEL" || true
else
echo "Invalid Title"
ERROR_MSG="$PR_TITLE -> should match -> $TITLE_REGEX"
echo "$ERROR_MSG"
echo "::set-output name=invalid::true"
echo "::set-output name=errorMessage::$ERROR_MSG"
touch comment.txt
echo "## The title \`$PR_TITLE\` should match \`$TITLE_REGEX\`" >> comment.txt
echo "" >> comment.txt
echo "SECTION: FIX #xzyw PLAYER DESCRIPTION" >> comment.txt
echo "" >> comment.txt
echo 'SECTION is something like "API", "UI", "MISC", "STANEK", "CORPORATION"' >> comment.txt
echo 'FIX #xyzw is the issue number, if any' >> comment.txt
echo "PLAYER DESCRIPTION is what you'd tell a non-contributor to convey what is changed." >> comment.txt
echo "Add pr label"
gh --repo "${{ github.repository }}" \
pr edit "${{ github.event.number }}" --add-label "$LABEL"
echo "And comment on the pr"
gh --repo "${{ github.repository }}" \
pr comment "${{ github.event.number }}" --body-file comment.txt
fi
- name: Flag workflow error
if: steps.validate-pr-title.outputs.invalid == 'true'
run: |
echo "${{ steps.validate-pr-title.outputs.errorMessage }}"
exit 1

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)

4
dist/main.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

66
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11
lore/bitnodes-general.txt Normal file
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
lore/enders.txt Normal file
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.

24
package-lock.json generated
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
} }
} }

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"
} }
} }

View File

@@ -5,6 +5,7 @@ import { Programs } from "../Programs/Programs";
import { WHRNG } from "../Casino/RNG"; 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 { CONSTANTS } from "../Constants";
function getRandomBonus(): any { function getRandomBonus(): any {
const bonuses = [ const bonuses = [
@@ -1892,6 +1893,8 @@ 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
console.log(donationBonus * 100);
return new Augmentation({ return new Augmentation({
name: AugmentationNames.NeuroFluxGovernor, name: AugmentationNames.NeuroFluxGovernor,
repCost: 500, repCost: 500,
@@ -1904,35 +1907,36 @@ 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).toFixed(6)}% 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), factions: Object.values(FactionNames),
}); });
} }

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: 4,
LatestUpdate: ` LatestUpdate: `
v1.6.3 - 2022-04-01 Few stanek fixes v1.6.3 - 2022-04-01 Few stanek fixes
---------------------------- ----------------------------

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;
} }

View File

@@ -68,7 +68,7 @@ export function General(props: IProps): React.ReactElement {
function setGangFactionDropdown(event: SelectChangeEvent<string>): void { function setGangFactionDropdown(event: SelectChangeEvent<string>): void {
setGangFaction(event.target.value); setGangFaction(event.target.value);
} }
function checkMessages(): void { function checkMessages(): void {
checkForMessagesToSend(); checkForMessagesToSend();
} }

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}`,
), ),

View File

@@ -730,7 +730,22 @@ export function NetscriptCorporation(
const divisionName = helper.string("hireEmployee", "divisionName", _divisionName); const divisionName = helper.string("hireEmployee", "divisionName", _divisionName);
const cityName = helper.city("hireEmployee", "cityName", _cityName); const cityName = helper.city("hireEmployee", "cityName", _cityName);
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
return office.hireRandomEmployee(); const employee = office.hireRandomEmployee();
if (employee === undefined) return undefined;
return {
name: employee.name,
mor: employee.mor,
hap: employee.hap,
ene: employee.ene,
int: employee.int,
cha: employee.cha,
exp: employee.exp,
cre: employee.cre,
eff: employee.eff,
sal: employee.sal,
loc: employee.loc,
pos: employee.pos,
};
}, },
upgradeOfficeSize: function (_divisionName: unknown, _cityName: unknown, _size: unknown): void { upgradeOfficeSize: function (_divisionName: unknown, _cityName: unknown, _size: unknown): void {
checkAccess("upgradeOfficeSize", 8); checkAccess("upgradeOfficeSize", 8);

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();
}, },
}; };
} }

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 {

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 {
@@ -163,10 +163,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const augs = getFactionAugmentationsFiltered(player, fac); const augs = getFactionAugmentationsFiltered(player, fac);
if (!augs.includes(augName)) { if (!augs.includes(augName)) {
workerScript.log( _ctx.log(() => `Faction '${facName}' does not have the '${augName}' augmentation.`);
"purchaseAugmentation",
() => `Faction '${facName}' does not have the '${augName}' augmentation.`,
);
return false; return false;
} }
@@ -174,25 +171,25 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
if (!isNeuroflux) { if (!isNeuroflux) {
for (let j = 0; j < player.queuedAugmentations.length; ++j) { for (let j = 0; j < player.queuedAugmentations.length; ++j) {
if (player.queuedAugmentations[j].name === aug.name) { if (player.queuedAugmentations[j].name === aug.name) {
workerScript.log("purchaseAugmentation", () => `You already have the '${augName}' augmentation.`); _ctx.log(() => `You already have the '${augName}' augmentation.`);
return false; return false;
} }
} }
for (let j = 0; j < player.augmentations.length; ++j) { for (let j = 0; j < player.augmentations.length; ++j) {
if (player.augmentations[j].name === aug.name) { if (player.augmentations[j].name === aug.name) {
workerScript.log("purchaseAugmentation", () => `You already have the '${augName}' augmentation.`); _ctx.log(() => `You already have the '${augName}' augmentation.`);
return false; return false;
} }
} }
} }
if (fac.playerReputation < aug.baseRepRequirement) { if (fac.playerReputation < aug.baseRepRequirement) {
workerScript.log("purchaseAugmentation", () => `You do not have enough reputation with '${fac.name}'.`); _ctx.log(() => `You do not have enough reputation with '${fac.name}'.`);
return false; return false;
} }
const res = purchaseAugmentation(aug, fac, true); const res = purchaseAugmentation(aug, fac, true);
workerScript.log("purchaseAugmentation", () => res); _ctx.log(() => res);
if (isString(res) && res.startsWith("You purchased")) { if (isString(res) && res.startsWith("You purchased")) {
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10);
return true; return true;
@@ -205,7 +202,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
_ctx.helper.checkSingularityAccess(); _ctx.helper.checkSingularityAccess();
const cbScript = _ctx.helper.string("cbScript", _cbScript); const cbScript = _ctx.helper.string("cbScript", _cbScript);
workerScript.log("softReset", () => "Soft resetting. This will cause this script to be killed"); _ctx.log(() => "Soft resetting. This will cause this script to be killed");
setTimeout(() => { setTimeout(() => {
installAugmentations(true); installAugmentations(true);
runAfterReset(cbScript); runAfterReset(cbScript);
@@ -221,14 +218,11 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const cbScript = _ctx.helper.string("cbScript", _cbScript); const cbScript = _ctx.helper.string("cbScript", _cbScript);
if (player.queuedAugmentations.length === 0) { if (player.queuedAugmentations.length === 0) {
workerScript.log("installAugmentations", () => "You do not have any Augmentations to be installed."); _ctx.log(() => "You do not have any Augmentations to be installed.");
return false; return false;
} }
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10);
workerScript.log( _ctx.log(() => "Installing Augmentations. This will cause this script to be killed");
"installAugmentations",
() => "Installing Augmentations. This will cause this script to be killed",
);
setTimeout(() => { setTimeout(() => {
installAugmentations(); installAugmentations();
runAfterReset(cbScript); runAfterReset(cbScript);
@@ -245,11 +239,11 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const locationName = _ctx.helper.string("locationName", _locationName); const locationName = _ctx.helper.string("locationName", _locationName);
const location = Object.values(Locations).find((l) => l.name === locationName); const location = Object.values(Locations).find((l) => l.name === locationName);
if (!location) { if (!location) {
workerScript.log("goToLocation", () => `No location named ${locationName}`); _ctx.log(() => `No location named ${locationName}`);
return false; return false;
} }
if (player.city !== location.city) { if (player.city !== location.city) {
workerScript.log("goToLocation", () => `No location named ${locationName} in ${player.city}`); _ctx.log(() => `No location named ${locationName} in ${player.city}`);
return false; return false;
} }
Router.toLocation(location); Router.toLocation(location);
@@ -265,17 +259,14 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const wasFocusing = player.focus; const wasFocusing = player.focus;
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("universityCourse", () => txt); _ctx.log(() => txt);
} }
let costMult, expMult; let costMult, expMult;
switch (universityName.toLowerCase()) { switch (universityName.toLowerCase()) {
case LocationName.AevumSummitUniversity.toLowerCase(): case LocationName.AevumSummitUniversity.toLowerCase():
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log( _ctx.log(() => `You cannot study at 'Summit University' because you are not in '${CityName.Aevum}'.`);
"universityCourse",
() => `You cannot study at 'Summit University' because you are not in '${CityName.Aevum}'.`,
);
return false; return false;
} }
player.gotoLocation(LocationName.AevumSummitUniversity); player.gotoLocation(LocationName.AevumSummitUniversity);
@@ -284,10 +275,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
break; break;
case LocationName.Sector12RothmanUniversity.toLowerCase(): case LocationName.Sector12RothmanUniversity.toLowerCase():
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( _ctx.log(() => `You cannot study at 'Rothman University' because you are not in '${CityName.Sector12}'.`);
"universityCourse",
() => `You cannot study at 'Rothman University' because you are not in '${CityName.Sector12}'.`,
);
return false; return false;
} }
player.location = LocationName.Sector12RothmanUniversity; player.location = LocationName.Sector12RothmanUniversity;
@@ -296,8 +284,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
break; break;
case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase():
if (player.city != CityName.Volhaven) { if (player.city != CityName.Volhaven) {
workerScript.log( _ctx.log(
"universityCourse",
() => `You cannot study at 'ZB Institute of Technology' because you are not in '${CityName.Volhaven}'.`, () => `You cannot study at 'ZB Institute of Technology' because you are not in '${CityName.Volhaven}'.`,
); );
return false; return false;
@@ -307,7 +294,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
expMult = 4; expMult = 4;
break; break;
default: default:
workerScript.log("universityCourse", () => `Invalid university name: '${universityName}'.`); _ctx.log(() => `Invalid university name: '${universityName}'.`);
return false; return false;
} }
@@ -332,7 +319,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
task = CONSTANTS.ClassLeadership; task = CONSTANTS.ClassLeadership;
break; break;
default: default:
workerScript.log("universityCourse", () => `Invalid class name: ${className}.`); _ctx.log(() => `Invalid class name: ${className}.`);
return false; return false;
} }
player.startClass(costMult, expMult, task); player.startClass(costMult, expMult, task);
@@ -343,7 +330,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.stopFocusing(); player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
workerScript.log("universityCourse", () => `Started ${task} at ${universityName}`); _ctx.log(() => `Started ${task} at ${universityName}`);
return true; return true;
}, },
@@ -356,14 +343,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const wasFocusing = player.focus; const wasFocusing = player.focus;
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("gymWorkout", () => txt); _ctx.log(() => txt);
} }
let costMult, expMult; let costMult, expMult;
switch (gymName.toLowerCase()) { switch (gymName.toLowerCase()) {
case LocationName.AevumCrushFitnessGym.toLowerCase(): case LocationName.AevumCrushFitnessGym.toLowerCase():
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log( _ctx.log(
"gymWorkout",
() => () =>
`You cannot workout at '${LocationName.AevumCrushFitnessGym}' because you are not in '${CityName.Aevum}'.`, `You cannot workout at '${LocationName.AevumCrushFitnessGym}' because you are not in '${CityName.Aevum}'.`,
); );
@@ -375,8 +361,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
break; break;
case LocationName.AevumSnapFitnessGym.toLowerCase(): case LocationName.AevumSnapFitnessGym.toLowerCase():
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log( _ctx.log(
"gymWorkout",
() => () =>
`You cannot workout at '${LocationName.AevumSnapFitnessGym}' because you are not in '${CityName.Aevum}'.`, `You cannot workout at '${LocationName.AevumSnapFitnessGym}' because you are not in '${CityName.Aevum}'.`,
); );
@@ -388,8 +373,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
break; break;
case LocationName.Sector12IronGym.toLowerCase(): case LocationName.Sector12IronGym.toLowerCase():
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( _ctx.log(
"gymWorkout",
() => () =>
`You cannot workout at '${LocationName.Sector12IronGym}' because you are not in '${CityName.Sector12}'.`, `You cannot workout at '${LocationName.Sector12IronGym}' because you are not in '${CityName.Sector12}'.`,
); );
@@ -401,8 +385,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
break; break;
case LocationName.Sector12PowerhouseGym.toLowerCase(): case LocationName.Sector12PowerhouseGym.toLowerCase():
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( _ctx.log(
"gymWorkout",
() => () =>
`You cannot workout at '${LocationName.Sector12PowerhouseGym}' because you are not in '${CityName.Sector12}'.`, `You cannot workout at '${LocationName.Sector12PowerhouseGym}' because you are not in '${CityName.Sector12}'.`,
); );
@@ -414,8 +397,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
break; break;
case LocationName.VolhavenMilleniumFitnessGym.toLowerCase(): case LocationName.VolhavenMilleniumFitnessGym.toLowerCase():
if (player.city != CityName.Volhaven) { if (player.city != CityName.Volhaven) {
workerScript.log( _ctx.log(
"gymWorkout",
() => () =>
`You cannot workout at '${LocationName.VolhavenMilleniumFitnessGym}' because you are not in '${CityName.Volhaven}'.`, `You cannot workout at '${LocationName.VolhavenMilleniumFitnessGym}' because you are not in '${CityName.Volhaven}'.`,
); );
@@ -426,7 +408,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
expMult = 4; expMult = 4;
break; break;
default: default:
workerScript.log("gymWorkout", () => `Invalid gym name: ${gymName}. gymWorkout() failed`); _ctx.log(() => `Invalid gym name: ${gymName}. gymWorkout() failed`);
return false; return false;
} }
@@ -448,7 +430,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility); player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility);
break; break;
default: default:
workerScript.log("gymWorkout", () => `Invalid stat: ${stat}.`); _ctx.log(() => `Invalid stat: ${stat}.`);
return false; return false;
} }
if (focus) { if (focus) {
@@ -458,7 +440,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.stopFocusing(); player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
workerScript.log("gymWorkout", () => `Started training ${stat} at ${gymName}`); _ctx.log(() => `Started training ${stat} at ${gymName}`);
return true; return true;
}, },
@@ -475,12 +457,12 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
case CityName.Ishima: case CityName.Ishima:
case CityName.Volhaven: case CityName.Volhaven:
if (player.money < CONSTANTS.TravelCost) { if (player.money < CONSTANTS.TravelCost) {
workerScript.log("travelToCity", () => "Not enough money to travel."); _ctx.log(() => "Not enough money to travel.");
return false; return false;
} }
player.loseMoney(CONSTANTS.TravelCost, "other"); player.loseMoney(CONSTANTS.TravelCost, "other");
player.city = cityName; player.city = cityName;
workerScript.log("travelToCity", () => `Traveled to ${cityName}`); _ctx.log(() => `Traveled to ${cityName}`);
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50000); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50000);
return true; return true;
default: default:
@@ -493,12 +475,12 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
_ctx.helper.checkSingularityAccess(); _ctx.helper.checkSingularityAccess();
if (player.hasTorRouter()) { if (player.hasTorRouter()) {
workerScript.log("purchaseTor", () => "You already have a TOR router!"); _ctx.log(() => "You already have a TOR router!");
return true; return true;
} }
if (player.money < CONSTANTS.TorRouterCost) { if (player.money < CONSTANTS.TorRouterCost) {
workerScript.log("purchaseTor", () => "You cannot afford to purchase a Tor router."); _ctx.log(() => "You cannot afford to purchase a Tor router.");
return false; return false;
} }
player.loseMoney(CONSTANTS.TorRouterCost, "other"); player.loseMoney(CONSTANTS.TorRouterCost, "other");
@@ -517,7 +499,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.getHomeComputer().serversOnNetwork.push(darkweb.hostname); player.getHomeComputer().serversOnNetwork.push(darkweb.hostname);
darkweb.serversOnNetwork.push(player.getHomeComputer().hostname); darkweb.serversOnNetwork.push(player.getHomeComputer().hostname);
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 500); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 500);
workerScript.log("purchaseTor", () => "You have purchased a Tor router!"); _ctx.log(() => "You have purchased a Tor router!");
return true; return true;
}, },
purchaseProgram: (_ctx: NetscriptContext) => purchaseProgram: (_ctx: NetscriptContext) =>
@@ -526,26 +508,25 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const programName = _ctx.helper.string("programName", _programName).toLowerCase(); const programName = _ctx.helper.string("programName", _programName).toLowerCase();
if (!player.hasTorRouter()) { if (!player.hasTorRouter()) {
workerScript.log("purchaseProgram", () => "You do not have the TOR router."); _ctx.log(() => "You do not have the TOR router.");
return false; return false;
} }
const item = Object.values(DarkWebItems).find((i) => i.program.toLowerCase() === programName); const item = Object.values(DarkWebItems).find((i) => i.program.toLowerCase() === programName);
if (item == null) { if (item == null) {
workerScript.log("purchaseProgram", () => `Invalid program name: '${programName}.`); _ctx.log(() => `Invalid program name: '${programName}.`);
return false; return false;
} }
if (player.money < item.price) { if (player.money < item.price) {
workerScript.log( _ctx.log(
"purchaseProgram",
() => `Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`, () => `Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`,
); );
return false; return false;
} }
if (player.hasProgram(item.program)) { if (player.hasProgram(item.program)) {
workerScript.log("purchaseProgram", () => `You already have the '${item.program}' program`); _ctx.log(() => `You already have the '${item.program}' program`);
return true; return true;
} }
@@ -557,8 +538,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
} }
player.loseMoney(item.price, "other"); player.loseMoney(item.price, "other");
workerScript.log( _ctx.log(
"purchaseProgram",
() => `You have purchased the '${item.program}' program. The new program can be found on your home computer.`, () => `You have purchased the '${item.program}' program. The new program can be found on your home computer.`,
); );
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 5000); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 5000);
@@ -629,7 +609,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
_ctx.helper.checkSingularityAccess(); _ctx.helper.checkSingularityAccess();
const baseserver = player.getCurrentServer(); const baseserver = player.getCurrentServer();
if (!(baseserver instanceof Server)) { if (!(baseserver instanceof Server)) {
workerScript.log("installBackdoor", () => "cannot backdoor this kind of server"); _ctx.log(() => "cannot backdoor this kind of server");
return Promise.resolve(); return Promise.resolve();
} }
const server = baseserver as Server; const server = baseserver as Server;
@@ -641,13 +621,12 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
throw _ctx.helper.makeRuntimeErrorMsg(canHack.msg || ""); throw _ctx.helper.makeRuntimeErrorMsg(canHack.msg || "");
} }
workerScript.log( _ctx.log(
"installBackdoor",
() => `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`, () => `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`,
); );
return netscriptDelay(installTime, workerScript).then(function () { return netscriptDelay(installTime, workerScript).then(function () {
workerScript.log("installBackdoor", () => `Successfully installed backdoor on '${server.hostname}'`); _ctx.log(() => `Successfully installed backdoor on '${server.hostname}'`);
server.backdoorInstalled = true; server.backdoorInstalled = true;
@@ -694,7 +673,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
getStats: (_ctx: NetscriptContext) => getStats: (_ctx: NetscriptContext) =>
function (): PlayerSkills { function (): PlayerSkills {
_ctx.helper.checkSingularityAccess(); _ctx.helper.checkSingularityAccess();
workerScript.log("getStats", () => `getStats is deprecated, please use getplayer`); _ctx.log(() => `getStats is deprecated, please use getplayer`);
return { return {
hacking: player.hacking, hacking: player.hacking,
@@ -709,10 +688,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
getCharacterInformation: (_ctx: NetscriptContext) => getCharacterInformation: (_ctx: NetscriptContext) =>
function (): CharacterInfo { function (): CharacterInfo {
_ctx.helper.checkSingularityAccess(); _ctx.helper.checkSingularityAccess();
workerScript.log( _ctx.log(() => `getCharacterInformation is deprecated, please use getplayer`);
"getCharacterInformation",
() => `getCharacterInformation is deprecated, please use getplayer`,
);
return { return {
bitnode: player.bitNodeN, bitnode: player.bitNodeN,
@@ -763,7 +739,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
function (): void { function (): void {
_ctx.helper.checkSingularityAccess(); _ctx.helper.checkSingularityAccess();
if (player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse) { if (player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse) {
workerScript.log("hospitalize", () => "Cannot go to the hospital because the player is busy."); _ctx.log(() => "Cannot go to the hospital because the player is busy.");
return; return;
} }
player.hospitalize(); player.hospitalize();
@@ -782,7 +758,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
Router.toTerminal(); Router.toTerminal();
} }
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("stopAction", () => txt); _ctx.log(() => txt);
return true; return true;
} }
return false; return false;
@@ -794,16 +770,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
// Check if we're at max cores // Check if we're at max cores
const homeComputer = player.getHomeComputer(); const homeComputer = player.getHomeComputer();
if (homeComputer.cpuCores >= 8) { if (homeComputer.cpuCores >= 8) {
workerScript.log("upgradeHomeCores", () => `Your home computer is at max cores.`); _ctx.log(() => `Your home computer is at max cores.`);
return false; return false;
} }
const cost = player.getUpgradeHomeCoresCost(); const cost = player.getUpgradeHomeCoresCost();
if (player.money < cost) { if (player.money < cost) {
workerScript.log( _ctx.log(() => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`);
"upgradeHomeCores",
() => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`,
);
return false; return false;
} }
@@ -811,10 +784,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.loseMoney(cost, "servers"); player.loseMoney(cost, "servers");
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2);
workerScript.log( _ctx.log(() => `Purchased an additional core for home computer! It now has ${homeComputer.cpuCores} cores.`);
"upgradeHomeCores",
() => `Purchased an additional core for home computer! It now has ${homeComputer.cpuCores} cores.`,
);
return true; return true;
}, },
getUpgradeHomeCoresCost: (_ctx: NetscriptContext) => getUpgradeHomeCoresCost: (_ctx: NetscriptContext) =>
@@ -830,16 +800,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
// Check if we're at max RAM // Check if we're at max RAM
const homeComputer = player.getHomeComputer(); const homeComputer = player.getHomeComputer();
if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) { if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) {
workerScript.log("upgradeHomeRam", () => `Your home computer is at max RAM.`); _ctx.log(() => `Your home computer is at max RAM.`);
return false; return false;
} }
const cost = player.getUpgradeHomeRamCost(); const cost = player.getUpgradeHomeRamCost();
if (player.money < cost) { if (player.money < cost) {
workerScript.log( _ctx.log(() => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`);
"upgradeHomeRam",
() => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`,
);
return false; return false;
} }
@@ -847,8 +814,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.loseMoney(cost, "servers"); player.loseMoney(cost, "servers");
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2);
workerScript.log( _ctx.log(
"upgradeHomeRam",
() => () =>
`Purchased additional RAM for home computer! It now has ${numeralWrapper.formatRAM( `Purchased additional RAM for home computer! It now has ${numeralWrapper.formatRAM(
homeComputer.maxRam, homeComputer.maxRam,
@@ -875,13 +841,13 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
// Make sure its a valid company // Make sure its a valid company
if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) { if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) {
workerScript.log("workForCompany", () => `Invalid company: '${companyName}'`); _ctx.log(() => `Invalid company: '${companyName}'`);
return false; return false;
} }
// Make sure player is actually employed at the comapny // Make sure player is actually employed at the comapny
if (!Object.keys(player.jobs).includes(companyName)) { if (!Object.keys(player.jobs).includes(companyName)) {
workerScript.log("workForCompany", () => `You do not have a job at '${companyName}'`); _ctx.log(() => `You do not have a job at '${companyName}'`);
return false; return false;
} }
@@ -889,14 +855,14 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const companyPositionName = player.jobs[companyName]; const companyPositionName = player.jobs[companyName];
const companyPosition = CompanyPositions[companyPositionName]; const companyPosition = CompanyPositions[companyPositionName];
if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) { if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) {
workerScript.log("workForCompany", () => "You do not have a job"); _ctx.log(() => "You do not have a job");
return false; return false;
} }
const wasFocused = player.focus; const wasFocused = player.focus;
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("workForCompany", () => txt); _ctx.log(() => txt);
} }
if (companyPosition.isPartTimeJob()) { if (companyPosition.isPartTimeJob()) {
@@ -912,10 +878,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.stopFocusing(); player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
workerScript.log( _ctx.log(() => `Began working at '${player.companyName}' as a '${companyPositionName}'`);
"workForCompany",
() => `Began working at '${player.companyName}' as a '${companyPositionName}'`,
);
return true; return true;
}, },
applyToCompany: (_ctx: NetscriptContext) => applyToCompany: (_ctx: NetscriptContext) =>
@@ -968,25 +931,19 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
res = player.applyForPartTimeWaiterJob(true); res = player.applyForPartTimeWaiterJob(true);
break; break;
default: default:
workerScript.log("applyToCompany", () => `Invalid job: '${field}'.`); _ctx.log(() => `Invalid job: '${field}'.`);
return false; return false;
} }
// TODO https://github.com/danielyxie/bitburner/issues/1378 // TODO https://github.com/danielyxie/bitburner/issues/1378
// The player object's applyForJob function can return string with special error messages // The player object's applyForJob function can return string with special error messages
// if (isString(res)) { // if (isString(res)) {
// workerScript.log("applyToCompany",()=> res); // _ctx.log("applyToCompany",()=> res);
// return false; // return false;
// } // }
if (res) { if (res) {
workerScript.log( _ctx.log(() => `You were offered a new job at '${companyName}' as a '${player.jobs[companyName]}'`);
"applyToCompany",
() => `You were offered a new job at '${companyName}' as a '${player.jobs[companyName]}'`,
);
} else { } else {
workerScript.log( _ctx.log(() => `You failed to get a new job/promotion at '${companyName}' in the '${field}' field.`);
"applyToCompany",
() => `You failed to get a new job/promotion at '${companyName}' in the '${field}' field.`,
);
} }
return res; return res;
}, },
@@ -1024,7 +981,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
getFaction(_ctx, facName); getFaction(_ctx, facName);
if (!player.factionInvitations.includes(facName)) { if (!player.factionInvitations.includes(facName)) {
workerScript.log("joinFaction", () => `You have not been invited by faction '${facName}'`); _ctx.log(() => `You have not been invited by faction '${facName}'`);
return false; return false;
} }
const fac = Factions[facName]; const fac = Factions[facName];
@@ -1038,7 +995,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
} }
} }
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 5); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 5);
workerScript.log("joinFaction", () => `Joined the '${facName}' faction.`); _ctx.log(() => `Joined the '${facName}' faction.`);
return true; return true;
}, },
workForFaction: (_ctx: NetscriptContext) => workForFaction: (_ctx: NetscriptContext) =>
@@ -1047,40 +1004,34 @@ 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.`); _ctx.log(() => `You can't work for '${facName}' because youre managing a gang for it`);
return false; return false;
} }
if (!player.factions.includes(facName)) { if (!player.factions.includes(facName)) {
workerScript.log("workForFaction", () => `You are not a member of '${facName}'`); _ctx.log(() => `You are not a member of '${facName}'`);
return false; return false;
} }
const wasFocusing = player.focus; const wasFocusing = player.focus;
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("workForFaction", () => txt); _ctx.log(() => 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( _ctx.log(() => `Faction '${faction.name}' do not need help with hacking contracts.`);
"workForFaction",
() => `Faction '${fac.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 +1039,16 @@ 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}'`); _ctx.log(() => `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.`); _ctx.log(() => `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 +1056,16 @@ 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}'`); _ctx.log(() => `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.`); _ctx.log(() => `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,10 +1073,10 @@ 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}'`); _ctx.log(() => `Started carrying out security work for '${faction.name}'`);
return true; return true;
default: default:
workerScript.log("workForFaction", () => `Invalid work type: '${type}`); _ctx.log(() => `Invalid work type: '${type}`);
return false; return false;
} }
return true; return true;
@@ -1158,31 +1109,28 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const amt = _ctx.helper.number("amt", _amt); const amt = _ctx.helper.number("amt", _amt);
const faction = getFaction(_ctx, facName); const faction = getFaction(_ctx, facName);
if (!player.factions.includes(faction.name)) { if (!player.factions.includes(faction.name)) {
workerScript.log("donateToFaction", () => `You can't donate to '${facName}' because you aren't a member`); _ctx.log(() => `You can't donate to '${facName}' because you aren't a member`);
return false; return false;
} }
if (player.inGang() && faction.name === player.getGangFaction().name) { if (player.inGang() && faction.name === player.getGangFaction().name) {
workerScript.log( _ctx.log(() => `You can't donate to '${facName}' because youre managing a gang for it`);
"donateToFaction", return false;
() => `You can't donate to '${facName}' because youre managing a gang for it`, }
); if (faction.name === FactionNames.ChurchOfTheMachineGod || faction.name === FactionNames.Bladeburners) {
_ctx.log(() => `You can't donate to '${facName}' because they do not accept donations`);
return false; 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}'.`); _ctx.log(() => `Invalid donation amount: '${amt}'.`);
return false; return false;
} }
if (player.money < amt) { if (player.money < amt) {
workerScript.log( _ctx.log(() => `You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${facName}'`);
"donateToFaction",
() => `You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${facName}'`,
);
return false; return false;
} }
const repNeededToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction); const repNeededToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
if (faction.favor < repNeededToDonate) { if (faction.favor < repNeededToDonate) {
workerScript.log( _ctx.log(
"donateToFaction",
() => () =>
`You do not have enough favor to donate to this faction. Have ${faction.favor}, need ${repNeededToDonate}`, `You do not have enough favor to donate to this faction. Have ${faction.favor}, need ${repNeededToDonate}`,
); );
@@ -1191,8 +1139,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const repGain = (amt / CONSTANTS.DonateMoneyToRepDivisor) * player.faction_rep_mult; const repGain = (amt / CONSTANTS.DonateMoneyToRepDivisor) * player.faction_rep_mult;
faction.playerReputation += repGain; faction.playerReputation += repGain;
player.loseMoney(amt, "other"); player.loseMoney(amt, "other");
workerScript.log( _ctx.log(
"donateToFaction",
() => () =>
`${numeralWrapper.formatMoney(amt)} donated to '${facName}' for ${numeralWrapper.formatReputation( `${numeralWrapper.formatMoney(amt)} donated to '${facName}' for ${numeralWrapper.formatReputation(
repGain, repGain,
@@ -1209,32 +1156,29 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
const wasFocusing = player.focus; const wasFocusing = player.focus;
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("createProgram", () => txt); _ctx.log(() => txt);
} }
const p = Object.values(Programs).find((p) => p.name.toLowerCase() === programName); const p = Object.values(Programs).find((p) => p.name.toLowerCase() === programName);
if (p == null) { if (p == null) {
workerScript.log("createProgram", () => `The specified program does not exist: '${programName}`); _ctx.log(() => `The specified program does not exist: '${programName}`);
return false; return false;
} }
if (player.hasProgram(p.name)) { if (player.hasProgram(p.name)) {
workerScript.log("createProgram", () => `You already have the '${p.name}' program`); _ctx.log(() => `You already have the '${p.name}' program`);
return false; return false;
} }
const create = p.create; const create = p.create;
if (create === null) { if (create === null) {
workerScript.log("createProgram", () => `You cannot create the '${p.name}' program`); _ctx.log(() => `You cannot create the '${p.name}' program`);
return false; return false;
} }
if (!create.req(player)) { if (!create.req(player)) {
workerScript.log( _ctx.log(() => `Hacking level is too low to create '${p.name}' (level ${create.level} req)`);
"createProgram",
() => `Hacking level is too low to create '${p.name}' (level ${create.level} req)`,
);
return false; return false;
} }
@@ -1246,7 +1190,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
player.stopFocusing(); player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
workerScript.log("createProgram", () => `Began creating program: '${programName}'`); _ctx.log(() => `Began creating program: '${programName}'`);
return true; return true;
}, },
commitCrime: (_ctx: NetscriptContext) => commitCrime: (_ctx: NetscriptContext) =>
@@ -1256,7 +1200,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("commitCrime", () => txt); _ctx.log(() => txt);
} }
// Set Location to slums // Set Location to slums
@@ -1267,7 +1211,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
// couldn't find crime // couldn't find crime
throw _ctx.helper.makeRuntimeErrorMsg(`Invalid crime: '${crimeRoughName}'`); throw _ctx.helper.makeRuntimeErrorMsg(`Invalid crime: '${crimeRoughName}'`);
} }
workerScript.log("commitCrime", () => `Attempting to commit ${crime.name}...`); _ctx.log(() => `Attempting to commit ${crime.name}...`);
return crime.commit(Router, player, 1, workerScript); return crime.commit(Router, player, 1, workerScript);
}, },
getCrimeChance: (_ctx: NetscriptContext) => getCrimeChance: (_ctx: NetscriptContext) =>
@@ -1300,7 +1244,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
// If we don't have Tor, log it and return [] (empty list) // If we don't have Tor, log it and return [] (empty list)
if (!player.hasTorRouter()) { if (!player.hasTorRouter()) {
workerScript.log("getDarkwebPrograms", () => "You do not have the TOR router."); _ctx.log(() => "You do not have the TOR router.");
return []; return [];
} }
return Object.values(DarkWebItems).map((p) => p.program); return Object.values(DarkWebItems).map((p) => p.program);
@@ -1312,7 +1256,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
// If we don't have Tor, log it and return -1 // If we don't have Tor, log it and return -1
if (!player.hasTorRouter()) { if (!player.hasTorRouter()) {
workerScript.log("getDarkwebProgramCost", () => "You do not have the TOR router."); _ctx.log(() => "You do not have the TOR router.");
// returning -1 rather than throwing an error to be consistent with purchaseProgram // returning -1 rather than throwing an error to be consistent with purchaseProgram
// which returns false if tor has // which returns false if tor has
return -1; return -1;
@@ -1332,7 +1276,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
} }
if (player.hasProgram(item.program)) { if (player.hasProgram(item.program)) {
workerScript.log("getDarkwebProgramCost", () => `You already have the '${item.program}' program`); _ctx.log(() => `You already have the '${item.program}' program`);
return 0; return 0;
} }
return item.price; return item.price;

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");

View File

@@ -358,7 +358,6 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
}, },
purchase4SMarketData: function (): boolean { purchase4SMarketData: function (): boolean {
updateRam("purchase4SMarketData"); updateRam("purchase4SMarketData");
checkTixApiAccess("purchase4SMarketData");
if (player.has4SData) { if (player.has4SData) {
workerScript.log("stock.purchase4SMarketData", () => "Already purchased 4S Market Data."); workerScript.log("stock.purchase4SMarketData", () => "Already purchased 4S Market Data.");

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
@@ -354,7 +355,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;

View File

@@ -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;

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;
} }
/** /**

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);
} }
} }

View File

@@ -3,8 +3,9 @@ import Typography from "@mui/material/Typography";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles"; import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import Paper from "@mui/material/Paper";
import Popper from "@mui/material/Popper";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
import Tooltip from "@mui/material/Tooltip";
import { KEY } from "../../utils/helpers/keyCodes"; import { KEY } from "../../utils/helpers/keyCodes";
import { ITerminal } from "../ITerminal"; import { ITerminal } from "../ITerminal";
@@ -376,46 +377,40 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
return ( return (
<> <>
<Tooltip <TextField
title={ fullWidth
possibilities.length > 0 ? ( color={terminal.action === null ? "primary" : "secondary"}
<> autoFocus
<Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}> disabled={terminal.action !== null}
Possible autocomplete candidate: autoComplete="off"
</Typography> value={value}
<Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}> classes={{ root: classes.textfield }}
{possibilities.join(" ")} onChange={handleValueChange}
</Typography> inputRef={terminalInput}
</> InputProps={{
) : ( // for players to hook in
"" id: "terminal-input",
) className: classes.input,
} startAdornment: (
> <Typography color={terminal.action === null ? "primary" : "secondary"} flexShrink={0}>
<TextField [{player.getCurrentServer().hostname}&nbsp;~{terminal.cwd()}]&gt;&nbsp;
fullWidth </Typography>
color={terminal.action === null ? "primary" : "secondary"} ),
autoFocus spellCheck: false,
disabled={terminal.action !== null} onBlur: () => setPossibilities([]),
autoComplete="off" onKeyDown: onKeyDown,
value={value} }}
classes={{ root: classes.textfield }} ></TextField>
onChange={handleValueChange} <Popper open={possibilities.length > 0} anchorEl={terminalInput.current} placement={"top-end"}>
inputRef={terminalInput} <Paper sx={{ m: 1, p: 2 }}>
InputProps={{ <Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}>
// for players to hook in Possible autocomplete candidates:
id: "terminal-input", </Typography>
className: classes.input, <Typography classes={{ root: classes.preformatted }} color={"primary"} paragraph={false}>
startAdornment: ( {possibilities.join(" ")}
<Typography color={terminal.action === null ? "primary" : "secondary"} flexShrink={0}> </Typography>
[{player.getCurrentServer().hostname}&nbsp;~{terminal.cwd()}]&gt;&nbsp; </Paper>
</Typography> </Popper>
),
spellCheck: false,
onKeyDown: onKeyDown,
}}
></TextField>
</Tooltip>
</> </>
); );
} }

View File

@@ -1,7 +1,7 @@
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomInt } from "../utils/helpers/getRandomInt";
import { MinHeap } from "../utils/Heap"; import { MinHeap } from "../utils/Heap";
import { HammingEncode, HammingDecode } from "../utils/HammingCodeTools"; // import { HammingEncode, HammingDecode } from "../utils/HammingCodeTools";
/* tslint:disable:completed-docs no-magic-numbers arrow-return-shorthand */ /* tslint:disable:completed-docs no-magic-numbers arrow-return-shorthand */
/* Function that generates a valid 'data' for a contract type */ /* Function that generates a valid 'data' for a contract type */
@@ -1126,7 +1126,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
for (let i = 0; i < sanitizedPlayerAnsArr.length; ++i) { for (let i = 0; i < sanitizedPlayerAnsArr.length; ++i) {
sanitizedPlayerAnsArr[i] = removeQuotesFromString(sanitizedPlayerAnsArr[i]).replace(/\s/g, ""); sanitizedPlayerAnsArr[i] = removeQuotesFromString(sanitizedPlayerAnsArr[i]).replace(/\s/g, "");
} }
if (sanitizedPlayerAnsArr.length !== res.length) { if (sanitizedPlayerAnsArr.length !== res.length) {
return false; return false;
} }
@@ -1247,7 +1247,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
return true; return true;
}, },
}, } /*
{ {
name: "HammingCodes: Integer to encoded Binary", name: "HammingCodes: Integer to encoded Binary",
numTries: 10, numTries: 10,
@@ -1306,5 +1306,5 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
solver: (data: string, ans: string): boolean => { solver: (data: string, ans: string): boolean => {
return parseInt(ans, 10) === HammingDecode(data); return parseInt(ans, 10) === HammingDecode(data);
}, },
}, },*/,
]; ];

View File

@@ -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"];