mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 09:33:49 +01:00
Converting bladeburner to react
This commit is contained in:
parent
78cd319c21
commit
0e9d7450c9
@ -52,6 +52,11 @@ import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElement } from "../utils/uiHelpers/removeElement";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
import { SkillElem } from "./Bladeburner/ui/SkillElem";
|
||||
import { BlackOpElem } from "./Bladeburner/ui/BlackOpElem";
|
||||
import { OperationElem } from "./Bladeburner/ui/OperationElem";
|
||||
import { ContractElem } from "./Bladeburner/ui/ContractElem";
|
||||
import { GeneralActionElem } from "./Bladeburner/ui/GeneralActionElem";
|
||||
import { StatsTable } from "./ui/React/StatsTable";
|
||||
import { CopyableText } from "./ui/React/CopyableText";
|
||||
import { Money } from "./ui/React/Money";
|
||||
@ -1894,442 +1899,28 @@ Bladeburner.prototype.updateActionAndSkillsContent = function() {
|
||||
}
|
||||
|
||||
Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
|
||||
removeChildrenFromElement(el);
|
||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
||||
var computedActionTimeCurrent = Math.min(this.actionTimeCurrent+this.actionTimeOverflow,this.actionTimeToComplete);
|
||||
|
||||
el.appendChild(createElement("h2", { // Header
|
||||
innerText:isActive ? action.name + " (IN PROGRESS - " +
|
||||
formatNumber(computedActionTimeCurrent, 0) + " / " +
|
||||
formatNumber(this.actionTimeToComplete, 0) + ")"
|
||||
: action.name,
|
||||
display:"inline-block",
|
||||
}));
|
||||
|
||||
if (isActive) { // Progress bar if its active
|
||||
var progress = computedActionTimeCurrent / this.actionTimeToComplete;
|
||||
el.appendChild(createElement("p", {
|
||||
display:"block",
|
||||
innerText:createProgressBarText({progress:progress}),
|
||||
}));
|
||||
} else {
|
||||
// Start button
|
||||
el.appendChild(createElement("a", {
|
||||
innerText:"Start", class: "a-link-button",
|
||||
margin:"3px", padding:"3px",
|
||||
clickListener:() => {
|
||||
this.action.type = ActionTypes[action.name];
|
||||
this.action.name = action.name;
|
||||
this.startAction(this.action);
|
||||
this.updateActionAndSkillsContent();
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
appendLineBreaks(el, 2);
|
||||
el.appendChild(createElement("pre", { // Info
|
||||
innerHTML:action.desc, display:"inline-block",
|
||||
}));
|
||||
|
||||
|
||||
ReactDOM.unmountComponentAtNode(el);
|
||||
ReactDOM.render(<GeneralActionElem bladeburner={this} action={action} />, el);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.updateContractsUIElement = function(el, action) {
|
||||
removeChildrenFromElement(el);
|
||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
||||
var estimatedSuccessChance = action.getSuccessChance(this, {est:true});
|
||||
var computedActionTimeCurrent = Math.min(this.actionTimeCurrent+this.actionTimeOverflow,this.actionTimeToComplete);
|
||||
|
||||
el.appendChild(createElement("h2", { // Header
|
||||
innerText:isActive ? action.name + " (IN PROGRESS - " +
|
||||
formatNumber(computedActionTimeCurrent, 0) + " / " +
|
||||
formatNumber(this.actionTimeToComplete, 0) + ")"
|
||||
: action.name,
|
||||
display:"inline-block",
|
||||
}));
|
||||
|
||||
if (isActive) { // Progress bar if its active
|
||||
var progress = computedActionTimeCurrent / this.actionTimeToComplete;
|
||||
el.appendChild(createElement("p", {
|
||||
display:"block",
|
||||
innerText:createProgressBarText({progress:progress}),
|
||||
}));
|
||||
} else { // Start button
|
||||
el.appendChild(createElement("a", {
|
||||
innerText:"Start", class: "a-link-button",
|
||||
padding:"3px", margin:"3px",
|
||||
clickListener:() => {
|
||||
this.action.type = ActionTypes.Contract;
|
||||
this.action.name = action.name;
|
||||
this.startAction(this.action);
|
||||
this.updateActionAndSkillsContent();
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
// Level and buttons to change level
|
||||
var maxLevel = (action.level >= action.maxLevel);
|
||||
appendLineBreaks(el, 2);
|
||||
el.appendChild(createElement("pre", {
|
||||
display:"inline-block",
|
||||
innerText:"Level: " + action.level + " / " + action.maxLevel,
|
||||
tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel) + " successes " +
|
||||
"needed for next level",
|
||||
}));
|
||||
el.appendChild(createElement("a", {
|
||||
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"↑",
|
||||
padding:"2px", margin:"2px",
|
||||
tooltip: isActive ? "WARNING: changing the level will restart the contract" : "",
|
||||
display:"inline",
|
||||
clickListener:() => {
|
||||
++action.level;
|
||||
if (isActive) {this.startAction(this.action);} // Restart Action
|
||||
this.updateContractsUIElement(el, action);
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
el.appendChild(createElement("a", {
|
||||
class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"↓",
|
||||
padding:"2px", margin:"2px",
|
||||
tooltip: isActive ? "WARNING: changing the level will restart the contract" : "",
|
||||
display:"inline",
|
||||
clickListener:() => {
|
||||
--action.level;
|
||||
if (isActive) {this.startAction(this.action);} // Restart Action
|
||||
this.updateContractsUIElement(el, action);
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
|
||||
var actionTime = action.getActionTime(this);
|
||||
appendLineBreaks(el, 2);
|
||||
el.appendChild(createElement("pre", { // Info
|
||||
display:"inline-block",
|
||||
innerHTML:action.desc + "\n\n" +
|
||||
`Estimated success chance: ${formatNumber(estimatedSuccessChance*100, 1)}% ${action.isStealth?stealthIcon:''}${action.isKill?killIcon:''}\n` +
|
||||
"Time Required: " + convertTimeMsToTimeElapsedString(actionTime*1000) + "\n" +
|
||||
"Contracts remaining: " + Math.floor(action.count) + "\n" +
|
||||
"Successes: " + action.successes + "\n" +
|
||||
"Failures: " + 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);
|
||||
ReactDOM.unmountComponentAtNode(el);
|
||||
ReactDOM.render(<ContractElem bladeburner={this} action={action} />, el);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
|
||||
removeChildrenFromElement(el);
|
||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
||||
var estimatedSuccessChance = action.getSuccessChance(this, {est:true});
|
||||
var computedActionTimeCurrent = Math.min(this.actionTimeCurrent+this.actionTimeOverflow,this.actionTimeToComplete);
|
||||
|
||||
el.appendChild(createElement("h2", { // Header
|
||||
innerText:isActive ? action.name + " (IN PROGRESS - " +
|
||||
formatNumber(computedActionTimeCurrent, 0) + " / " +
|
||||
formatNumber(this.actionTimeToComplete, 0) + ")"
|
||||
: action.name,
|
||||
display:"inline-block",
|
||||
}));
|
||||
|
||||
if (isActive) { // Progress bar if its active
|
||||
var progress = computedActionTimeCurrent / this.actionTimeToComplete;
|
||||
el.appendChild(createElement("p", {
|
||||
display:"block",
|
||||
innerText:createProgressBarText({progress:progress}),
|
||||
}));
|
||||
} else { // Start button and set Team Size button
|
||||
el.appendChild(createElement("a", {
|
||||
innerText:"Start", class: "a-link-button",
|
||||
margin:"3px", padding:"3px",
|
||||
clickListener:() => {
|
||||
this.action.type = ActionTypes.Operation;
|
||||
this.action.name = action.name;
|
||||
this.startAction(this.action);
|
||||
this.updateActionAndSkillsContent();
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
el.appendChild(createElement("a", {
|
||||
innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button",
|
||||
margin:"3px", padding:"3px",
|
||||
clickListener:() => {
|
||||
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();
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
// Level and buttons to change level
|
||||
var maxLevel = (action.level >= action.maxLevel);
|
||||
appendLineBreaks(el, 2);
|
||||
el.appendChild(createElement("pre", {
|
||||
display:"inline-block",
|
||||
innerText:"Level: " + action.level + " / " + action.maxLevel,
|
||||
tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel) + " successes " +
|
||||
"needed for next level",
|
||||
}));
|
||||
el.appendChild(createElement("a", {
|
||||
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"↑",
|
||||
padding:"2px", margin:"2px",
|
||||
tooltip: isActive ? "WARNING: changing the level will restart the Operation" : "",
|
||||
display:"inline",
|
||||
clickListener:() => {
|
||||
++action.level;
|
||||
if (isActive) {this.startAction(this.action);} // Restart Action
|
||||
this.updateOperationsUIElement(el, action);
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
el.appendChild(createElement("a", {
|
||||
class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"↓",
|
||||
padding:"2px", margin:"2px",
|
||||
tooltip: isActive ? "WARNING: changing the level will restart the Operation" : "",
|
||||
display:"inline",
|
||||
clickListener:() => {
|
||||
--action.level;
|
||||
if (isActive) {this.startAction(this.action);} // Restart Action
|
||||
this.updateOperationsUIElement(el, action);
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
|
||||
// General Info
|
||||
var actionTime = action.getActionTime(this);
|
||||
appendLineBreaks(el, 2);
|
||||
el.appendChild(createElement("pre", {
|
||||
display:"inline-block",
|
||||
innerHTML:action.desc + "\n\n" +
|
||||
`Estimated success chance: ${formatNumber(estimatedSuccessChance*100, 1)}% ${action.isStealth?stealthIcon:''}${action.isKill?killIcon:''}\n` +
|
||||
"Time Required: " + convertTimeMsToTimeElapsedString(actionTime*1000) + "\n" +
|
||||
"Operations remaining: " + Math.floor(action.count) + "\n" +
|
||||
"Successes: " + action.successes + "\n" +
|
||||
"Failures: " + 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 operation level when possible",
|
||||
}));
|
||||
|
||||
const checkboxInput = createElement("input", {
|
||||
type:"checkbox",
|
||||
id: autolevelCheckboxId,
|
||||
checked: action.autoLevel,
|
||||
changeListener: () => {
|
||||
action.autoLevel = checkboxInput.checked;
|
||||
},
|
||||
});
|
||||
|
||||
el.appendChild(checkboxInput);
|
||||
ReactDOM.unmountComponentAtNode(el);
|
||||
ReactDOM.render(<OperationElem bladeburner={this} action={action} />, el);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
|
||||
removeChildrenFromElement(el);
|
||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
||||
var isCompleted = (this.blackops[action.name] != null);
|
||||
var estimatedSuccessChance = action.getSuccessChance(this, {est:true});
|
||||
var actionTime = action.getActionTime(this);
|
||||
var hasReqdRank = this.rank >= action.reqdRank;
|
||||
var computedActionTimeCurrent = Math.min(this.actionTimeCurrent+this.actionTimeOverflow,this.actionTimeToComplete);
|
||||
|
||||
// UI for Completed Black Op
|
||||
if (isCompleted) {
|
||||
el.appendChild(createElement("h2", {
|
||||
innerText:action.name + " (COMPLETED)", display:"block",
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
el.appendChild(createElement("h2", { // Header
|
||||
innerText:isActive ? action.name + " (IN PROGRESS - " +
|
||||
formatNumber(computedActionTimeCurrent, 0) + " / " +
|
||||
formatNumber(this.actionTimeToComplete, 0) + ")"
|
||||
: action.name,
|
||||
display:"inline-block",
|
||||
}));
|
||||
|
||||
if (isActive) { // Progress bar if its active
|
||||
var progress = computedActionTimeCurrent / this.actionTimeToComplete;
|
||||
el.appendChild(createElement("p", {
|
||||
display:"block",
|
||||
innerText:createProgressBarText({progress:progress}),
|
||||
}));
|
||||
} else {
|
||||
el.appendChild(createElement("a", { // Start button
|
||||
innerText:"Start", margin:"3px", padding:"3px",
|
||||
class:hasReqdRank ? "a-link-button" : "a-link-button-inactive",
|
||||
clickListener:() => {
|
||||
this.action.type = ActionTypes.BlackOperation;
|
||||
this.action.name = action.name;
|
||||
this.startAction(this.action);
|
||||
this.updateActionAndSkillsContent();
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
el.appendChild(createElement("a", { // Set Team Size Button
|
||||
innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button",
|
||||
margin:"3px", padding:"3px",
|
||||
clickListener:() => {
|
||||
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();
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
// Info
|
||||
appendLineBreaks(el, 2);
|
||||
el.appendChild(createElement("p", {
|
||||
display:"inline-block",
|
||||
innerHTML:"<br>" + action.desc + "<br><br>",
|
||||
}));
|
||||
el.appendChild(createElement("p", {
|
||||
display:"block", color:hasReqdRank ? "white" : "red",
|
||||
innerHTML:"Required Rank: " + formatNumber(action.reqdRank, 0) + "<br>",
|
||||
}));
|
||||
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(<BlackOpElem bladeburner={this} action={action} />, el);
|
||||
}
|
||||
|
||||
Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
|
||||
removeChildrenFromElement(el);
|
||||
var skillName = skill.name;
|
||||
var currentLevel = 0;
|
||||
if (this.skills[skillName] && !isNaN(this.skills[skillName])) {
|
||||
currentLevel = this.skills[skillName];
|
||||
}
|
||||
var pointCost = skill.calculateCost(currentLevel);
|
||||
|
||||
const nameDiv = createElement("div");
|
||||
ReactDOM.render(React.createElement(CopyableText, {value: skill.name}, null), nameDiv);
|
||||
el.appendChild(nameDiv)
|
||||
|
||||
const h2 = createElement("h2", { // Header
|
||||
display:"inline-block",
|
||||
});
|
||||
h2.appendChild(nameDiv);
|
||||
el.appendChild(h2);
|
||||
|
||||
var canLevel = this.skillPoints >= pointCost;
|
||||
var maxLvl = skill.maxLvl ? currentLevel >= skill.maxLvl : false;
|
||||
el.appendChild(createElement("a", { // Level up button
|
||||
innerText:"Level", display:"inline-block",
|
||||
class: canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive",
|
||||
margin:"3px", padding:"3px",
|
||||
clickListener:() => {
|
||||
if (this.skillPoints < pointCost) {return;}
|
||||
this.skillPoints -= pointCost;
|
||||
this.upgradeSkill(skill);
|
||||
this.createActionAndSkillsContent();
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
appendLineBreaks(el, 2);
|
||||
el.appendChild(createElement("p", {
|
||||
display:"block",
|
||||
innerText:`Level: ${currentLevel}`,
|
||||
}));
|
||||
if (maxLvl) {
|
||||
el.appendChild(createElement("p", {
|
||||
color:"red", display:"block",
|
||||
innerText:"MAX LEVEL",
|
||||
}));
|
||||
} else {
|
||||
el.appendChild(createElement("p", {
|
||||
display:"block",
|
||||
innerText:"Skill Points required: " + formatNumber(pointCost, 0),
|
||||
}));
|
||||
}
|
||||
el.appendChild(createElement("p", { // Info/Description
|
||||
innerHTML:skill.desc, display:"inline-block",
|
||||
}));
|
||||
ReactDOM.unmountComponentAtNode(el);
|
||||
ReactDOM.render(<SkillElem bladeburner={this} skill={skill} />, el);
|
||||
}
|
||||
|
||||
// Bladeburner Console Window
|
||||
|
@ -1,5 +1,18 @@
|
||||
// Action Identifier enum
|
||||
export const ActionTypes = Object.freeze({
|
||||
export const ActionTypes: {
|
||||
[key: string]: number;
|
||||
"Idle": number;
|
||||
"Contract": number;
|
||||
"Operation": number;
|
||||
"BlackOp": number;
|
||||
"BlackOperation": number;
|
||||
"Training": number;
|
||||
"Recruitment": number;
|
||||
"FieldAnalysis": number;
|
||||
"Field Analysis": number;
|
||||
"Diplomacy": number;
|
||||
"Hyperbolic Regeneration Chamber": number;
|
||||
} = {
|
||||
"Idle": 1,
|
||||
"Contract": 2,
|
||||
"Operation": 3,
|
||||
@ -11,4 +24,4 @@ export const ActionTypes = Object.freeze({
|
||||
"Field Analysis": 7,
|
||||
"Diplomacy": 8,
|
||||
"Hyperbolic Regeneration Chamber": 9,
|
||||
});
|
||||
};
|
14
src/Bladeburner/data/Icons.tsx
Normal file
14
src/Bladeburner/data/Icons.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import * as React from "react";
|
||||
|
||||
export const stealthIcon = <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 166 132" style={{fill:'#adff2f'}}>
|
||||
<g>
|
||||
<path d="M132.658-0.18l-24.321,24.321c-7.915-2.71-16.342-4.392-25.087-4.392c-45.84,0-83,46-83,46 s14.1,17.44,35.635,30.844L12.32,120.158l12.021,12.021L144.68,11.841L132.658-0.18z M52.033,80.445 c-2.104-4.458-3.283-9.438-3.283-14.695c0-19.054,15.446-34.5,34.5-34.5c5.258,0,10.237,1.179,14.695,3.284L52.033,80.445z" />
|
||||
<path d="M134.865,37.656l-18.482,18.482c0.884,3.052,1.367,6.275,1.367,9.612c0,19.055-15.446,34.5-34.5,34.5 c-3.337,0-6.56-0.483-9.611-1.367l-10.124,10.124c6.326,1.725,12.934,2.743,19.735,2.743c45.84,0,83-46,83-46 S153.987,50.575,134.865,37.656z" />
|
||||
</g>
|
||||
</svg>
|
||||
export const killIcon = <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="-22 0 511 511.99561" style={{fill:'#adff2f'}}>
|
||||
<path d="m.496094 466.242188 39.902344-39.902344 45.753906 45.753906-39.898438 39.902344zm0 0" />
|
||||
<path d="m468.421875 89.832031-1.675781-89.832031-300.265625 300.265625 45.753906 45.753906zm0 0" />
|
||||
<path d="m95.210938 316.785156 16.84375 16.847656h.003906l83.65625 83.65625 22.753906-22.753906-100.503906-100.503906zm0 0" />
|
||||
<path d="m101.445312 365.300781-39.902343 39.902344 45.753906 45.753906 39.902344-39.902343-39.90625-39.902344zm0 0" />
|
||||
</svg>
|
110
src/Bladeburner/ui/BlackOpElem.tsx
Normal file
110
src/Bladeburner/ui/BlackOpElem.tsx
Normal file
@ -0,0 +1,110 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
formatNumber,
|
||||
convertTimeMsToTimeElapsedString,
|
||||
} from "../../../utils/StringHelperFunctions";
|
||||
import { ActionTypes } from "../data/ActionTypes";
|
||||
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
|
||||
import { stealthIcon, killIcon } from "../data/Icons";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: any;
|
||||
action: any;
|
||||
}
|
||||
|
||||
export function BlackOpElem(props: IProps): React.ReactElement {
|
||||
const isCompleted = (props.bladeburner.blackops[props.action.name] != null);
|
||||
if(isCompleted) {
|
||||
return (
|
||||
<h2 style={{display: 'block'}}>{props.action.name} (COMPLETED)</h2>);
|
||||
}
|
||||
|
||||
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 (<>
|
||||
<h2 style={{display: 'inline-block'}}>
|
||||
{isActive ?
|
||||
<>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
|
||||
<>{props.action.name}</>
|
||||
}
|
||||
</h2>
|
||||
{isActive ?
|
||||
<p style={{display: 'block'}}>{createProgressBarText({progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
|
||||
<>
|
||||
<a
|
||||
className={hasReqdRank ? "a-link-button" : "a-link-button-inactive"}
|
||||
style={{margin:"3px", padding:"3px"}}
|
||||
onClick={onStart}
|
||||
>Start</a>
|
||||
<a
|
||||
onClick={onTeam}
|
||||
style={{margin:"3px", padding:"3px"}}
|
||||
className="a-link-button">
|
||||
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
|
||||
</a>
|
||||
</>}
|
||||
<br />
|
||||
<br />
|
||||
<p style={{display:"inline-block"}} dangerouslySetInnerHTML={{__html: props.action.desc}} />
|
||||
<br />
|
||||
<br />
|
||||
<p style={{display:"block", color:hasReqdRank ? "white" : "red"}}>
|
||||
Required Rank: {formatNumber(props.action.reqdRank, 0)}
|
||||
</p>
|
||||
<br />
|
||||
<p style={{display:"inline-block"}}>
|
||||
Estimated Success Chance: {formatNumber(estimatedSuccessChance*100, 1)}% {props.action.isStealth?stealthIcon:<></>}{props.action.isKill?killIcon:<></>}
|
||||
<br />
|
||||
Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}
|
||||
</p>
|
||||
</>);
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
import { BlackOperations } from "../BlackOperations";
|
||||
/*
|
||||
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.<br><br>" +
|
||||
"<b>Your ultimate goal to climb through the ranks of Bladeburners is to complete " +
|
||||
"all of the Black Ops.</b><br><br>" +
|
||||
"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 (<div>
|
||||
<p>
|
||||
Black Operations (Black Ops) are special, one-time covert operations. Each Black Op must be unlocked successively by completing the one before it.<br /><br />
|
||||
<b>Your ultimate goal to climb through the ranks of Bladeburners is to complete all of the Black Ops.</b><br /><br />
|
||||
Like normal operations, you may use a team for Black Ops. Failing a black op will incur heavy HP and rank losses.</p>
|
||||
{blackops.map(() => <div className="bladeburner-action">
|
||||
</div>,
|
||||
)}
|
||||
</div>)
|
||||
}
|
137
src/Bladeburner/ui/ContractElem.tsx
Normal file
137
src/Bladeburner/ui/ContractElem.tsx
Normal file
@ -0,0 +1,137 @@
|
||||
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 ContractElem(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
const isActive = props.bladeburner.action.type === ActionTypes["Contract"] && 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.Contract;
|
||||
props.bladeburner.action.name = props.action.name;
|
||||
props.bladeburner.startAction(props.bladeburner.action);
|
||||
props.bladeburner.updateActionAndSkillsContent();
|
||||
setRerender(old => !old);
|
||||
}
|
||||
|
||||
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<HTMLInputElement>) {
|
||||
props.action.autoLevel = event.target.checked;
|
||||
setRerender(old => !old);
|
||||
}
|
||||
|
||||
return (<>
|
||||
<h2 style={{display: 'inline-block'}}>
|
||||
{isActive ?
|
||||
<>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
|
||||
<>{props.action.name}</>
|
||||
}
|
||||
</h2>
|
||||
{isActive ?
|
||||
<p style={{display: 'block'}}>{createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
|
||||
<>
|
||||
<a
|
||||
onClick={onStart}
|
||||
className="a-link-button"
|
||||
style={{margin:"3px", padding:"3px"}}>
|
||||
Start
|
||||
</a>
|
||||
</>}
|
||||
<br />
|
||||
<br />
|
||||
<pre className="tooltip" style={{display:"inline-block"}}>
|
||||
<span className="tooltiptext">
|
||||
{props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel)} successes needed for next level
|
||||
</span>
|
||||
Level: {props.action.level} / {props.action.maxLevel}
|
||||
</pre>
|
||||
<a
|
||||
onClick={increaseLevel}
|
||||
style={{padding:"2px", margin:"2px"}}
|
||||
className={`tooltip ${maxLevel ? "a-link-button-inactive" : "a-link-button"}`}>
|
||||
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
|
||||
↑
|
||||
</a>
|
||||
<a
|
||||
onClick={decreaseLevel}
|
||||
style={{padding:"2px", margin:"2px"}}
|
||||
className={`tooltip ${props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"}`}>
|
||||
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
|
||||
↓
|
||||
</a>
|
||||
<br />
|
||||
<br />
|
||||
<pre style={{display: 'inline-block'}}>
|
||||
<span dangerouslySetInnerHTML={{__html: props.action.desc}} />
|
||||
<br /><br />
|
||||
Estimated success chance: {formatNumber(estimatedSuccessChance*100, 1)}% {props.action.isStealth?stealthIcon:<></>}${props.action.isKill?killIcon:<></>}<br />
|
||||
Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}<br />
|
||||
Contracts remaining: {Math.floor(props.action.count)}<br />
|
||||
Successes: {props.action.successes}<br />
|
||||
Failures: {props.action.failures}
|
||||
</pre>
|
||||
<br />
|
||||
<label
|
||||
className="tooltip"
|
||||
style={{color: 'white'}}
|
||||
htmlFor={autolevelCheckboxId}>
|
||||
Autolevel:
|
||||
<span className="tooltiptext">Automatically increase operation level when possible</span>
|
||||
</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={autolevelCheckboxId}
|
||||
checked={props.action.autoLevel}
|
||||
onChange={onAutolevel}/>
|
||||
</>);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// 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);
|
||||
|
||||
*/
|
49
src/Bladeburner/ui/GeneralActionElem.tsx
Normal file
49
src/Bladeburner/ui/GeneralActionElem.tsx
Normal file
@ -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 (<>
|
||||
<h2 style={{display: 'inline-block'}}>
|
||||
{isActive ?
|
||||
<>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
|
||||
<>{props.action.name}</>
|
||||
}
|
||||
</h2>
|
||||
{isActive ?
|
||||
<p style={{display: 'block'}}>{createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
|
||||
<>
|
||||
<a
|
||||
onClick={onStart}
|
||||
className="a-link-button"
|
||||
style={{margin:"3px", padding:"3px"}}>
|
||||
Start
|
||||
</a>
|
||||
</>}
|
||||
<br />
|
||||
<br />
|
||||
<pre style={{display: 'inline-block'}} dangerouslySetInnerHTML={{__html: props.action.desc}}></pre>
|
||||
</>);
|
||||
}
|
157
src/Bladeburner/ui/OperationElem.tsx
Normal file
157
src/Bladeburner/ui/OperationElem.tsx
Normal file
@ -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<HTMLInputElement>) {
|
||||
props.action.autoLevel = event.target.checked;
|
||||
setRerender(old => !old);
|
||||
}
|
||||
|
||||
return (<>
|
||||
<h2 style={{display: 'inline-block'}}>
|
||||
{isActive ?
|
||||
<>{props.action.name} (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
|
||||
<>{props.action.name}</>
|
||||
}
|
||||
</h2>
|
||||
{isActive ?
|
||||
<p style={{display: 'block'}}>{createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
|
||||
<>
|
||||
<a
|
||||
onClick={onStart}
|
||||
className="a-link-button"
|
||||
style={{margin:"3px", padding:"3px"}}>
|
||||
Start
|
||||
</a>
|
||||
<a
|
||||
onClick={onTeam}
|
||||
style={{margin:"3px", padding:"3px"}}
|
||||
className="a-link-button">
|
||||
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
|
||||
</a>
|
||||
</>}
|
||||
<br />
|
||||
<br />
|
||||
<pre className="tooltip" style={{display:"inline-block"}}>
|
||||
<span className="tooltiptext">
|
||||
{props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel)} successes needed for next level
|
||||
</span>
|
||||
Level: {props.action.level} / {props.action.maxLevel}
|
||||
</pre>
|
||||
<a
|
||||
onClick={increaseLevel}
|
||||
style={{padding:"2px", margin:"2px"}}
|
||||
className={`tooltip ${maxLevel ? "a-link-button-inactive" : "a-link-button"}`}>
|
||||
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
|
||||
↑
|
||||
</a>
|
||||
<a
|
||||
onClick={decreaseLevel}
|
||||
style={{padding:"2px", margin:"2px"}}
|
||||
className={`tooltip ${props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"}`}>
|
||||
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
|
||||
↓
|
||||
</a>
|
||||
<br />
|
||||
<br />
|
||||
<pre style={{display:"inline-block"}}>
|
||||
<span dangerouslySetInnerHTML={{__html: props.action.desc}} />
|
||||
<br /><br />
|
||||
Estimated success chance: {formatNumber(estimatedSuccessChance*100, 1)}% {props.action.isStealth?stealthIcon:<></>}{props.action.isKill?killIcon:<></>}<br />
|
||||
Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}<br />
|
||||
Operations remaining: {Math.floor(props.action.count)}<br />
|
||||
Successes: {props.action.successes}<br />
|
||||
Failures: {props.action.failures}
|
||||
</pre>
|
||||
<br />
|
||||
<label
|
||||
className="tooltip"
|
||||
style={{color: 'white'}}
|
||||
htmlFor={autolevelCheckboxId}>
|
||||
Autolevel:
|
||||
<span className="tooltiptext">Automatically increase operation level when possible</span>
|
||||
</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={autolevelCheckboxId}
|
||||
checked={props.action.autoLevel}
|
||||
onChange={onAutolevel}/>
|
||||
</>);
|
||||
}
|
46
src/Bladeburner/ui/SkillElem.tsx
Normal file
46
src/Bladeburner/ui/SkillElem.tsx
Normal file
@ -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 (<>
|
||||
<h2 style={{display: 'inline-block'}}>
|
||||
<CopyableText value={props.skill.name} />
|
||||
</h2>
|
||||
<a
|
||||
onClick={onClick}
|
||||
style={{display: "inline-block", margin: "3px", padding: "3px"}}
|
||||
className={canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive"}>
|
||||
Level
|
||||
</a>
|
||||
<br />
|
||||
<br />
|
||||
<p style={{display: 'block'}}>Level: {currentLevel}</p>
|
||||
{maxLvl ?
|
||||
<p style={{color:"red", display:"block"}}>MAX LEVEL</p> :
|
||||
<p style={{display:"block"}}>Skill Points required: {formatNumber(pointCost, 0)}</p>}
|
||||
<p style={{display:"inline-block"}} dangerouslySetInnerHTML={{__html: props.skill.desc}} />
|
||||
</>);
|
||||
}
|
@ -475,6 +475,7 @@ const Engine = {
|
||||
Engine.hideAllContent();
|
||||
routing.navigateTo(Page.Bladeburner);
|
||||
Player.bladeburner.createContent();
|
||||
MainMenuLinks.Bladeburner.classList.add("active");
|
||||
} catch(e) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user