mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 17:43:48 +01:00
Merge pull request #2095 from MartinFournier/fix/bladeburner
Bladeburner console fixes & command checks
This commit is contained in:
commit
f01b12a56a
@ -34,6 +34,12 @@ import { getTimestamp } from "../utils/helpers/getTimestamp";
|
|||||||
import { joinFaction } from "../Faction/FactionHelpers";
|
import { joinFaction } from "../Faction/FactionHelpers";
|
||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
|
|
||||||
|
interface BlackOpsAttempt {
|
||||||
|
error?: string;
|
||||||
|
isAvailable?: boolean;
|
||||||
|
action?: BlackOperation;
|
||||||
|
}
|
||||||
|
|
||||||
export class Bladeburner implements IBladeburner {
|
export class Bladeburner implements IBladeburner {
|
||||||
numHosp = 0;
|
numHosp = 0;
|
||||||
moneyLost = 0;
|
moneyLost = 0;
|
||||||
@ -113,6 +119,44 @@ export class Bladeburner implements IBladeburner {
|
|||||||
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
|
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
canAttemptBlackOp(actionId: IActionIdentifier): BlackOpsAttempt {
|
||||||
|
// Safety measure - don't repeat BlackOps that are already done
|
||||||
|
if (this.blackops[actionId.name] != null) {
|
||||||
|
return { error: "Tried to start a Black Operation that had already been completed" }
|
||||||
|
}
|
||||||
|
|
||||||
|
const action = this.getActionObject(actionId);
|
||||||
|
if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
|
||||||
|
if (action == null) throw new Error("Failed to get BlackOperation object for: " + actionId.name);
|
||||||
|
|
||||||
|
if (action.reqdRank > this.rank) {
|
||||||
|
return { error: "Tried to start a Black Operation without the rank requirement" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't start a BlackOp if you haven't done the one before it
|
||||||
|
const blackops = [];
|
||||||
|
for (const nm in BlackOperations) {
|
||||||
|
if (BlackOperations.hasOwnProperty(nm)) {
|
||||||
|
blackops.push(nm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blackops.sort(function (a, b) {
|
||||||
|
return BlackOperations[a].reqdRank - BlackOperations[b].reqdRank; // Sort black ops in intended order
|
||||||
|
});
|
||||||
|
|
||||||
|
const i = blackops.indexOf(actionId.name);
|
||||||
|
if (i === -1) {
|
||||||
|
return { error: `Invalid Black Op: '${name}'` };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0 && this.blackops[blackops[i - 1]] == null) {
|
||||||
|
return { error: `Preceding Black Op must be completed before starting '${actionId.name}'.` }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { isAvailable: true, action }
|
||||||
|
}
|
||||||
|
|
||||||
startAction(player: IPlayer, actionId: IActionIdentifier): void {
|
startAction(player: IPlayer, actionId: IActionIdentifier): void {
|
||||||
if (actionId == null) return;
|
if (actionId == null) return;
|
||||||
this.action = actionId;
|
this.action = actionId;
|
||||||
@ -156,18 +200,13 @@ export class Bladeburner implements IBladeburner {
|
|||||||
case ActionTypes["BlackOp"]:
|
case ActionTypes["BlackOp"]:
|
||||||
case ActionTypes["BlackOperation"]: {
|
case ActionTypes["BlackOperation"]: {
|
||||||
try {
|
try {
|
||||||
// Safety measure - don't repeat BlackOps that are already done
|
const testBlackOp = this.canAttemptBlackOp(actionId);
|
||||||
if (this.blackops[actionId.name] != null) {
|
if (!testBlackOp.isAvailable) {
|
||||||
this.resetAction();
|
this.resetAction();
|
||||||
this.log("Error: Tried to start a Black Operation that had already been completed");
|
this.log(`Error: ${testBlackOp.error}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this.actionTimeToComplete = testBlackOp.action.getActionTime(this);
|
||||||
const action = this.getActionObject(actionId);
|
|
||||||
if (action == null) {
|
|
||||||
throw new Error("Failed to get BlackOperation object for: " + actionId.name);
|
|
||||||
}
|
|
||||||
this.actionTimeToComplete = action.getActionTime(this);
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
exceptionAlert(e);
|
exceptionAlert(e);
|
||||||
}
|
}
|
||||||
@ -502,6 +541,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
const skill = Skills[skillName];
|
const skill = Skills[skillName];
|
||||||
if (skill == null || !(skill instanceof Skill)) {
|
if (skill == null || !(skill instanceof Skill)) {
|
||||||
this.postToConsole("Invalid skill name (Note that it is case-sensitive): " + skillName);
|
this.postToConsole("Invalid skill name (Note that it is case-sensitive): " + skillName);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (args[1].toLowerCase() === "list") {
|
if (args[1].toLowerCase() === "list") {
|
||||||
let level = 0;
|
let level = 0;
|
||||||
@ -515,7 +555,11 @@ export class Bladeburner implements IBladeburner {
|
|||||||
currentLevel = this.skills[skillName];
|
currentLevel = this.skills[skillName];
|
||||||
}
|
}
|
||||||
const pointCost = skill.calculateCost(currentLevel);
|
const pointCost = skill.calculateCost(currentLevel);
|
||||||
if (this.skillPoints >= pointCost) {
|
if (skill.maxLvl !== 0 && currentLevel >= skill.maxLvl) {
|
||||||
|
this.postToConsole(
|
||||||
|
`This skill ${skill.name} is already at max level (${currentLevel}/${skill.maxLvl}).`,
|
||||||
|
);
|
||||||
|
} else if (this.skillPoints >= pointCost) {
|
||||||
this.skillPoints -= pointCost;
|
this.skillPoints -= pointCost;
|
||||||
this.upgradeSkill(skill);
|
this.upgradeSkill(skill);
|
||||||
this.log(skill.name + " upgraded to Level " + this.skills[skillName]);
|
this.log(skill.name + " upgraded to Level " + this.skills[skillName]);
|
||||||
@ -2032,44 +2076,9 @@ export class Bladeburner implements IBladeburner {
|
|||||||
|
|
||||||
// Special logic for Black Ops
|
// Special logic for Black Ops
|
||||||
if (actionId.type === ActionTypes["BlackOp"]) {
|
if (actionId.type === ActionTypes["BlackOp"]) {
|
||||||
// Can't start a BlackOp if you don't have the required rank
|
const canRunOp = this.canAttemptBlackOp(actionId);
|
||||||
const action = this.getActionObject(actionId);
|
if (!canRunOp.isAvailable) {
|
||||||
if (action == null) throw new Error(`Action not found ${actionId.type}, ${actionId.name}`);
|
workerScript.log("bladeburner.startAction", () => canRunOp.error);
|
||||||
if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
|
|
||||||
//const blackOp = (action as BlackOperation);
|
|
||||||
if (action.reqdRank > this.rank) {
|
|
||||||
workerScript.log("bladeburner.startAction", () => `Insufficient rank to start Black Op '${actionId.name}'.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't start a BlackOp if its already been done
|
|
||||||
if (this.blackops[actionId.name] != null) {
|
|
||||||
workerScript.log("bladeburner.startAction", () => `Black Op ${actionId.name} has already been completed.`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't start a BlackOp if you haven't done the one before it
|
|
||||||
const blackops = [];
|
|
||||||
for (const nm in BlackOperations) {
|
|
||||||
if (BlackOperations.hasOwnProperty(nm)) {
|
|
||||||
blackops.push(nm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blackops.sort(function (a, b) {
|
|
||||||
return BlackOperations[a].reqdRank - BlackOperations[b].reqdRank; // Sort black ops in intended order
|
|
||||||
});
|
|
||||||
|
|
||||||
const i = blackops.indexOf(actionId.name);
|
|
||||||
if (i === -1) {
|
|
||||||
workerScript.log("bladeburner.startAction", () => `Invalid Black Op: '${name}'`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > 0 && this.blackops[blackops[i - 1]] == null) {
|
|
||||||
workerScript.log(
|
|
||||||
"bladeburner.startAction",
|
|
||||||
() => `Preceding Black Op must be completed before starting '${actionId.name}'.`,
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,6 @@ interface IProps {
|
|||||||
|
|
||||||
export function Console(props: IProps): React.ReactElement {
|
export function Console(props: IProps): React.ReactElement {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const scrollHook = useRef<HTMLDivElement>(null);
|
|
||||||
const [command, setCommand] = useState("");
|
const [command, setCommand] = useState("");
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
|
|
||||||
@ -64,22 +63,14 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
|
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
|
||||||
|
|
||||||
// TODO: Figure out how to actually make the scrolling work correctly.
|
|
||||||
function scrollToBottom(): void {
|
|
||||||
if (!scrollHook.current) return;
|
|
||||||
scrollHook.current.scrollTop = scrollHook.current.scrollHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
function rerender(): void {
|
function rerender(): void {
|
||||||
setRerender((old) => !old);
|
setRerender((old) => !old);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = setInterval(rerender, 1000);
|
const id = setInterval(rerender, 1000);
|
||||||
const id2 = setInterval(scrollToBottom, 100);
|
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(id);
|
clearInterval(id);
|
||||||
clearInterval(id2);
|
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -113,6 +104,7 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
setConsoleHistoryIndex(i);
|
setConsoleHistoryIndex(i);
|
||||||
const prevCommand = consoleHistory[i];
|
const prevCommand = consoleHistory[i];
|
||||||
event.currentTarget.value = prevCommand;
|
event.currentTarget.value = prevCommand;
|
||||||
|
setCommand(prevCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === 40) {
|
if (event.keyCode === 40) {
|
||||||
@ -134,39 +126,68 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
setConsoleHistoryIndex(consoleHistoryIndex + 1);
|
setConsoleHistoryIndex(consoleHistoryIndex + 1);
|
||||||
const prevCommand = consoleHistory[consoleHistoryIndex + 1];
|
const prevCommand = consoleHistory[consoleHistoryIndex + 1];
|
||||||
event.currentTarget.value = prevCommand;
|
event.currentTarget.value = prevCommand;
|
||||||
|
setCommand(prevCommand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box height={"60vh"} display={"flex"} alignItems={"stretch"} component={Paper}>
|
<Paper>
|
||||||
<Box>
|
<Box sx={{
|
||||||
<List sx={{ height: "100%", overflow: "auto" }}>
|
height: '60vh',
|
||||||
{props.bladeburner.consoleLogs.map((log: any, i: number) => (
|
paddingBottom: '8px',
|
||||||
<Line key={i} content={log} />
|
display: 'flex',
|
||||||
))}
|
alignItems: 'stretch',
|
||||||
<TextField
|
}}>
|
||||||
classes={{ root: classes.textfield }}
|
<Box>
|
||||||
autoFocus
|
<Logs entries={[...props.bladeburner.consoleLogs]} />
|
||||||
tabIndex={1}
|
</Box>
|
||||||
type="text"
|
|
||||||
value={command}
|
|
||||||
onChange={handleCommandChange}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
InputProps={{
|
|
||||||
// for players to hook in
|
|
||||||
className: classes.input,
|
|
||||||
startAdornment: (
|
|
||||||
<>
|
|
||||||
<Typography>> </Typography>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
spellCheck: false,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</List>
|
|
||||||
<div ref={scrollHook}></div>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
<TextField
|
||||||
|
classes={{ root: classes.textfield }}
|
||||||
|
autoFocus
|
||||||
|
tabIndex={1}
|
||||||
|
type="text"
|
||||||
|
value={command}
|
||||||
|
onChange={handleCommandChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
InputProps={{
|
||||||
|
// for players to hook in
|
||||||
|
className: classes.input,
|
||||||
|
startAdornment: (
|
||||||
|
<>
|
||||||
|
<Typography>> </Typography>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
spellCheck: false,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILogProps {
|
||||||
|
entries: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function Logs({entries}: ILogProps): React.ReactElement {
|
||||||
|
const scrollHook = useRef<HTMLUListElement>(null);
|
||||||
|
|
||||||
|
// TODO: Text gets shifted up as new entries appear, if the user scrolled up it should attempt to keep the text focused
|
||||||
|
function scrollToBottom(): void {
|
||||||
|
if (!scrollHook.current) return;
|
||||||
|
scrollHook.current.scrollTop = scrollHook.current.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, [entries]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List sx={{ height: "100%", overflow: "auto", p: 1 }} ref={scrollHook}>
|
||||||
|
{entries && entries.map((log: any, i: number) => (
|
||||||
|
<Line key={i} content={log} />
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user