From 0e9d7450c9eb4ce74fca77cc5c08ec07b1bd18d0 Mon Sep 17 00:00:00 2001
From: Olivier Gagnon {createProgressBarText({progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}
+ Required Rank: {formatNumber(props.action.reqdRank, 0)}
+
+ Estimated Success Chance: {formatNumber(estimatedSuccessChance*100, 1)}% {props.action.isStealth?stealthIcon:<>>}{props.action.isKill?killIcon:<>>}
+
- Black Operations (Black Ops) are special, one-time covert operations. Each Black Op must be unlocked successively by completing the one before it. {createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})} {createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})} {createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})} Level: {currentLevel} MAX LEVEL Skill Points required: {formatNumber(pointCost, 0)}
+ Black Operations (Black Ops) are special, one-time covert operations.
+ Each Black Op must be unlocked successively by completing
+ the one before it.
+
+ Complete contracts in order to increase your Bladeburner rank and earn money.
+ Failing a contract will cause you to lose HP, which can lead to hospitalization.
+
+ These are generic actions that will assist you in your Bladeburner
+ duties. They will not affect your Bladeburner rank in any way.
+
+ Carry out operations for the Bladeburner division.
+ Failing an operation will reduce your Bladeburner rank. It will also
+ cause you to lose HP, which can lead to hospitalization. In general,
+ operations are harder and more punishing than contracts,
+ but are also more rewarding.
+
+ You will gain one skill point every {BladeburnerConstants.RanksPerSkillPoint} ranks.
+
+ Rank: {formatNumber(props.bladeburner.rank, 2)}
" + action.desc + "
",
- }));
- el.appendChild(createElement("p", {
- display:"block", color:hasReqdRank ? "white" : "red",
- innerHTML:"Required Rank: " + formatNumber(action.reqdRank, 0) + "
",
- }));
- el.appendChild(createElement("p", {
- display:"inline-block",
- innerHTML:`Estimated Success Chance: ${formatNumber(estimatedSuccessChance*100, 1)}% ${action.isStealth?stealthIcon:''}${action.isKill?killIcon:''}\n` +
- "Time Required: " + convertTimeMsToTimeElapsedString(actionTime*1000),
- }))
+ ReactDOM.unmountComponentAtNode(el);
+ ReactDOM.render({props.action.name} (COMPLETED)
);
+ }
+
+ const isActive = props.bladeburner.action.type === ActionTypes["BlackOperation"] && props.action.name === props.bladeburner.action.name;
+ const estimatedSuccessChance = props.action.getSuccessChance(props.bladeburner, {est:true});
+ const actionTime = props.action.getActionTime(props.bladeburner);
+ const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
+ const computedActionTimeCurrent = Math.min(props.bladeburner.actionTimeCurrent+props.bladeburner.actionTimeOverflow, props.bladeburner.actionTimeToComplete);
+
+ function onStart() {
+ props.bladeburner.action.type = ActionTypes.BlackOperation;
+ props.bladeburner.action.name = props.action.name;
+ props.bladeburner.startAction(props.bladeburner.action);
+ props.bladeburner.updateActionAndSkillsContent();
+ }
+
+ function onTeam() {
+ // TODO(hydroflame): this needs some changes that are in the Gang conversion.
+ // var popupId = "bladeburner-operation-set-team-size-popup";
+ // var txt = createElement("p", {
+ // innerText:"Enter the amount of team members you would like to take on this " +
+ // "BlackOp. If you do not have the specified number of team members, " +
+ // "then as many as possible will be used. Note that team members may " +
+ // "be lost during operations.",
+
+ // });
+ // var input = createElement("input", {
+ // type:"number", placeholder: "Team size", class: "text-input",
+ // });
+ // var setBtn = createElement("a", {
+ // innerText:"Confirm", class:"a-link-button",
+ // clickListener:() => {
+ // var num = Math.round(parseFloat(input.value));
+ // if (isNaN(num) || num < 0) {
+ // dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
+ // } else {
+ // action.teamCount = num;
+ // this.updateBlackOpsUIElement(el, action);
+ // }
+ // removeElementById(popupId);
+ // return false;
+ // },
+ // });
+ // var cancelBtn = createElement("a", {
+ // innerText:"Cancel", class:"a-link-button",
+ // clickListener:() => {
+ // removeElementById(popupId);
+ // return false;
+ // },
+ // });
+ // createPopup(popupId, [txt, input, setBtn, cancelBtn]);
+ // input.focus();
+ }
+
+ return (<>
+
+ {isActive ?
+ <>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})> :
+ <>{props.action.name}>
+ }
+
+ {isActive ?
+
+
+
+
+
+
+
+ Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}
+
" +
- "Your ultimate goal to climb through the ranks of Bladeburners is to complete " +
- "all of the Black Ops.
" +
- "Like normal operations, you may use a team for Black Ops. Failing " +
- "a black op will incur heavy HP and rank losses.";
-
-// Put Black Operations in sequence of required rank
-var blackops = [];
-for (var blackopName in BlackOperations) {
- if (BlackOperations.hasOwnProperty(blackopName)) {
- blackops.push(BlackOperations[blackopName]);
- }
-}
-blackops.sort(function(a, b) {
- return (a.reqdRank - b.reqdRank);
-});
-
-for (var i = blackops.length-1; i >= 0 ; --i) {
- if (this.blackops[[blackops[i].name]] == null && i !== 0 && this.blackops[[blackops[i-1].name]] == null) {continue;} // If this one nor the next are completed then this isn't unlocked yet.
- DomElems.blackops[blackops[i].name] = createElement("div", {
- class:"bladeburner-action", name:blackops[i].name
- });
- DomElems.actionsAndSkillsList.appendChild(DomElems.blackops[blackops[i].name]);
-}
-*/
-
-
-
-import * as React from "react";
-
-export function BlackOperationsPage(): React.ReactElement {
- // Put Black Operations in sequence of required rank
- const blackops = [];
- for (const name in BlackOperations) {
- if (BlackOperations.hasOwnProperty(name)) {
- blackops.push(BlackOperations[name]);
- }
- }
- blackops.sort(function(a, b) {
- return (a.reqdRank - b.reqdRank);
- });
-
- return (
- Your ultimate goal to climb through the ranks of Bladeburners is to complete all of the Black Ops.
- Like normal operations, you may use a team for Black Ops. Failing a black op will incur heavy HP and rank losses.
+ {isActive ?
+ <>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})> :
+ <>{props.action.name}>
+ }
+
+ {isActive ?
+
+
+
+
+ {props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel)} successes needed for next level
+
+ Level: {props.action.level} / {props.action.maxLevel}
+
+
+ {isActive && (WARNING: changing the level will restart the Operation)}
+ ↑
+
+
+ {isActive && (WARNING: changing the level will restart the Operation)}
+ ↓
+
+
+
+
+
+
+
+Estimated success chance: {formatNumber(estimatedSuccessChance*100, 1)}% {props.action.isStealth?stealthIcon:<>>}${props.action.isKill?killIcon:<>>}
+Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}
+Contracts remaining: {Math.floor(props.action.count)}
+Successes: {props.action.successes}
+Failures: {props.action.failures}
+
+
+
+ >);
+}
+
+/*
+
+// Autolevel Checkbox
+el.appendChild(createElement("br"));
+var autolevelCheckboxId = "bladeburner-" + action.name + "-autolevel-checkbox";
+el.appendChild(createElement("label", {
+ for:autolevelCheckboxId, innerText:"Autolevel: ",color:"white",
+ tooltip:"Automatically increase contract level when possible",
+}));
+
+const checkboxInput = createElement("input", {
+ type:"checkbox",
+ id: autolevelCheckboxId,
+ checked: action.autoLevel,
+ changeListener: () => {
+ action.autoLevel = checkboxInput.checked;
+ },
+});
+
+el.appendChild(checkboxInput);
+
+*/
\ No newline at end of file
diff --git a/src/Bladeburner/ui/GeneralActionElem.tsx b/src/Bladeburner/ui/GeneralActionElem.tsx
new file mode 100644
index 000000000..93b7b1e2d
--- /dev/null
+++ b/src/Bladeburner/ui/GeneralActionElem.tsx
@@ -0,0 +1,49 @@
+import React, { useState } from "react";
+import { ActionTypes } from "../data/ActionTypes";
+import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
+import {
+ formatNumber,
+ convertTimeMsToTimeElapsedString,
+} from "../../../utils/StringHelperFunctions";
+import { stealthIcon, killIcon } from "../data/Icons";
+import { BladeburnerConstants } from "../data/Constants";
+
+interface IProps {
+ bladeburner: any;
+ action: any;
+}
+
+export function GeneralActionElem(props: IProps): React.ReactElement {
+ const setRerender = useState(false)[1];
+ const isActive = props.action.name === props.bladeburner.action.name;
+ const computedActionTimeCurrent = Math.min(props.bladeburner.actionTimeCurrent+props.bladeburner.actionTimeOverflow, props.bladeburner.actionTimeToComplete);
+
+ function onStart() {
+ props.bladeburner.action.type = ActionTypes[(props.action.name as string)];
+ props.bladeburner.action.name = props.action.name;
+ props.bladeburner.startAction(props.bladeburner.action);
+ setRerender(old => !old);
+ }
+
+ return (<>
+
+ {isActive ?
+ <>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})> :
+ <>{props.action.name}>
+ }
+
+ {isActive ?
+
+
+
+ >);
+}
\ No newline at end of file
diff --git a/src/Bladeburner/ui/OperationElem.tsx b/src/Bladeburner/ui/OperationElem.tsx
new file mode 100644
index 000000000..1dabeb650
--- /dev/null
+++ b/src/Bladeburner/ui/OperationElem.tsx
@@ -0,0 +1,157 @@
+import React, { useState } from "react";
+import { ActionTypes } from "../data/ActionTypes";
+import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
+import {
+ formatNumber,
+ convertTimeMsToTimeElapsedString,
+} from "../../../utils/StringHelperFunctions";
+import { stealthIcon, killIcon } from "../data/Icons";
+import { BladeburnerConstants } from "../data/Constants";
+
+interface IProps {
+ bladeburner: any;
+ action: any;
+}
+
+export function OperationElem(props: IProps): React.ReactElement {
+ const setRerender = useState(false)[1];
+ const isActive = props.bladeburner.action.type === ActionTypes["Operation"] && props.action.name === props.bladeburner.action.name;
+ const estimatedSuccessChance = props.action.getSuccessChance(props.bladeburner, {est:true});
+ const computedActionTimeCurrent = Math.min(props.bladeburner.actionTimeCurrent+props.bladeburner.actionTimeOverflow,props.bladeburner.actionTimeToComplete);
+ const maxLevel = (props.action.level >= props.action.maxLevel);
+ const actionTime = props.action.getActionTime(props.bladeburner);
+ const autolevelCheckboxId = `bladeburner-${props.action.name}-autolevel-checkbox`;
+
+ function onStart() {
+ props.bladeburner.action.type = ActionTypes.Operation;
+ props.bladeburner.action.name = props.action.name;
+ props.bladeburner.startAction(props.bladeburner.action);
+ props.bladeburner.updateActionAndSkillsContent();
+ setRerender(old => !old);
+ }
+
+ function onTeam() {
+ // var popupId = "bladeburner-operation-set-team-size-popup";
+ // var txt = createElement("p", {
+ // innerText:"Enter the amount of team members you would like to take on these " +
+ // "operations. If you do not have the specified number of team members, " +
+ // "then as many as possible will be used. Note that team members may " +
+ // "be lost during operations.",
+
+ // });
+ // var input = createElement("input", {
+ // type:"number", placeholder: "Team size", class: "text-input",
+ // });
+ // var setBtn = createElement("a", {
+ // innerText:"Confirm", class:"a-link-button",
+ // clickListener:() => {
+ // var num = Math.round(parseFloat(input.value));
+ // if (isNaN(num) || num < 0) {
+ // dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
+ // } else {
+ // action.teamCount = num;
+ // this.updateOperationsUIElement(el, action);
+ // }
+ // removeElementById(popupId);
+ // return false;
+ // },
+ // });
+ // var cancelBtn = createElement("a", {
+ // innerText:"Cancel", class:"a-link-button",
+ // clickListener:() => {
+ // removeElementById(popupId);
+ // return false;
+ // },
+ // });
+ // createPopup(popupId, [txt, input, setBtn, cancelBtn]);
+ // input.focus();
+ }
+
+ function increaseLevel() {
+ ++props.action.level;
+ if (isActive) props.bladeburner.startAction(props.bladeburner.action);
+ setRerender(old => !old);
+ }
+
+ function decreaseLevel() {
+ --props.action.level;
+ if (isActive) props.bladeburner.startAction(props.bladeburner.action);
+ setRerender(old => !old);
+ }
+
+ function onAutolevel(event: React.ChangeEvent
+ {isActive ?
+ <>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})> :
+ <>{props.action.name}>
+ }
+
+ {isActive ?
+
+
+
+
+ {props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel)} successes needed for next level
+
+ Level: {props.action.level} / {props.action.maxLevel}
+
+
+ {isActive && (WARNING: changing the level will restart the Operation)}
+ ↑
+
+
+ {isActive && (WARNING: changing the level will restart the Operation)}
+ ↓
+
+
+
+
+
+
+
+Estimated success chance: {formatNumber(estimatedSuccessChance*100, 1)}% {props.action.isStealth?stealthIcon:<>>}{props.action.isKill?killIcon:<>>}
+Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}
+Operations remaining: {Math.floor(props.action.count)}
+Successes: {props.action.successes}
+Failures: {props.action.failures}
+
+
+
+ >);
+}
diff --git a/src/Bladeburner/ui/SkillElem.tsx b/src/Bladeburner/ui/SkillElem.tsx
new file mode 100644
index 000000000..af7ebfbf1
--- /dev/null
+++ b/src/Bladeburner/ui/SkillElem.tsx
@@ -0,0 +1,46 @@
+import * as React from "react";
+import { CopyableText } from "../../ui/React/CopyableText";
+import { formatNumber } from "../../../utils/StringHelperFunctions";
+
+interface IProps {
+ skill: any;
+ bladeburner: any;
+}
+
+export function SkillElem(props: IProps): React.ReactElement {
+ const skillName = props.skill.name;
+ let currentLevel = 0;
+ if (props.bladeburner.skills[skillName] && !isNaN(props.bladeburner.skills[skillName])) {
+ currentLevel = props.bladeburner.skills[skillName];
+ }
+ const pointCost = props.skill.calculateCost(currentLevel);
+
+ const canLevel = props.bladeburner.skillPoints >= pointCost;
+ const maxLvl = props.skill.maxLvl ? currentLevel >= props.skill.maxLvl : false;
+
+ function onClick() {
+ if (props.bladeburner.skillPoints < pointCost) return;
+ props.bladeburner.skillPoints -= pointCost;
+ props.bladeburner.upgradeSkill(props.skill);
+ props.bladeburner.createActionAndSkillsContent();
+ }
+
+ return (<>
+
+
+
+ Level
+
+
+
+
" +
- "You can unlock higher-level contracts by successfully completing them. " +
- "Higher-level contracts are more difficult, but grant more rank, experience, and money.";
-
- for (var contractName in this.contracts) {
- if (this.contracts.hasOwnProperty(contractName)) {
- DomElems.contracts[contractName] = createElement("div", {
- class:"bladeburner-action", name:contractName,
- });
- DomElems.actionsAndSkillsList.appendChild(DomElems.contracts[contractName]);
- }
- }
-}
-
-Bladeburner.prototype.createOperationsContent = function() {
- if (DomElems.actionsAndSkillsList == null || DomElems.actionsAndSkillsDesc == null) {
- throw new Error("Bladeburner.createOperationsContent called with either " +
- "DomElems.actionsAndSkillsList or DomElems.actionsAndSkillsDesc = null");
- }
-
- DomElems.actionsAndSkillsDesc.innerHTML =
- "Carry out operations for the Bladeburner division. " +
- "Failing an operation will reduce your Bladeburner rank. It will also " +
- "cause you to lose HP, which can lead to hospitalization. In general, " +
- "operations are harder and more punishing than contracts, " +
- "but are also more rewarding.
" +
- "Operations can affect the chaos level and Synthoid population of your " +
- "current city. The exact effects vary between different Operations.
" +
- "For operations, you can use a team. You must first recruit team members. " +
- "Having a larger team will improves your chances of success.
" +
- "You can unlock higher-level operations by successfully completing them. " +
- "Higher-level operations are more difficult, but grant more rank and experience.";
-
- for (var operationName in this.operations) {
- if (this.operations.hasOwnProperty(operationName)) {
- DomElems.operations[operationName] = createElement("div", {
- class:"bladeburner-action", name:operationName,
- });
- DomElems.actionsAndSkillsList.appendChild(DomElems.operations[operationName]);
- }
- }
-}
-
-Bladeburner.prototype.createBlackOpsContent = function() {
-
- if (DomElems.actionsAndSkillsList == null || DomElems.actionsAndSkillsDesc == null) {
- throw new Error("Bladeburner.createBlackOpsContent called with either " +
- "DomElems.actionsAndSkillsList or DomElems.actionsAndSkillsDesc = null");
- }
-
-
- DomElems.actionsAndSkillsDesc.innerHTML =
- "Black Operations (Black Ops) are special, one-time covert operations. " +
- "Each Black Op must be unlocked successively by completing " +
- "the one before it.
" +
- "Your ultimate goal to climb through the ranks of Bladeburners is to complete " +
- "all of the Black Ops.
" +
- "Like normal operations, you may use a team for Black Ops. Failing " +
- "a black op will incur heavy HP and rank losses.";
-
- // Put Black Operations in sequence of required rank
- var blackops = [];
- for (var blackopName in BlackOperations) {
- if (BlackOperations.hasOwnProperty(blackopName)) {
- blackops.push(BlackOperations[blackopName]);
- }
- }
- blackops.sort(function(a, b) {
- return (a.reqdRank - b.reqdRank);
- });
-
- for (var i = blackops.length-1; i >= 0 ; --i) {
- if (this.blackops[[blackops[i].name]] == null && i !== 0 && this.blackops[[blackops[i-1].name]] == null) {continue;} // If this one nor the next are completed then this isn't unlocked yet.
- DomElems.blackops[blackops[i].name] = createElement("div", {
- class:"bladeburner-action", name:blackops[i].name,
- });
- DomElems.actionsAndSkillsList.appendChild(DomElems.blackops[blackops[i].name]);
- }
-}
-
-Bladeburner.prototype.createSkillsContent = function() {
- if (DomElems.actionsAndSkillsList == null || DomElems.actionsAndSkillsDesc == null) {
- throw new Error("Bladeburner.createSkillsContent called with either " +
- "DomElems.actionsAndSkillsList or DomElems.actionsAndSkillsDesc = null");
- }
-
- // Display Current multipliers
- DomElems.actionsAndSkillsDesc.innerHTML =
- "You will gain one skill point every " + BladeburnerConstants.RanksPerSkillPoint + " ranks.
" +
- "Note that when upgrading a skill, the benefit for that skill is additive. " +
- "However, the effects of different skills with each other is multiplicative.
"
- var multKeys = Object.keys(this.skillMultipliers);
- for (var i = 0; i < multKeys.length; ++i) {
- var mult = this.skillMultipliers[multKeys[i]];
- if (mult && mult !== 1) {
- mult = formatNumber(mult, 3);
- switch(multKeys[i]) {
- case "successChanceAll":
- DomElems.actionsAndSkillsDesc.innerHTML += "Total Success Chance: x" + mult + "
";
- break;
- case "successChanceStealth":
- DomElems.actionsAndSkillsDesc.innerHTML += "Stealth Success Chance: x" + mult + "
";
- break;
- case "successChanceKill":
- DomElems.actionsAndSkillsDesc.innerHTML += "Retirement Success Chance: x" + mult + "
";
- break;
- case "successChanceContract":
- DomElems.actionsAndSkillsDesc.innerHTML += "Contract Success Chance: x" + mult + "
";
- break;
- case "successChanceOperation":
- DomElems.actionsAndSkillsDesc.innerHTML += "Operation Success Chance: x" + mult + "
";
- break;
- case "successChanceEstimate":
- DomElems.actionsAndSkillsDesc.innerHTML += "Synthoid Data Estimate: x" + mult + "
";
- break;
- case "actionTime":
- DomElems.actionsAndSkillsDesc.innerHTML += "Action Time: x" + mult + "
";
- break;
- case "effHack":
- DomElems.actionsAndSkillsDesc.innerHTML += "Hacking Skill: x" + mult + "
";
- break;
- case "effStr":
- DomElems.actionsAndSkillsDesc.innerHTML += "Strength: x" + mult + "
";
- break;
- case "effDef":
- DomElems.actionsAndSkillsDesc.innerHTML += "Defense: x" + mult + "
";
- break;
- case "effDex":
- DomElems.actionsAndSkillsDesc.innerHTML += "Dexterity: x" + mult + "
";
- break;
- case "effAgi":
- DomElems.actionsAndSkillsDesc.innerHTML += "Agility: x" + mult + "
";
- break;
- case "effCha":
- DomElems.actionsAndSkillsDesc.innerHTML += "Charisma: x" + mult + "
";
- break;
- case "effInt":
- DomElems.actionsAndSkillsDesc.innerHTML += "Intelligence: x" + mult + "
";
- break;
- case "stamina":
- DomElems.actionsAndSkillsDesc.innerHTML += "Stamina: x" + mult + "
";
- break;
- case "money":
- DomElems.actionsAndSkillsDesc.innerHTML += "Contract Money: x" + mult + "
";
- break;
- case "expGain":
- DomElems.actionsAndSkillsDesc.innerHTML += "Exp Gain: x" + mult + "
";
- break;
- default:
- console.warn(`Unrecognized SkillMult Key: ${multKeys[i]}`);
- break;
- }
- }
- }
-
- // Skill Points
- DomElems.skillPointsDisplay = createElement("p", {
- innerHTML:"
Skill Points: " + formatNumber(this.skillPoints, 0) + "",
- });
- DomElems.actionAndSkillsDiv.appendChild(DomElems.skillPointsDisplay);
-
- // UI Element for each skill
- for (var skillName in Skills) {
- if (Skills.hasOwnProperty(skillName)) {
- DomElems.skills[skillName] = createElement("div", {
- class:"bladeburner-action", name:skillName,
- });
- DomElems.actionsAndSkillsList.appendChild(DomElems.skills[skillName]);
- }
- }
-}
-
Bladeburner.prototype.updateContent = function() {
this.updateOverviewContent();
- this.updateActionAndSkillsContent();
}
Bladeburner.prototype.updateOverviewContent = function() {
- if (!routing.isOn(Page.Bladeburner)) {return;}
- DomElems.overviewRank.childNodes[0].nodeValue = "Rank: " + formatNumber(this.rank, 2);
- DomElems.overviewStamina.innerText = "Stamina: " + formatNumber(this.stamina, 3) + " / " + formatNumber(this.maxStamina, 3);
- ReactDOM.render(<>
- Stamina Penalty: {formatNumber((1-this.calculateStaminaPenalty())*100, 1)}%
- Team Size: {formatNumber(this.teamSize, 0)}
- Team Members Lost: {formatNumber(this.teamLost, 0)}
- Num Times Hospitalized: {this.numHosp}
- Money Lost From Hospitalizations: {Money(this.moneyLost)}
- Current City: {this.city}
- >, DomElems.overviewGen1);
-
- DomElems.overviewEstPop.childNodes[0].nodeValue = "Est. Synthoid Population: " + numeralWrapper.formatPopulation(this.getCurrentCity().popEst);
- DomElems.overviewEstComms.childNodes[0].nodeValue = "Est. Synthoid Communities: " + formatNumber(this.getCurrentCity().comms, 0);
- DomElems.overviewChaos.childNodes[0].nodeValue = "City Chaos: " + formatNumber(this.getCurrentCity().chaos);
- DomElems.overviewSkillPoints.innerText = "Skill Points: " + formatNumber(this.skillPoints, 0);
- DomElems.overviewBonusTime.childNodes[0].nodeValue = "Bonus time: " + convertTimeMsToTimeElapsedString(this.storedCycles/BladeburnerConstants.CyclesPerSecond*1000);
- ReactDOM.render(StatsTable([
- ["Aug. Success Chance mult: ", formatNumber(Player.bladeburner_success_chance_mult*100, 1) + "%"],
- ["Aug. Max Stamina mult: ", formatNumber(Player.bladeburner_max_stamina_mult*100, 1) + "%"],
- ["Aug. Stamina Gain mult: ", formatNumber(Player.bladeburner_stamina_gain_mult*100, 1) + "%"],
- ["Aug. Field Analysis mult: ", formatNumber(Player.bladeburner_analysis_mult*100, 1) + "%"],
- ]), DomElems.overviewAugMults);
+ if (!routing.isOn(Page.Bladeburner)) return;
+ ReactDOM.render(
Skill Points: " + formatNumber(this.skillPoints, 0) + "";
-
- var skillElems = Object.keys(DomElems.skills);
- for (var i = 0; i < skillElems.length; ++i) {
- var skillElem = DomElems.skills[skillElems[i]];
- var name = skillElem.name;
- var skill = Skills[name];
- if (skill == null) {
- throw new Error("Could not find Skill " + name + " in Bladeburner.updateActionAndSkillsContent()");
- }
- this.updateSkillsUIElement(skillElem, skill);
- }
- break;
- default:
- throw new Error("Invalid value for DomElems.currentTab in Bladeburner.createActionAndSkillsContent");
- }
-}
-
-Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
- ReactDOM.unmountComponentAtNode(el);
- ReactDOM.render(
+
+ Your ultimate goal to climb through the ranks of Bladeburners is to complete
+ all of the Black Ops.
+
+
+ Like normal operations, you may use a team for Black Ops. Failing
+ a black op will incur heavy HP and rank losses.
+
+
+ You can unlock higher-level contracts by successfully completing them.
+ Higher-level contracts are more difficult, but grant more rank, experience, and money.
+
+
+ Operations can affect the chaos level and Synthoid population of your
+ current city. The exact effects vary between different Operations.
+
+
+ For operations, you can use a team. You must first recruit team members.
+ Having a larger team will improves your chances of success.
+
+
+ You can unlock higher-level operations by successfully completing them.
+ Higher-level operations are more difficult, but grant more rank and experience.
+
+
+ Note that when upgrading a skill, the benefit for that skill is additive.
+ However, the effects of different skills with each other is multiplicative.
+
+
+
>}
+ {valid(mults["successChanceStealth"]) && <>Stealth Success Chance: x{formatNumber(mults["successChanceStealth"], 3)}
>}
+ {valid(mults["successChanceKill"]) && <>Retirement Success Chance: x{formatNumber(mults["successChanceKill"], 3)}
>}
+ {valid(mults["successChanceContract"]) && <>Contract Success Chance: x{formatNumber(mults["successChanceContract"], 3)}
>}
+ {valid(mults["successChanceOperation"]) && <>Operation Success Chance: x{formatNumber(mults["successChanceOperation"], 3)}
>}
+ {valid(mults["successChanceEstimate"]) && <>Synthoid Data Estimate: x{formatNumber(mults["successChanceEstimate"], 3)}
>}
+ {valid(mults["actionTime"]) && <>Action Time: x{formatNumber(mults["actionTime"], 3)}
>}
+ {valid(mults["effHack"]) && <>Hacking Skill: x{formatNumber(mults["effHack"], 3)}
>}
+ {valid(mults["effStr"]) && <>Strength: x{formatNumber(mults["effStr"], 3)}
>}
+ {valid(mults["effDef"]) && <>Defense: x{formatNumber(mults["effDef"], 3)}
>}
+ {valid(mults["effDex"]) && <>Dexterity: x{formatNumber(mults["effDex"], 3)}
>}
+ {valid(mults["effAgi"]) && <>Agility: x{formatNumber(mults["effAgi"], 3)}
>}
+ {valid(mults["effCha"]) && <>Charisma: x{formatNumber(mults["effCha"], 3)}
>}
+ {valid(mults["effInt"]) && <>Intelligence: x{formatNumber(mults["effInt"], 3)}
>}
+ {valid(mults["stamina"]) && <>Stamina: x{formatNumber(mults["stamina"], 3)}
>}
+ {valid(mults["money"]) && <>Contract Money: x{formatNumber(mults["money"], 3)}
>}
+ {valid(mults["expGain"]) && <>Exp Gain: x{formatNumber(mults["expGain"], 3)}
>}
+
+
" +
+ "Your max stamina is determined primarily by your agility stat.
" +
+ "Your stamina gain rate is determined by both your agility and your " +
+ "max stamina. Higher max stamina leads to a higher gain rate.
" +
+ "Once your " +
+ "stamina falls below 50% of its max value, it begins to negatively " +
+ "affect the success rate of your contracts/operations. This penalty " +
+ "is shown in the overview panel. If the penalty is 15%, then this means " +
+ "your success rate would be multipled by 85% (100 - 15).
" +
+ "Your max stamina and stamina gain rate can also be increased by " +
+ "training, or through skills and Augmentation upgrades.");
+ }
+
+ function openPopulationHelp(): void {
+ dialogBoxCreate("The success rate of your contracts/operations depends on " +
+ "the population of Synthoids in your current city. " +
+ "The success rate that is shown to you is only an estimate, " +
+ "and it is based on your Synthoid population estimate.
" +
+ "Therefore, it is important that this Synthoid population estimate " +
+ "is accurate so that you have a better idea of your " +
+ "success rate for contracts/operations. Certain " +
+ "actions will increase the accuracy of your population " +
+ "estimate.
" +
+ "The Synthoid populations of cities can change due to your " +
+ "actions or random events. If random events occur, they will " +
+ "be logged in the Bladeburner Console.");
+ }
+
+ return (
+ Stamina: {formatNumber(props.bladeburner.stamina, 3)} / {formatNumber(props.bladeburner.maxStamina, 3)}
+
+ Est. Synthoid Population: {numeralWrapper.formatPopulation(props.bladeburner.getCurrentCity().popEst)}
+
+ Est. Synthoid Communities: {formatNumber(props.bladeburner.getCurrentCity().comms, 0)}
+ City Chaos: {formatNumber(props.bladeburner.getCurrentCity().chaos)}
+ Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}
+ Bonus time: {convertTimeMsToTimeElapsedString(props.bladeburner.storedCycles/BladeburnerConstants.CyclesPerSecond*1000)}
+ Stamina Penalty: {formatNumber((1-props.bladeburner.calculateStaminaPenalty())*100, 1)}%
+ Team Size: {formatNumber(props.bladeburner.teamSize, 0)}
+ Team Members Lost: {formatNumber(props.bladeburner.teamLost, 0)}
+ Num Times Hospitalized: {props.bladeburner.numHosp}
+ Money Lost From Hospitalizations: {Money(props.bladeburner.moneyLost)}
+ Current City: {props.bladeburner.city}
+ {StatsTable([
+ ["Aug. Success Chance mult: ", formatNumber(props.player.bladeburner_success_chance_mult*100, 1) + "%"],
+ ["Aug. Max Stamina mult: ", formatNumber(props.player.bladeburner_max_stamina_mult*100, 1) + "%"],
+ ["Aug. Stamina Gain mult: ", formatNumber(props.player.bladeburner_stamina_gain_mult*100, 1) + "%"],
+ ["Aug. Field Analysis mult: ", formatNumber(props.player.bladeburner_analysis_mult*100, 1) + "%"],
+ ])}
+
+ {"> "}+ |
+
+ Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)} +
You will gain one skill point every {BladeburnerConstants.RanksPerSkillPoint} ranks.
@@ -24,27 +27,27 @@ export function SkillPage(props: IProps): React.ReactElement {
Note that when upgrading a skill, the benefit for that skill is additive.
However, the effects of different skills with each other is multiplicative.
-
Total Success Chance: x{formatNumber(mults["successChanceAll"], 3)}
} + {valid(mults["successChanceStealth"]) &&Stealth Success Chance: x{formatNumber(mults["successChanceStealth"], 3)}
} + {valid(mults["successChanceKill"]) &&Retirement Success Chance: x{formatNumber(mults["successChanceKill"], 3)}
} + {valid(mults["successChanceContract"]) &&Contract Success Chance: x{formatNumber(mults["successChanceContract"], 3)}
} + {valid(mults["successChanceOperation"]) &&Operation Success Chance: x{formatNumber(mults["successChanceOperation"], 3)}
} + {valid(mults["successChanceEstimate"]) &&Synthoid Data Estimate: x{formatNumber(mults["successChanceEstimate"], 3)}
} + {valid(mults["actionTime"]) &&Action Time: x{formatNumber(mults["actionTime"], 3)}
} + {valid(mults["effHack"]) &&Hacking Skill: x{formatNumber(mults["effHack"], 3)}
} + {valid(mults["effStr"]) &&Strength: x{formatNumber(mults["effStr"], 3)}
} + {valid(mults["effDef"]) &&Defense: x{formatNumber(mults["effDef"], 3)}
} + {valid(mults["effDex"]) &&Dexterity: x{formatNumber(mults["effDex"], 3)}
} + {valid(mults["effAgi"]) &&Agility: x{formatNumber(mults["effAgi"], 3)}
} + {valid(mults["effCha"]) &&Charisma: x{formatNumber(mults["effCha"], 3)}
} + {valid(mults["effInt"]) &&Intelligence: x{formatNumber(mults["effInt"], 3)}
} + {valid(mults["stamina"]) &&Stamina: x{formatNumber(mults["stamina"], 3)}
} + {valid(mults["money"]) &&Contract Money: x{formatNumber(mults["money"], 3)}
} + {valid(mults["expGain"]) &&Exp Gain: x{formatNumber(mults["expGain"], 3)}
} +
- Rank: {formatNumber(props.bladeburner.rank, 2)}
- Stamina: {formatNumber(props.bladeburner.stamina, 3)} / {formatNumber(props.bladeburner.maxStamina, 3)}
+ function openTravel() {
+ // var popupId = "bladeburner-travel-popup-cancel-btn";
+ // var popupArguments = [];
+ // popupArguments.push(createElement("a", { // Cancel Button
+ // innerText:"Cancel", class:"a-link-button",
+ // clickListener:() => {
+ // removeElementById(popupId); return false;
+ // },
+ // }))
+ // popupArguments.push(createElement("p", { // Info Text
+ // innerText:"Travel to a different city for your Bladeburner " +
+ // "activities. This does not cost any money. The city you are " +
+ // "in for your Bladeburner duties does not affect " +
+ // "your location in the game otherwise",
+ // }));
+ // for (var i = 0; i < BladeburnerConstants.CityNames.length; ++i) {
+ // (function(inst, i) {
+ // popupArguments.push(createElement("div", {
+ // // Reusing this css class...it adds a border and makes it
+ // // so that background color changes when you hover
+ // class:"cmpy-mgmt-find-employee-option",
+ // innerText:BladeburnerConstants.CityNames[i],
+ // clickListener:() => {
+ // inst.city = BladeburnerConstants.CityNames[i];
+ // removeElementById(popupId);
+ // inst.updateOverviewContent();
+ // return false;
+ // },
+ // }));
+ // })(this, i);
+ // }
+ // createPopup(popupId, popupArguments);
+ }
+
+ function openFaction() {
+ // if (bladeburnerFac.isMember) {
+ // Engine.loadFactionContent();
+ // displayFactionContent(bladeburnersFactionName);
+ // } else {
+ // if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
+ // joinFaction(bladeburnerFac);
+ // dialogBoxCreate("Congratulations! You were accepted into the Bladeburners faction");
+ // removeChildrenFromElement(DomElems.overviewDiv);
+ // this.createOverviewContent();
+ // } else {
+ // dialogBoxCreate("You need a rank of 25 to join the Bladeburners Faction!")
+ // }
+ // }
+ }
+
+ return (<>
+
+ Rank: {formatNumber(props.bladeburner.rank, 2)} + Your rank within the Bladeburner division. +
Stamina: {formatNumber(props.bladeburner.stamina, 3)} / {formatNumber(props.bladeburner.maxStamina, 3)}
Stamina Penalty: {formatNumber((1-props.bladeburner.calculateStaminaPenalty())*100, 1)}%
Team Size: {formatNumber(props.bladeburner.teamSize, 0)}
+Team Members Lost: {formatNumber(props.bladeburner.teamLost, 0)}
Num Times Hospitalized: {props.bladeburner.numHosp}
+Money Lost From Hospitalizations: {Money(props.bladeburner.moneyLost)}
Current City: {props.bladeburner.city}
++ Est. Synthoid Population: {numeralWrapper.formatPopulation(props.bladeburner.getCurrentCity().popEst)} + This is your Bladeburner division's estimate of how many Synthoids exist in your current city. +
+ Est. Synthoid Communities: {formatNumber(props.bladeburner.getCurrentCity().comms, 0)} + This is your Bladeburner divison's estimate of how many Synthoid communities exist in your current city. +
+ City Chaos: {formatNumber(props.bladeburner.getCurrentCity().chaos)} + The city's chaos level due to tensions and conflicts between humans and Synthoids. Having too high of a chaos level can make contracts and operations harder. +
+ Bonus time: {convertTimeMsToTimeElapsedString(props.bladeburner.storedCycles/BladeburnerConstants.CyclesPerSecond*1000)}
+
+ You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by browser).
+ Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed.
+
+
Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}
- {"> "}- |
-
+ {"> "}+ |
+
+ Enter the amount of team members you would like to take on this + Op. If you do not have the specified number of team members, + then as many as possible will be used. Note that team members may + be lost during operations. +
+ setTeamSize(parseFloat(event.target.value))} /> + Confirm + >); +} \ No newline at end of file diff --git a/src/Bladeburner/ui/TravelPopup.tsx b/src/Bladeburner/ui/TravelPopup.tsx new file mode 100644 index 000000000..3becd7cc4 --- /dev/null +++ b/src/Bladeburner/ui/TravelPopup.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { removePopup } from "../../ui/React/createPopup"; +import { BladeburnerConstants } from "../data/Constants"; + +interface IProps { + bladeburner: any; + popupId: string; +} + +export function TravelPopup(props: IProps): React.ReactElement { + function travel(city: string) { + props.bladeburner.city = city; + removePopup(props.popupId); + } + + return (<> ++ Travel to a different city for your Bladeburner + activities. This does not cost any money. The city you are + in for your Bladeburner duties does not affect + your location in the game otherwise. +
+ {BladeburnerConstants.CityNames.map(city => + // Reusing this css class...it adds a border and makes it + // so that background color changes when you hover +Lists all factions you have joined
Lists factions you have been invited to. You can accept these faction invitations at any time.
{faction}
--- {tasks.map((task: string, i: number) => )} -Stats
tab on the main navigation menu (left-hand side of the screen)"),s.style.display="none",t.setAttribute("class","flashing-button"),t.addEventListener("click",function(){return a.Engine.loadCharacterContent(),y(),!1});break;case h.CharacterPage:a.Engine.loadCharacterContent(),v("The Stats
page shows a lot of important information about your progress, such as your skills, money, and bonuses. "),s.style.display="inline-block";break;case h.CharacterGoToTerminalPage:a.Engine.loadCharacterContent(),v("Let's head to your computer's terminal by clicking the Terminal
tab on the main navigation menu."),s.style.display="none",e.setAttribute("class","flashing-button"),e.addEventListener("click",function(){return a.Engine.loadTerminalContent(),y(),!1});break;case h.TerminalIntro:a.Engine.loadTerminalContent(),v("The Terminal
is used to interface with your home computer as well as all of the other machines around the world."),s.style.display="inline-block";break;case h.TerminalHelp:a.Engine.loadTerminalContent(),v("Let's try it out. Start by entering the help
command into the Terminal
(Don't forget to press Enter after typing the command)"),s.style.display="none";break;case h.TerminalLs:a.Engine.loadTerminalContent(),v("The help
command displays a list of all available Terminal
commands, how to use them, and a description of what they do. ls
command."),s.style.display="none";break;case h.TerminalScan:a.Engine.loadTerminalContent(),v(" ls
is a basic command that shows files on the computer. Right now, it shows that you have a program called NUKE.exe
on your computer. We'll get to what this does later. scan
command."),s.style.display="none";break;case h.TerminalScanAnalyze1:a.Engine.loadTerminalContent(),v("The scan
command shows all available network connections. In other words, it displays a list of all servers that can be connected to from your current machine. A server is identified by its hostname. scan-analyze
command gives some more detailed information about servers on the network. Try it now!"),s.style.display="none";break;case h.TerminalScanAnalyze2:a.Engine.loadTerminalContent(),v("You just ran scan-analyze
with a depth of one. This command shows more detailed information about each server that you can connect to (servers that are a distance of one node away). scan-analyze
with a higher depth. Let's try a depth of two with the following command: scan-analyze 2
."),s.style.display="none";break;case h.TerminalConnect:a.Engine.loadTerminalContent(),v("Now you can see information about all servers that are up to two nodes away, as well as figure out how to navigate to those servers through the network. You can only connect to a server that is one node away. To connect to a machine, use the connect [hostname]
command.scan-analyze
command, we can see that the n00dles
server is only one node away. Let's connect so it now using: connect n00dles
"),s.style.display="none";break;case h.TerminalAnalyze:a.Engine.loadTerminalContent(),v("You are now connected to another machine! What can you do now? You can hack it!analyze
command."),s.style.display="none";break;case h.TerminalNuke:a.Engine.loadTerminalContent(),v("When the analyze
command finishes running it will show useful information about hacking the server. NUKE.exe
program that we saw earlier on your home computer is a virus that will grant you root access to a machine if there are enough open ports.analyze
results shows that there do not need to be any open ports on this machine for the NUKE virus to work, so go ahead and run the virus using the run NUKE.exe
command."),s.style.display="none";break;case h.TerminalManualHack:a.Engine.loadTerminalContent(),v("You now have root access! You can hack the server using the hack
command. Try doing that now."),s.style.display="none";break;case h.TerminalHackingMechanics:a.Engine.loadTerminalContent(),v("You are now attempting to hack the server. Performing a hack takes time and only has a certain percentage chance of success. This time and success chance is determined by a variety of factors, including your hacking skill and the server's security level.nano
command. Scripts must end with the .script
extension. Let's make a script now by entering nano n00dles.script
after the hack command finishes running (Sidenote: Pressing ctrl + c will end a command like hack early)"),s.style.display="none";break;case h.TerminalTypeScript:a.Engine.loadScriptEditorContent("n00dles.script",""),v("This is the script editor. You can use it to program your scripts. Scripts are written in a simplified version of javascript. Copy and paste the following code into the script editor: while(true) {\n hack('n00dles');\n}For anyone with basic programming experience, this code should be straightforward. This script will continuously hack the
n00dles
server.free
command."),s.style.display="none";break;case h.TerminalRunScript:a.Engine.loadTerminalContent(),v("We have 4GB of free RAM on this machine, which is enough to run our script. Let's run our script using run n00dles.script
."),s.style.display="none";break;case h.TerminalGoToActiveScriptsPage:a.Engine.loadTerminalContent(),v("Your script is now running! It will continuously run in the background and will automatically stop if the code ever completes (the n00dles.script
will never complete because it runs an infinite loop). Active Scripts
link in the main navigation menu."),s.style.display="none",n.setAttribute("class","flashing-button"),n.addEventListener("click",function(){return a.Engine.loadActiveScriptsContent(),y(),!1});break;case h.ActiveScriptsPage:a.Engine.loadActiveScriptsContent(),v("This page displays information about all of your scripts that are running across every server. You can use this to gauge how well your scripts are doing. Let's go back to the Terminal
"),s.style.display="none",e.setAttribute("class","flashing-button"),e.addEventListener("click",function(){return a.Engine.loadTerminalContent(),y(),!1});break;case h.ActiveScriptsToTerminal:a.Engine.loadTerminalContent(),v("One last thing about scripts, each active script contains logs that detail what it's doing. We can check these logs using the tail
command. Do that now for the script we just ran by typing tail n00dles.script
"),s.style.display="none";break;case h.TerminalTailScript:a.Engine.loadTerminalContent(),v("The log for this script won't show much right now (it might show nothing at all) because it just started running...but check back again in a few minutes! Tutorial
link in the main navigation menu to look at the documentation. If you are an experienced JavaScript developer, I would highly suggest you check out the section on NetscriptJS/Netscript 2.0, it's faster and more powerful.Hacknet
page through the main navigation menu now."),s.style.display="none",r.setAttribute("class","flashing-button"),r.addEventListener("click",function(){return a.Engine.loadHacknetNodesContent(),y(),!1});break;case h.HacknetNodesIntroduction:a.Engine.loadHacknetNodesContent(),v("here you can purchase new Hacknet Nodes and upgrade your existing ones. Let's purchase a new one now."),s.style.display="none";break;case h.HacknetNodesGoToWorldPage:a.Engine.loadHacknetNodesContent(),v("You just purchased a Hacknet Node! This Hacknet Node will passively earn you money over time, both online and offline. When you get enough money, you can upgrade your newly-purchased Hacknet Node below.City
page through the main navigation menu."),s.style.display="none",i.setAttribute("class","flashing-button"),i.addEventListener("click",function(){return a.Engine.loadLocationContent(),y(),!1});break;case h.WorldDescription:a.Engine.loadLocationContent(),v("This page lists all of the different locations you can currently travel to. Each location has something that you can do. There's a lot of content out in the world, make sure you explore and discover!Tutorial
link in the main navigation menu."),s.style.display="none",o.setAttribute("class","flashing-button"),o.addEventListener("click",function(){return a.Engine.loadTutorialContent(),y(),!1});break;case h.TutorialPageInfo:a.Engine.loadTutorialContent(),v("This page contains a lot of different documentation about the game's content and mechanics. I know it's a lot, but I highly suggest you read (or at least skim) through this before you start playing. That's the end of the tutorial. Hope you enjoy the game!"),s.style.display="inline-block",s.innerHTML="Finish Tutorial";break;case h.End:b();break;default:throw new Error("Invalid tutorial step")}!0===_.stepIsDone[_.currStep]&&(s.style.display="inline-block")}function y(){_.currStep===h.GoToCharacterPage&&document.getElementById("stats-menu-link").removeAttribute("class"),_.currStep===h.CharacterGoToTerminalPage&&document.getElementById("terminal-menu-link").removeAttribute("class"),_.currStep===h.TerminalGoToActiveScriptsPage&&document.getElementById("active-scripts-menu-link").removeAttribute("class"),_.currStep===h.ActiveScriptsPage&&document.getElementById("terminal-menu-link").removeAttribute("class"),_.currStep===h.GoToHacknetNodesPage&&document.getElementById("hacknet-nodes-menu-link").removeAttribute("class"),_.currStep===h.HacknetNodesGoToWorldPage&&document.getElementById("city-menu-link").removeAttribute("class"),_.currStep===h.WorldDescription&&document.getElementById("tutorial-menu-link").removeAttribute("class"),_.stepIsDone[_.currStep]=!0,_.currStepFAILED
- Contract is now self-destructing"),t.removeContract(n)):Object(_ui_postToTerminal__WEBPACK_IMPORTED_MODULE_40__.post)(`ContractFAILED
- ${n.getMaxNumTries()-n.tries} tries remaining`);break;case _CodingContracts__WEBPACK_IMPORTED_MODULE_7__.CodingContractResult.Cancelled:default:Object(_ui_postToTerminal__WEBPACK_IMPORTED_MODULE_40__.post)("Contract cancelled")}Terminal.contractOpen=!1}}}).call(this,__webpack_require__(129))},,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.HacknetServer=void 0;const a=n(11),r=n(692),i=n(38),o=n(155),s=n(410),l=n(26);class c extends r.BaseServer{constructor(e={hostname:"",ip:s.createRandomIp()}){super(e),this.cache=1,this.cores=1,this.hashCapacity=0,this.hashRate=0,this.level=1,this.onlineTimeSeconds=0,this.totalHashesGenerated=0,this.maxRam=1,this.updateHashCapacity()}calculateCacheUpgradeCost(e){return o.calculateCacheUpgradeCost(this.cache,e)}calculateCoreUpgradeCost(e,t){return o.calculateCoreUpgradeCost(this.cores,e,t)}calculateLevelUpgradeCost(e,t){return o.calculateLevelUpgradeCost(this.level,e,t)}calculateRamUpgradeCost(e,t){return o.calculateRamUpgradeCost(this.maxRam,e,t)}process(e=1){const t=e*a.CONSTANTS.MilliPerCycle/1e3;return this.hashRate*t}upgradeCache(e){this.cache=Math.min(i.HacknetServerConstants.MaxCache,Math.round(this.cache+e)),this.updateHashCapacity()}upgradeCore(e,t){this.cores=Math.min(i.HacknetServerConstants.MaxCores,Math.round(this.cores+e)),this.updateHashRate(t)}upgradeLevel(e,t){this.level=Math.min(i.HacknetServerConstants.MaxLevel,Math.round(this.level+e)),this.updateHashRate(t)}upgradeRam(e,t){for(let t=0;tStats
tab on the main navigation menu (left-hand side of the screen)"),s.style.display="none",t.setAttribute("class","flashing-button"),t.addEventListener("click",function(){return a.Engine.loadCharacterContent(),y(),!1});break;case h.CharacterPage:a.Engine.loadCharacterContent(),v("The Stats
page shows a lot of important information about your progress, such as your skills, money, and bonuses. "),s.style.display="inline-block";break;case h.CharacterGoToTerminalPage:a.Engine.loadCharacterContent(),v("Let's head to your computer's terminal by clicking the Terminal
tab on the main navigation menu."),s.style.display="none",e.setAttribute("class","flashing-button"),e.addEventListener("click",function(){return a.Engine.loadTerminalContent(),y(),!1});break;case h.TerminalIntro:a.Engine.loadTerminalContent(),v("The Terminal
is used to interface with your home computer as well as all of the other machines around the world."),s.style.display="inline-block";break;case h.TerminalHelp:a.Engine.loadTerminalContent(),v("Let's try it out. Start by entering the help
command into the Terminal
(Don't forget to press Enter after typing the command)"),s.style.display="none";break;case h.TerminalLs:a.Engine.loadTerminalContent(),v("The help
command displays a list of all available Terminal
commands, how to use them, and a description of what they do. ls
command."),s.style.display="none";break;case h.TerminalScan:a.Engine.loadTerminalContent(),v(" ls
is a basic command that shows files on the computer. Right now, it shows that you have a program called NUKE.exe
on your computer. We'll get to what this does later. scan
command."),s.style.display="none";break;case h.TerminalScanAnalyze1:a.Engine.loadTerminalContent(),v("The scan
command shows all available network connections. In other words, it displays a list of all servers that can be connected to from your current machine. A server is identified by its hostname. scan-analyze
command gives some more detailed information about servers on the network. Try it now!"),s.style.display="none";break;case h.TerminalScanAnalyze2:a.Engine.loadTerminalContent(),v("You just ran scan-analyze
with a depth of one. This command shows more detailed information about each server that you can connect to (servers that are a distance of one node away). scan-analyze
with a higher depth. Let's try a depth of two with the following command: scan-analyze 2
."),s.style.display="none";break;case h.TerminalConnect:a.Engine.loadTerminalContent(),v("Now you can see information about all servers that are up to two nodes away, as well as figure out how to navigate to those servers through the network. You can only connect to a server that is one node away. To connect to a machine, use the connect [hostname]
command.scan-analyze
command, we can see that the n00dles
server is only one node away. Let's connect so it now using: connect n00dles
"),s.style.display="none";break;case h.TerminalAnalyze:a.Engine.loadTerminalContent(),v("You are now connected to another machine! What can you do now? You can hack it!analyze
command."),s.style.display="none";break;case h.TerminalNuke:a.Engine.loadTerminalContent(),v("When the analyze
command finishes running it will show useful information about hacking the server. NUKE.exe
program that we saw earlier on your home computer is a virus that will grant you root access to a machine if there are enough open ports.analyze
results shows that there do not need to be any open ports on this machine for the NUKE virus to work, so go ahead and run the virus using the run NUKE.exe
command."),s.style.display="none";break;case h.TerminalManualHack:a.Engine.loadTerminalContent(),v("You now have root access! You can hack the server using the hack
command. Try doing that now."),s.style.display="none";break;case h.TerminalHackingMechanics:a.Engine.loadTerminalContent(),v("You are now attempting to hack the server. Performing a hack takes time and only has a certain percentage chance of success. This time and success chance is determined by a variety of factors, including your hacking skill and the server's security level.nano
command. Scripts must end with the .script
extension. Let's make a script now by entering nano n00dles.script
after the hack command finishes running (Sidenote: Pressing ctrl + c will end a command like hack early)"),s.style.display="none";break;case h.TerminalTypeScript:a.Engine.loadScriptEditorContent("n00dles.script",""),v("This is the script editor. You can use it to program your scripts. Scripts are written in a simplified version of javascript. Copy and paste the following code into the script editor: while(true) {\n hack('n00dles');\n}For anyone with basic programming experience, this code should be straightforward. This script will continuously hack the
n00dles
server.free
command."),s.style.display="none";break;case h.TerminalRunScript:a.Engine.loadTerminalContent(),v("We have 4GB of free RAM on this machine, which is enough to run our script. Let's run our script using run n00dles.script
."),s.style.display="none";break;case h.TerminalGoToActiveScriptsPage:a.Engine.loadTerminalContent(),v("Your script is now running! It will continuously run in the background and will automatically stop if the code ever completes (the n00dles.script
will never complete because it runs an infinite loop). Active Scripts
link in the main navigation menu."),s.style.display="none",n.setAttribute("class","flashing-button"),n.addEventListener("click",function(){return a.Engine.loadActiveScriptsContent(),y(),!1});break;case h.ActiveScriptsPage:a.Engine.loadActiveScriptsContent(),v("This page displays information about all of your scripts that are running across every server. You can use this to gauge how well your scripts are doing. Let's go back to the Terminal
"),s.style.display="none",e.setAttribute("class","flashing-button"),e.addEventListener("click",function(){return a.Engine.loadTerminalContent(),y(),!1});break;case h.ActiveScriptsToTerminal:a.Engine.loadTerminalContent(),v("One last thing about scripts, each active script contains logs that detail what it's doing. We can check these logs using the tail
command. Do that now for the script we just ran by typing tail n00dles.script
"),s.style.display="none";break;case h.TerminalTailScript:a.Engine.loadTerminalContent(),v("The log for this script won't show much right now (it might show nothing at all) because it just started running...but check back again in a few minutes! Tutorial
link in the main navigation menu to look at the documentation. If you are an experienced JavaScript developer, I would highly suggest you check out the section on NetscriptJS/Netscript 2.0, it's faster and more powerful.Hacknet
page through the main navigation menu now."),s.style.display="none",r.setAttribute("class","flashing-button"),r.addEventListener("click",function(){return a.Engine.loadHacknetNodesContent(),y(),!1});break;case h.HacknetNodesIntroduction:a.Engine.loadHacknetNodesContent(),v("here you can purchase new Hacknet Nodes and upgrade your existing ones. Let's purchase a new one now."),s.style.display="none";break;case h.HacknetNodesGoToWorldPage:a.Engine.loadHacknetNodesContent(),v("You just purchased a Hacknet Node! This Hacknet Node will passively earn you money over time, both online and offline. When you get enough money, you can upgrade your newly-purchased Hacknet Node below.City
page through the main navigation menu."),s.style.display="none",i.setAttribute("class","flashing-button"),i.addEventListener("click",function(){return a.Engine.loadLocationContent(),y(),!1});break;case h.WorldDescription:a.Engine.loadLocationContent(),v("This page lists all of the different locations you can currently travel to. Each location has something that you can do. There's a lot of content out in the world, make sure you explore and discover!Tutorial
link in the main navigation menu."),s.style.display="none",o.setAttribute("class","flashing-button"),o.addEventListener("click",function(){return a.Engine.loadTutorialContent(),y(),!1});break;case h.TutorialPageInfo:a.Engine.loadTutorialContent(),v("This page contains a lot of different documentation about the game's content and mechanics. I know it's a lot, but I highly suggest you read (or at least skim) through this before you start playing. That's the end of the tutorial. Hope you enjoy the game!"),s.style.display="inline-block",s.innerHTML="Finish Tutorial";break;case h.End:b();break;default:throw new Error("Invalid tutorial step")}!0===_.stepIsDone[_.currStep]&&(s.style.display="inline-block")}function y(){_.currStep===h.GoToCharacterPage&&document.getElementById("stats-menu-link").removeAttribute("class"),_.currStep===h.CharacterGoToTerminalPage&&document.getElementById("terminal-menu-link").removeAttribute("class"),_.currStep===h.TerminalGoToActiveScriptsPage&&document.getElementById("active-scripts-menu-link").removeAttribute("class"),_.currStep===h.ActiveScriptsPage&&document.getElementById("terminal-menu-link").removeAttribute("class"),_.currStep===h.GoToHacknetNodesPage&&document.getElementById("hacknet-nodes-menu-link").removeAttribute("class"),_.currStep===h.HacknetNodesGoToWorldPage&&document.getElementById("city-menu-link").removeAttribute("class"),_.currStep===h.WorldDescription&&document.getElementById("tutorial-menu-link").removeAttribute("class"),_.stepIsDone[_.currStep]=!0,_.currStepFAILED
- Contract is now self-destructing"),t.removeContract(n)):Object(_ui_postToTerminal__WEBPACK_IMPORTED_MODULE_40__.post)(`ContractFAILED
- ${n.getMaxNumTries()-n.tries} tries remaining`);break;case _CodingContracts__WEBPACK_IMPORTED_MODULE_7__.CodingContractResult.Cancelled:default:Object(_ui_postToTerminal__WEBPACK_IMPORTED_MODULE_40__.post)("Contract cancelled")}Terminal.contractOpen=!1}}}).call(this,__webpack_require__(138))},,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setTimeoutRef=void 0,t.setTimeoutRef=window.setTimeout.bind(window)},,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.HacknetServer=void 0;const a=n(10),r=n(688),i=n(37),o=n(147),s=n(401),l=n(26);class c extends r.BaseServer{constructor(e={hostname:"",ip:s.createRandomIp()}){super(e),this.cache=1,this.cores=1,this.hashCapacity=0,this.hashRate=0,this.level=1,this.onlineTimeSeconds=0,this.totalHashesGenerated=0,this.maxRam=1,this.updateHashCapacity()}calculateCacheUpgradeCost(e){return o.calculateCacheUpgradeCost(this.cache,e)}calculateCoreUpgradeCost(e,t){return o.calculateCoreUpgradeCost(this.cores,e,t)}calculateLevelUpgradeCost(e,t){return o.calculateLevelUpgradeCost(this.level,e,t)}calculateRamUpgradeCost(e,t){return o.calculateRamUpgradeCost(this.maxRam,e,t)}process(e=1){const t=e*a.CONSTANTS.MilliPerCycle/1e3;return this.hashRate*t}upgradeCache(e){this.cache=Math.min(i.HacknetServerConstants.MaxCache,Math.round(this.cache+e)),this.updateHashCapacity()}upgradeCore(e,t){this.cores=Math.min(i.HacknetServerConstants.MaxCores,Math.round(this.cores+e)),this.updateHashRate(t)}upgradeLevel(e,t){this.level=Math.min(i.HacknetServerConstants.MaxLevel,Math.round(this.level+e)),this.updateHashRate(t)}upgradeRam(e,t){for(let t=0;t