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 { removeElement } from "../utils/uiHelpers/removeElement";
|
||||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
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 { StatsTable } from "./ui/React/StatsTable";
|
||||||
import { CopyableText } from "./ui/React/CopyableText";
|
import { CopyableText } from "./ui/React/CopyableText";
|
||||||
import { Money } from "./ui/React/Money";
|
import { Money } from "./ui/React/Money";
|
||||||
@ -1894,442 +1899,28 @@ Bladeburner.prototype.updateActionAndSkillsContent = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
|
Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
|
||||||
removeChildrenFromElement(el);
|
ReactDOM.unmountComponentAtNode(el);
|
||||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
ReactDOM.render(<GeneralActionElem bladeburner={this} action={action} />, el);
|
||||||
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",
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.updateContractsUIElement = function(el, action) {
|
Bladeburner.prototype.updateContractsUIElement = function(el, action) {
|
||||||
removeChildrenFromElement(el);
|
ReactDOM.unmountComponentAtNode(el);
|
||||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
ReactDOM.render(<ContractElem bladeburner={this} action={action} />, el);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
|
Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
|
||||||
removeChildrenFromElement(el);
|
ReactDOM.unmountComponentAtNode(el);
|
||||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
ReactDOM.render(<OperationElem bladeburner={this} action={action} />, el);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
|
Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
|
||||||
removeChildrenFromElement(el);
|
ReactDOM.unmountComponentAtNode(el);
|
||||||
var isActive = el.classList.contains(ActiveActionCssClass);
|
ReactDOM.render(<BlackOpElem bladeburner={this} action={action} />, el);
|
||||||
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),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
|
Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
|
||||||
removeChildrenFromElement(el);
|
ReactDOM.unmountComponentAtNode(el);
|
||||||
var skillName = skill.name;
|
ReactDOM.render(<SkillElem bladeburner={this} skill={skill} />, el);
|
||||||
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",
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bladeburner Console Window
|
// Bladeburner Console Window
|
||||||
|
@ -1,5 +1,18 @@
|
|||||||
// Action Identifier enum
|
// 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,
|
"Idle": 1,
|
||||||
"Contract": 2,
|
"Contract": 2,
|
||||||
"Operation": 3,
|
"Operation": 3,
|
||||||
@ -11,4 +24,4 @@ export const ActionTypes = Object.freeze({
|
|||||||
"Field Analysis": 7,
|
"Field Analysis": 7,
|
||||||
"Diplomacy": 8,
|
"Diplomacy": 8,
|
||||||
"Hyperbolic Regeneration Chamber": 9,
|
"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();
|
Engine.hideAllContent();
|
||||||
routing.navigateTo(Page.Bladeburner);
|
routing.navigateTo(Page.Bladeburner);
|
||||||
Player.bladeburner.createContent();
|
Player.bladeburner.createContent();
|
||||||
|
MainMenuLinks.Bladeburner.classList.add("active");
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(e);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user